From b346671fa196abaf82ed3e1842f981209f7887af Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 16 Jan 2006 11:31:24 +0000 Subject: [PATCH 0001/1619] [PATCH] Export tty_write_message() for GFS2 quota code The kernel's existing quota code makes use of tty_write_message() to inform the user of certain events. GFS2 also uses the same mechanism so we export it here to avoid code duplication in GFS2. Signed-off-by: Steven Whitehouse --- kernel/printk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/printk.c b/kernel/printk.c index 13ced0f7828..7ba79ad895e 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -999,6 +999,7 @@ void tty_write_message(struct tty_struct *tty, char *msg) tty->driver->write(tty, msg, strlen(msg)); return; } +EXPORT_SYMBOL_GPL(tty_write_message); /* * printk rate limiting, lifted from the networking subsystem. -- GitLab From fba7b940194465ac7a8f0cdf793959fb5fbb8834 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 16 Jan 2006 11:48:01 +0000 Subject: [PATCH 0002/1619] [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 --- fs/namespace.c | 5 +++++ include/linux/fs.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 8bc15b362d2..ce97becff46 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -48,6 +48,10 @@ static int hash_mask __read_mostly, hash_bits __read_mostly; static kmem_cache_t *mnt_cache; static struct rw_semaphore namespace_sem; +/* /sys/fs */ +decl_subsys(fs, NULL, NULL); +EXPORT_SYMBOL_GPL(fs_subsys); + static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); @@ -1725,6 +1729,7 @@ void __init mnt_init(unsigned long mempages) i--; } while (i); sysfs_init(); + subsystem_register(&fs_subsys); init_rootfs(); init_mount_tree(); } diff --git a/include/linux/fs.h b/include/linux/fs.h index 552cedfa606..eabc80d22bb 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); -- GitLab From f7825dcf8c7301cfd3724eb40c5b443cc85ab7b8 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 16 Jan 2006 16:43:37 +0000 Subject: [PATCH 0003/1619] [GFS2] Hook GFS2 into the Kbuild system Adds GFS2 into fs/Kconfig and adds a Makefile entry Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/Kconfig | 1 + fs/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/Kconfig b/fs/Kconfig index ef78e3a42d3..bec8afa5704 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -323,6 +323,7 @@ config FS_POSIX_ACL default n source "fs/xfs/Kconfig" +source "fs/gfs2/Kconfig" config OCFS2_FS tristate "OCFS2 file system support (EXPERIMENTAL)" diff --git a/fs/Makefile b/fs/Makefile index 1db711319c8..0922727732c 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -103,3 +103,4 @@ obj-$(CONFIG_HPPFS) += hppfs/ obj-$(CONFIG_DEBUG_FS) += debugfs/ obj-$(CONFIG_CONFIGFS_FS) += configfs/ obj-$(CONFIG_OCFS2_FS) += ocfs2/ +obj-$(CONFIG_GFS2_FS) += gfs2/ -- GitLab From b3b94faa5fe5968827ba0640ee9fba4b3e7f736e Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 16 Jan 2006 16:50:04 +0000 Subject: [PATCH 0004/1619] [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 diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig new file mode 100644 index 00000000000..17cb44bea1c --- /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 00000000000..b1bac4f199d --- /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 00000000000..33c465a2ab5 --- /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 00000000000..a174b4f6bcc --- /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 00000000000..57d420a86ad --- /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 00000000000..36ccbdcb1ee --- /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 00000000000..4b4e295b3bf --- /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 00000000000..de16e44f049 --- /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 00000000000..cff8d5368d2 --- /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 00000000000..a27fdeda5fb --- /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 00000000000..6b1dc3dc3a2 --- /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 00000000000..79f77aab426 --- /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 00000000000..2914731250c --- /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 00000000000..f83c497eddc --- /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 00000000000..63a5cf1e247 --- /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 00000000000..a6403929575 --- /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 00000000000..c7bf32ce3ec --- /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 00000000000..a5d11823846 --- /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 00000000000..321945fde12 --- /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 00000000000..06847ebebde --- /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 00000000000..127008146a5 --- /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 00000000000..94f2d264aa6 --- /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 00000000000..3ed0a7f26e4 --- /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 00000000000..73922dba539 --- /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 00000000000..4df7da51f71 --- /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 00000000000..d4adbf171ed --- /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 00000000000..95e18fcb8f8 --- /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 00000000000..cc7442261b2 --- /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 00000000000..ec812424fde --- /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 00000000000..378432f17f2 --- /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 00000000000..2d2f8fe5399 --- /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 00000000000..736d0d33dd1 --- /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 00000000000..4413cda8115 --- /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 00000000000..d501e8224ed --- /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 00000000000..417f5aade4b --- /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 00000000000..8af62568a3f --- /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 00000000000..ca9732b2d9f --- /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 00000000000..0c60f2b10fd --- /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 00000000000..177b0246d19 --- /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 00000000000..5556df8cc6c --- /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 00000000000..3e42697aafc --- /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 00000000000..bc8331cd7b2 --- /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 00000000000..2a1ef5aa7f0 --- /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 00000000000..0aa5f140ddb --- /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 00000000000..ced9ea0fdd3 --- /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 00000000000..5c618611c11 --- /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 00000000000..94e3ee17016 --- /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 00000000000..0ae3a0af192 --- /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 00000000000..2f342f3d875 --- /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 00000000000..1e6f51b74f4 --- /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 00000000000..95123d7bbcd --- /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 00000000000..c61a80c439a --- /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 00000000000..7008364e76e --- /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 00000000000..d0f90b88380 --- /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 00000000000..5fafd87c8d7 --- /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 00000000000..ca6a4d81bc2 --- /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 00000000000..a41d208dc55 --- /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 00000000000..a1b409ce75e --- /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 00000000000..54e3a8769cb --- /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 00000000000..05453c5a06f --- /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 00000000000..7ad8c99ee0e --- /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 00000000000..a0320f22b57 --- /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 00000000000..005529f6895 --- /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 00000000000..15cd26fbcff --- /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 00000000000..50d7eb57881 --- /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 00000000000..67d26b99a73 --- /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 00000000000..bb97f050159 --- /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 00000000000..8df6fba20fa --- /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 00000000000..4c44a191b1c --- /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 00000000000..d37f203e133 --- /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 00000000000..cc1a3df1949 --- /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 00000000000..75e9a3231b8 --- /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 00000000000..62c8ed89ab9 --- /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 00000000000..afa5408c000 --- /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 00000000000..ac615e9e852 --- /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 00000000000..4a993af58c1 --- /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 00000000000..51e77f88d74 --- /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 00000000000..74e2c62f237 --- /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 00000000000..21466fe9bf4 --- /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 00000000000..dde9840b1c3 --- /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 00000000000..213d664d495 --- /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__ */ -- GitLab From 29b7998d887529eca1ef43c8ca7b278448dc983c Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 16 Jan 2006 16:52:38 +0000 Subject: [PATCH 0005/1619] [GFS2] The lock modules for GFS2 This patch contains the pluggable locking modules for GFS2. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/Makefile | 3 + fs/gfs2/locking/dlm/lock.c | 537 +++++++++++++++++++++++ fs/gfs2/locking/dlm/main.c | 58 +++ fs/gfs2/locking/dlm/mount.c | 240 ++++++++++ fs/gfs2/locking/dlm/sysfs.c | 315 +++++++++++++ fs/gfs2/locking/dlm/thread.c | 359 +++++++++++++++ fs/gfs2/locking/nolock/Makefile | 3 + fs/gfs2/locking/nolock/lock_nolock.mod.c | 44 ++ fs/gfs2/locking/nolock/main.c | 357 +++++++++++++++ 9 files changed, 1916 insertions(+) create mode 100644 fs/gfs2/locking/dlm/Makefile create mode 100644 fs/gfs2/locking/dlm/lock.c create mode 100644 fs/gfs2/locking/dlm/main.c create mode 100644 fs/gfs2/locking/dlm/mount.c create mode 100644 fs/gfs2/locking/dlm/sysfs.c create mode 100644 fs/gfs2/locking/dlm/thread.c create mode 100644 fs/gfs2/locking/nolock/Makefile create mode 100644 fs/gfs2/locking/nolock/lock_nolock.mod.c create mode 100644 fs/gfs2/locking/nolock/main.c diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile new file mode 100644 index 00000000000..d3bca02f7b3 --- /dev/null +++ b/fs/gfs2/locking/dlm/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_GFS2_FS) += lock_dlm.o +lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o + diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c new file mode 100644 index 00000000000..daf59d504e2 --- /dev/null +++ b/fs/gfs2/locking/dlm/lock.c @@ -0,0 +1,537 @@ +/****************************************************************************** +******************************************************************************* +** +** 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" + +static char junk_lvb[GDLM_LVB_SIZE]; + +static void queue_complete(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + clear_bit(LFL_ACTIVE, &lp->flags); + + spin_lock(&ls->async_lock); + list_add_tail(&lp->clist, &ls->complete); + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +static inline void gdlm_ast(void *astarg) +{ + queue_complete((struct gdlm_lock *) astarg); +} + +static inline void gdlm_bast(void *astarg, int mode) +{ + struct gdlm_lock *lp = astarg; + struct gdlm_ls *ls = lp->ls; + + if (!mode) { + printk("lock_dlm: bast mode zero %x,%"PRIx64"\n", + lp->lockname.ln_type, lp->lockname.ln_number); + return; + } + + spin_lock(&ls->async_lock); + if (!lp->bast_mode) { + list_add_tail(&lp->blist, &ls->blocking); + lp->bast_mode = mode; + } else if (lp->bast_mode < mode) + lp->bast_mode = mode; + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +void gdlm_queue_delayed(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + spin_lock(&ls->async_lock); + list_add_tail(&lp->delay_list, &ls->delayed); + spin_unlock(&ls->async_lock); +} + +/* convert gfs lock-state to dlm lock-mode */ + +static int16_t make_mode(int16_t lmstate) +{ + switch (lmstate) { + case LM_ST_UNLOCKED: + return DLM_LOCK_NL; + case LM_ST_EXCLUSIVE: + return DLM_LOCK_EX; + case LM_ST_DEFERRED: + return DLM_LOCK_CW; + case LM_ST_SHARED: + return DLM_LOCK_PR; + default: + GDLM_ASSERT(0, printk("unknown LM state %d\n", lmstate);); + } +} + +/* convert dlm lock-mode to gfs lock-state */ + +int16_t gdlm_make_lmstate(int16_t dlmmode) +{ + switch (dlmmode) { + case DLM_LOCK_IV: + case DLM_LOCK_NL: + return LM_ST_UNLOCKED; + case DLM_LOCK_EX: + return LM_ST_EXCLUSIVE; + case DLM_LOCK_CW: + return LM_ST_DEFERRED; + case DLM_LOCK_PR: + return LM_ST_SHARED; + default: + GDLM_ASSERT(0, printk("unknown DLM mode %d\n", dlmmode);); + } +} + +/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and + DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */ + +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);); +} + +static inline unsigned int make_flags(struct gdlm_lock *lp, + unsigned int gfs_flags, + int16_t cur, int16_t req) +{ + unsigned int lkf = 0; + + if (gfs_flags & LM_FLAG_TRY) + lkf |= DLM_LKF_NOQUEUE; + + if (gfs_flags & LM_FLAG_TRY_1CB) { + lkf |= DLM_LKF_NOQUEUE; + lkf |= DLM_LKF_NOQUEUEBAST; + } + + if (gfs_flags & LM_FLAG_PRIORITY) { + lkf |= DLM_LKF_NOORDER; + lkf |= DLM_LKF_HEADQUE; + } + + if (gfs_flags & LM_FLAG_ANY) { + if (req == DLM_LOCK_PR) + lkf |= DLM_LKF_ALTCW; + else if (req == DLM_LOCK_CW) + lkf |= DLM_LKF_ALTPR; + } + + if (lp->lksb.sb_lkid != 0) { + lkf |= DLM_LKF_CONVERT; + + /* Conversion deadlock avoidance by DLM */ + + if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) && + !(lkf & DLM_LKF_NOQUEUE) && + cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req) + lkf |= DLM_LKF_CONVDEADLK; + } + + if (lp->lvb) + lkf |= DLM_LKF_VALBLK; + + return lkf; +} + +/* make_strname - convert GFS lock numbers to a string */ + +static inline void make_strname(struct lm_lockname *lockname, + struct gdlm_strname *str) +{ + sprintf(str->name, "%8x%16"PRIx64, lockname->ln_type, + lockname->ln_number); + str->namelen = GDLM_STRNAME_BYTES; +} + +int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, + struct gdlm_lock **lpp) +{ + struct gdlm_lock *lp; + + lp = kmalloc(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; + lp->lvb = NULL; + lp->hold_null = NULL; + init_completion(&lp->ast_wait); + INIT_LIST_HEAD(&lp->clist); + INIT_LIST_HEAD(&lp->blist); + INIT_LIST_HEAD(&lp->delay_list); + + spin_lock(&ls->async_lock); + list_add(&lp->all_list, &ls->all_locks); + ls->all_locks_count++; + spin_unlock(&ls->async_lock); + + *lpp = lp; + return 0; +} + +void gdlm_delete_lp(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + spin_lock(&ls->async_lock); + if (!list_empty(&lp->clist)) + list_del_init(&lp->clist); + if (!list_empty(&lp->blist)) + list_del_init(&lp->blist); + if (!list_empty(&lp->delay_list)) + list_del_init(&lp->delay_list); + GDLM_ASSERT(!list_empty(&lp->all_list),); + list_del_init(&lp->all_list); + ls->all_locks_count--; + spin_unlock(&ls->async_lock); + + kfree(lp); +} + +int gdlm_get_lock(lm_lockspace_t *lockspace, struct lm_lockname *name, + lm_lock_t **lockp) +{ + struct gdlm_lock *lp; + int error; + + error = gdlm_create_lp((struct gdlm_ls *) lockspace, name, &lp); + + *lockp = (lm_lock_t *) lp; + return error; +} + +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) +{ + struct gdlm_ls *ls = lp->ls; + struct gdlm_strname str; + int error, bast = 1; + + /* + * When recovery is in progress, delay lock requests for submission + * once recovery is done. Requests for recovery (NOEXP) and unlocks + * can pass. + */ + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && + !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) { + gdlm_queue_delayed(lp); + return; + } + + /* + * Submit the actual lock request. + */ + + if (test_bit(LFL_NOBAST, &lp->flags)) + bast = 0; + + make_strname(&lp->lockname, &str); + + set_bit(LFL_ACTIVE, &lp->flags); + + log_debug("lk %x,%"PRIx64" id %x %d,%d %x", lp->lockname.ln_type, + lp->lockname.ln_number, lp->lksb.sb_lkid, + lp->cur, lp->req, lp->lkf); + + error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf, + str.name, str.namelen, 0, gdlm_ast, (void *) lp, + bast ? gdlm_bast : NULL, range); + + if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) { + lp->lksb.sb_status = -EAGAIN; + queue_complete(lp); + 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, + lp->lockname.ln_number, error, lp->cur, lp->req, + lp->lkf);); +} + +void gdlm_do_unlock(struct gdlm_lock *lp) +{ + unsigned int lkf = 0; + int error; + + set_bit(LFL_DLM_UNLOCK, &lp->flags); + set_bit(LFL_ACTIVE, &lp->flags); + + if (lp->lvb) + lkf = DLM_LKF_VALBLK; + + log_debug("un %x,%"PRIx64" %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); + + 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);); +} + +unsigned int gdlm_lock(lm_lock_t *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags) +{ + struct gdlm_lock *lp = (struct gdlm_lock *) lock; + + clear_bit(LFL_DLM_CANCEL, &lp->flags); + if (flags & LM_FLAG_NOEXP) + set_bit(LFL_NOBLOCK, &lp->flags); + + check_cur_state(lp, 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; +} + +unsigned int gdlm_unlock(lm_lock_t *lock, unsigned int cur_state) +{ + struct gdlm_lock *lp = (struct gdlm_lock *) lock; + + clear_bit(LFL_DLM_CANCEL, &lp->flags); + if (lp->cur == DLM_LOCK_IV) + return 0; + gdlm_do_unlock(lp); + return LM_OUT_ASYNC; +} + +void gdlm_cancel(lm_lock_t *lock) +{ + struct gdlm_lock *lp = (struct gdlm_lock *) lock; + struct gdlm_ls *ls = lp->ls; + int error, delay_list = 0; + + 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); + + spin_lock(&ls->async_lock); + if (!list_empty(&lp->delay_list)) { + list_del_init(&lp->delay_list); + delay_list = 1; + } + spin_unlock(&ls->async_lock); + + if (delay_list) { + set_bit(LFL_CANCEL, &lp->flags); + set_bit(LFL_ACTIVE, &lp->flags); + queue_complete(lp); + return; + } + + 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); + return; + } + + /* the lock is blocked in the dlm */ + + set_bit(LFL_DLM_CANCEL, &lp->flags); + set_bit(LFL_ACTIVE, &lp->flags); + + 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); + + if (error == -EBUSY) + clear_bit(LFL_DLM_CANCEL, &lp->flags); +} + +int gdlm_add_lvb(struct gdlm_lock *lp) +{ + char *lvb; + + lvb = kmalloc(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; +} + +void gdlm_del_lvb(struct gdlm_lock *lp) +{ + kfree(lp->lvb); + lp->lvb = NULL; + lp->lksb.sb_lvbptr = NULL; +} + +/* This can do a synchronous dlm request (requiring a lock_dlm thread to get + the completion) because gfs won't call hold_lvb() during a callback (from + the context of a lock_dlm thread). */ + +static int hold_null_lock(struct gdlm_lock *lp) +{ + struct gdlm_lock *lpn = NULL; + int error; + + if (lp->hold_null) { + printk("lock_dlm: lvb already held\n"); + return 0; + } + + error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn); + if (error) + goto out; + + lpn->lksb.sb_lvbptr = junk_lvb; + lpn->lvb = junk_lvb; + + lpn->req = DLM_LOCK_NL; + lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE; + set_bit(LFL_NOBAST, &lpn->flags); + set_bit(LFL_INLOCK, &lpn->flags); + + init_completion(&lpn->ast_wait); + gdlm_do_lock(lpn, NULL); + wait_for_completion(&lpn->ast_wait); + error = lp->lksb.sb_status; + if (error) { + printk("lock_dlm: hold_null_lock dlm error %d\n", error); + gdlm_delete_lp(lpn); + lpn = NULL; + } + out: + lp->hold_null = lpn; + return error; +} + +/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get + the completion) because gfs may call unhold_lvb() during a callback (from + the context of a lock_dlm thread) which could cause a deadlock since the + other lock_dlm thread could be engaged in recovery. */ + +static void unhold_null_lock(struct gdlm_lock *lp) +{ + struct gdlm_lock *lpn = lp->hold_null; + + GDLM_ASSERT(lpn,); + lpn->lksb.sb_lvbptr = NULL; + lpn->lvb = NULL; + set_bit(LFL_UNLOCK_DELETE, &lpn->flags); + gdlm_do_unlock(lpn); + lp->hold_null = NULL; +} + +/* Acquire a NL lock because gfs requires the value block to remain + intact on the resource while the lvb is "held" even if it's holding no locks + on the resource. */ + +int gdlm_hold_lvb(lm_lock_t *lock, char **lvbp) +{ + struct gdlm_lock *lp = (struct gdlm_lock *) lock; + int error; + + error = gdlm_add_lvb(lp); + if (error) + return error; + + *lvbp = lp->lvb; + + error = hold_null_lock(lp); + if (error) + gdlm_del_lvb(lp); + + return error; +} + +void gdlm_unhold_lvb(lm_lock_t *lock, char *lvb) +{ + struct gdlm_lock *lp = (struct gdlm_lock *) lock; + + unhold_null_lock(lp); + gdlm_del_lvb(lp); +} + +void gdlm_sync_lvb(lm_lock_t *lock, char *lvb) +{ + struct gdlm_lock *lp = (struct gdlm_lock *) lock; + + if (lp->cur != DLM_LOCK_EX) + return; + + init_completion(&lp->ast_wait); + set_bit(LFL_SYNC_LVB, &lp->flags); + + lp->req = DLM_LOCK_EX; + lp->lkf = make_flags(lp, 0, lp->cur, lp->req); + + gdlm_do_lock(lp, NULL); + wait_for_completion(&lp->ast_wait); +} + +void gdlm_submit_delayed(struct gdlm_ls *ls) +{ + struct gdlm_lock *lp, *safe; + + spin_lock(&ls->async_lock); + list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) { + list_del_init(&lp->delay_list); + list_add_tail(&lp->delay_list, &ls->submit); + } + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +int gdlm_release_all_locks(struct gdlm_ls *ls) +{ + struct gdlm_lock *lp, *safe; + int count = 0; + + spin_lock(&ls->async_lock); + list_for_each_entry_safe(lp, safe, &ls->all_locks, all_list) { + list_del_init(&lp->all_list); + + if (lp->lvb && lp->lvb != junk_lvb) + kfree(lp->lvb); + kfree(lp); + count++; + } + spin_unlock(&ls->async_lock); + + return count; +} + diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c new file mode 100644 index 00000000000..3ced92ef1b1 --- /dev/null +++ b/fs/gfs2/locking/dlm/main.c @@ -0,0 +1,58 @@ +/****************************************************************************** +******************************************************************************* +** +** 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 "lock_dlm.h" + +extern int gdlm_drop_count; +extern int gdlm_drop_period; + +extern struct lm_lockops gdlm_ops; + +int __init init_lock_dlm(void) +{ + int error; + + error = lm_register_proto(&gdlm_ops); + if (error) { + printk("lock_dlm: can't register protocol: %d\n", error); + return error; + } + + error = gdlm_sysfs_init(); + if (error) { + lm_unregister_proto(&gdlm_ops); + return error; + } + + gdlm_drop_count = GDLM_DROP_COUNT; + gdlm_drop_period = GDLM_DROP_PERIOD; + + printk("Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); + return 0; +} + +void __exit exit_lock_dlm(void) +{ + lm_unregister_proto(&gdlm_ops); + gdlm_sysfs_exit(); +} + +module_init(init_lock_dlm); +module_exit(exit_lock_dlm); + +MODULE_DESCRIPTION("GFS DLM Locking Module"); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c new file mode 100644 index 00000000000..92b1789deb8 --- /dev/null +++ b/fs/gfs2/locking/dlm/mount.c @@ -0,0 +1,240 @@ +/****************************************************************************** +******************************************************************************* +** +** 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" + +int gdlm_drop_count; +int gdlm_drop_period; +struct lm_lockops gdlm_ops; + + +static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata, + int flags, char *table_name) +{ + struct gdlm_ls *ls; + char buf[256], *p; + + ls = kmalloc(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; + ls->thread2 = NULL; + ls->drop_time = jiffies; + ls->jid = -1; + + strncpy(buf, table_name, 256); + buf[255] = '\0'; + + p = strstr(buf, ":"); + if (!p) { + printk("lock_dlm: invalid table_name \"%s\"\n", table_name); + kfree(ls); + return NULL; + } + *p = '\0'; + p++; + + strncpy(ls->clustername, buf, 128); + strncpy(ls->fsname, p, 128); + + return ls; +} + +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 gdlm_ls *ls; + int error = -ENOMEM; + + if (min_lvb_size > GDLM_LVB_SIZE) + goto out; + + ls = init_gdlm(cb, fsdata, flags, table_name); + if (!ls) + goto out; + + error = gdlm_init_threads(ls); + if (error) + goto out_free; + + 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); + goto out_thread; + } + + error = gdlm_kobject_setup(ls); + 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)); + 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; + lockstruct->ls_ops = &gdlm_ops; + lockstruct->ls_flags = 0; + lockstruct->ls_lvb_size = GDLM_LVB_SIZE; + return 0; + + out_sysfs: + gdlm_kobject_release(ls); + out_dlm: + dlm_release_lockspace(ls->dlm_lockspace, 2); + out_thread: + gdlm_release_threads(ls); + out_free: + kfree(ls); + out: + return error; +} + +static void gdlm_unmount(lm_lockspace_t *lockspace) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + int rv; + + 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); + + wait_event_interruptible(ls->wait_control, + test_bit(DFL_LEAVE_DONE, &ls->flags)); + + 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); + out: + kfree(ls); +} + +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; + kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL); +} + +static void gdlm_others_may_mount(lm_lockspace_t *lockspace) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + ls->first_done = 1; + kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL); +} + +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, + test_bit(DFL_WITHDRAW, &ls->flags)); + + 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; +} + +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, +}; + diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c new file mode 100644 index 00000000000..8964733f55e --- /dev/null +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -0,0 +1,315 @@ +/****************************************************************************** +******************************************************************************* +** +** 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 ssize_t gdlm_block_show(struct gdlm_ls *ls, char *buf) +{ + ssize_t ret; + int val = 0; + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags)) + val = 1; + ret = sprintf(buf, "%d\n", val); + return ret; +} + +static ssize_t gdlm_block_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_BLOCK_LOCKS, &ls->flags); + else if (val == 0) { + clear_bit(DFL_BLOCK_LOCKS, &ls->flags); + gdlm_submit_delayed(ls); + } else + ret = -EINVAL; + 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) +{ + ssize_t ret; + int val = 0; + + if (test_bit(DFL_WITHDRAW, &ls->flags)) + val = 1; + ret = sprintf(buf, "%d\n", val); + return ret; +} + +static ssize_t gdlm_withdraw_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_WITHDRAW, &ls->flags); + else + ret = -EINVAL; + wake_up(&ls->wait_control); + 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) +{ + ls->jid = simple_strtol(buf, NULL, 0); + return len; +} + +static ssize_t gdlm_first_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%u\n", ls->first); +} + +static ssize_t gdlm_first_store(struct gdlm_ls *ls, const char *buf, size_t len) +{ + ls->first = simple_strtol(buf, NULL, 0); + return len; +} + +static ssize_t gdlm_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) +{ + return sprintf(buf, "%u\n", ls->recover_jid); +} + +static ssize_t gdlm_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) +{ + ssize_t ret = 0; + + if (ls->fsflags & LM_MFLAG_SPECTATOR) + ret += sprintf(buf, "spectator "); + + return ret; +} + +struct gdlm_attr { + struct attribute attr; + ssize_t (*show)(struct gdlm_ls *, char *); + 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, +}; + +static struct gdlm_attr gdlm_attr_options = { + .attr = {.name = "options", .mode = S_IRUGO | S_IWUSR}, + .show = gdlm_options_show, +}; + +static struct attribute *gdlm_attrs[] = { + &gdlm_attr_block.attr, + &gdlm_attr_mounted.attr, + &gdlm_attr_withdraw.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, +}; + +static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); + struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr); + return a->show ? a->show(ls, buf) : 0; +} + +static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); + struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr); + return a->store ? a->store(ls, buf, len) : len; +} + +static struct sysfs_ops gdlm_attr_ops = { + .show = gdlm_attr_show, + .store = gdlm_attr_store, +}; + +static struct kobj_type gdlm_ktype = { + .default_attrs = gdlm_attrs, + .sysfs_ops = &gdlm_attr_ops, +}; + +static struct kset gdlm_kset = { + .subsys = &kernel_subsys, + .kobj = {.name = "lock_dlm",}, + .ktype = &gdlm_ktype, +}; + +int gdlm_kobject_setup(struct gdlm_ls *ls) +{ + int error; + + error = kobject_set_name(&ls->kobj, "%s", ls->fsname); + if (error) + return error; + + ls->kobj.kset = &gdlm_kset; + ls->kobj.ktype = &gdlm_ktype; + + error = kobject_register(&ls->kobj); + + return 0; +} + +void gdlm_kobject_release(struct gdlm_ls *ls) +{ + kobject_unregister(&ls->kobj); +} + +int gdlm_sysfs_init(void) +{ + int error; + + error = kset_register(&gdlm_kset); + if (error) + printk("lock_dlm: cannot register kset %d\n", error); + + return error; +} + +void gdlm_sysfs_exit(void) +{ + kset_unregister(&gdlm_kset); +} + diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c new file mode 100644 index 00000000000..22bbe6d3a5a --- /dev/null +++ b/fs/gfs2/locking/dlm/thread.c @@ -0,0 +1,359 @@ +/****************************************************************************** +******************************************************************************* +** +** 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" + +/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm + thread gets to it. */ + +static void queue_submit(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + spin_lock(&ls->async_lock); + list_add_tail(&lp->delay_list, &ls->submit); + spin_unlock(&ls->async_lock); + 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; + + switch (gdlm_make_lmstate(bast_mode)) { + case LM_ST_EXCLUSIVE: + cb = LM_CB_NEED_E; + break; + case LM_ST_DEFERRED: + cb = LM_CB_NEED_D; + break; + case LM_ST_SHARED: + cb = LM_CB_NEED_S; + break; + default: + GDLM_ASSERT(0, printk("unknown bast mode %u\n",lp->bast_mode);); + } + + ls->fscb(ls->fsdata, cb, &lp->lockname); +} + +static void process_complete(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + struct lm_async_cb acb; + int16_t prev_mode = lp->cur; + + 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); + + lp->req = lp->cur; + acb.lc_ret |= LM_OUT_CANCELED; + if (lp->cur == DLM_LOCK_IV) + lp->lksb.sb_lkid = 0; + goto out; + } + + 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); + return; + } + + lp->cur = DLM_LOCK_IV; + lp->req = DLM_LOCK_IV; + lp->lksb.sb_lkid = 0; + + if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) { + gdlm_delete_lp(lp); + return; + } + goto out; + } + + if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID) + memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE); + + if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) { + if (lp->req == DLM_LOCK_PR) + lp->req = DLM_LOCK_CW; + else if (lp->req == DLM_LOCK_CW) + lp->req = DLM_LOCK_PR; + } + + /* + * A canceled lock request. The lock was just taken off the delayed + * list and was never even submitted to dlm. + */ + + if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) { + log_all("complete internal cancel %x,%"PRIx64"", + lp->lockname.ln_type, lp->lockname.ln_number); + lp->req = lp->cur; + acb.lc_ret |= LM_OUT_CANCELED; + goto out; + } + + /* + * An error occured. + */ + + if (lp->lksb.sb_status) { + /* a "normal" error */ + if ((lp->lksb.sb_status == -EAGAIN) && + (lp->lkf & DLM_LKF_NOQUEUE)) { + lp->req = lp->cur; + if (lp->cur == DLM_LOCK_IV) + lp->lksb.sb_lkid = 0; + goto out; + } + + /* 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); + return; + } + + /* + * This is an AST for an EX->EX conversion for sync_lvb from GFS. + */ + + if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) { + complete(&lp->ast_wait); + return; + } + + /* + * A lock has been demoted to NL because it initially completed during + * BLOCK_LOCKS. Now it must be requested in the originally requested + * mode. + */ + + if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) { + GDLM_ASSERT(lp->req == DLM_LOCK_NL,); + GDLM_ASSERT(lp->prev_req > DLM_LOCK_NL,); + + lp->cur = DLM_LOCK_NL; + lp->req = lp->prev_req; + lp->prev_req = DLM_LOCK_IV; + lp->lkf &= ~DLM_LKF_CONVDEADLK; + + set_bit(LFL_NOCACHE, &lp->flags); + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && + !test_bit(LFL_NOBLOCK, &lp->flags)) + gdlm_queue_delayed(lp); + else + queue_submit(lp); + return; + } + + /* + * A request is granted during dlm recovery. It may be granted + * because the locks of a failed node were cleared. In that case, + * there may be inconsistent data beneath this lock and we must wait + * for recovery to complete to use it. When gfs recovery is done this + * granted lock will be converted to NL and then reacquired in this + * granted state. + */ + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && + !test_bit(LFL_NOBLOCK, &lp->flags) && + lp->req != DLM_LOCK_NL) { + + lp->cur = lp->req; + lp->prev_req = lp->req; + lp->req = DLM_LOCK_NL; + lp->lkf |= DLM_LKF_CONVERT; + lp->lkf &= ~DLM_LKF_CONVDEADLK; + + log_debug("rereq %x,%"PRIx64" id %x %d,%d", + lp->lockname.ln_type, lp->lockname.ln_number, + lp->lksb.sb_lkid, lp->cur, lp->req); + + set_bit(LFL_REREQUEST, &lp->flags); + queue_submit(lp); + return; + } + + /* + * DLM demoted the lock to NL before it was granted so GFS must be + * told it cannot cache data for this lock. + */ + + if (lp->lksb.sb_flags & DLM_SBF_DEMOTED) + set_bit(LFL_NOCACHE, &lp->flags); + + out: + /* + * This is an internal lock_dlm lock + */ + + if (test_bit(LFL_INLOCK, &lp->flags)) { + clear_bit(LFL_NOBLOCK, &lp->flags); + lp->cur = lp->req; + complete(&lp->ast_wait); + return; + } + + /* + * Normal completion of a lock request. Tell GFS it now has the lock. + */ + + clear_bit(LFL_NOBLOCK, &lp->flags); + lp->cur = lp->req; + + acb.lc_name = lp->lockname; + acb.lc_ret |= gdlm_make_lmstate(lp->cur); + + if (!test_and_clear_bit(LFL_NOCACHE, &lp->flags) && + (lp->cur > DLM_LOCK_NL) && (prev_mode > DLM_LOCK_NL)) + acb.lc_ret |= LM_OUT_CACHEABLE; + + ls->fscb(ls->fsdata, LM_CB_ASYNC, &acb); +} + +static inline int no_work(struct gdlm_ls *ls, int blocking) +{ + int ret; + + spin_lock(&ls->async_lock); + ret = list_empty(&ls->complete) && list_empty(&ls->submit); + if (ret && blocking) + ret = list_empty(&ls->blocking); + spin_unlock(&ls->async_lock); + + return ret; +} + +static inline int check_drop(struct gdlm_ls *ls) +{ + if (!ls->drop_locks_count) + return 0; + + if (time_after(jiffies, ls->drop_time + ls->drop_locks_period * HZ)) { + ls->drop_time = jiffies; + if (ls->all_locks_count >= ls->drop_locks_count) + return 1; + } + return 0; +} + +static int gdlm_thread(void *data) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) data; + struct gdlm_lock *lp = NULL; + int blist = 0; + uint8_t complete, blocking, submit, drop; + DECLARE_WAITQUEUE(wait, current); + + /* Only thread1 is allowed to do blocking callbacks since gfs + may wait for a completion callback within a blocking cb. */ + + if (current == ls->thread1) + blist = 1; + + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ls->thread_wait, &wait); + if (no_work(ls, blist)) + schedule(); + remove_wait_queue(&ls->thread_wait, &wait); + set_current_state(TASK_RUNNING); + + complete = blocking = submit = drop = 0; + + spin_lock(&ls->async_lock); + + if (blist && !list_empty(&ls->blocking)) { + lp = list_entry(ls->blocking.next, struct gdlm_lock, + blist); + list_del_init(&lp->blist); + blocking = lp->bast_mode; + lp->bast_mode = 0; + } else if (!list_empty(&ls->complete)) { + lp = list_entry(ls->complete.next, struct gdlm_lock, + clist); + list_del_init(&lp->clist); + complete = 1; + } else if (!list_empty(&ls->submit)) { + lp = list_entry(ls->submit.next, struct gdlm_lock, + delay_list); + list_del_init(&lp->delay_list); + submit = 1; + } + + drop = check_drop(ls); + spin_unlock(&ls->async_lock); + + if (complete) + process_complete(lp); + + else if (blocking) + process_blocking(lp, blocking); + + else if (submit) + process_submit(lp); + + if (drop) + ls->fscb(ls->fsdata, LM_CB_DROPLOCKS, NULL); + + schedule(); + } + + return 0; +} + +int gdlm_init_threads(struct gdlm_ls *ls) +{ + struct task_struct *p; + int error; + + p = kthread_run(gdlm_thread, ls, "lock_dlm1"); + error = IS_ERR(p); + if (error) { + log_all("can't start lock_dlm1 thread %d", error); + return error; + } + ls->thread1 = p; + + p = kthread_run(gdlm_thread, ls, "lock_dlm2"); + error = IS_ERR(p); + if (error) { + log_all("can't start lock_dlm2 thread %d", error); + kthread_stop(ls->thread1); + return error; + } + ls->thread2 = p; + + return 0; +} + +void gdlm_release_threads(struct gdlm_ls *ls) +{ + kthread_stop(ls->thread1); + kthread_stop(ls->thread2); +} + diff --git a/fs/gfs2/locking/nolock/Makefile b/fs/gfs2/locking/nolock/Makefile new file mode 100644 index 00000000000..cdadf956c83 --- /dev/null +++ b/fs/gfs2/locking/nolock/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_GFS2_FS) += lock_nolock.o +lock_nolock-y := main.o + diff --git a/fs/gfs2/locking/nolock/lock_nolock.mod.c b/fs/gfs2/locking/nolock/lock_nolock.mod.c new file mode 100644 index 00000000000..ae92522b218 --- /dev/null +++ b/fs/gfs2/locking/nolock/lock_nolock.mod.c @@ -0,0 +1,44 @@ +#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 new file mode 100644 index 00000000000..d3919e47116 --- /dev/null +++ b/fs/gfs2/locking/nolock/main.c @@ -0,0 +1,357 @@ +/****************************************************************************** +******************************************************************************* +** +** 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 "../../lm_interface.h" + +struct nolock_lockspace { + unsigned int nl_lvb_size; +}; + +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) +{ + char *c; + unsigned int jid; + struct nolock_lockspace *nl; + + /* If there is a "jid=" in the hostdata, return that jid. + Otherwise, return zero. */ + + c = strstr(host_data, "jid="); + if (!c) + jid = 0; + else { + c += 4; + sscanf(c, "%u", &jid); + } + + nl = kmalloc(sizeof(struct nolock_lockspace), GFP_KERNEL); + if (!nl) + return -ENOMEM; + + memset(nl, 0, sizeof(struct nolock_lockspace)); + nl->nl_lvb_size = min_lvb_size; + + lockstruct->ls_jid = jid; + lockstruct->ls_first = 1; + lockstruct->ls_lvb_size = min_lvb_size; + lockstruct->ls_lockspace = (lm_lockspace_t *)nl; + lockstruct->ls_ops = &nolock_ops; + lockstruct->ls_flags = LM_LSFLAG_LOCAL; + + 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) +{ +} + +/** + * nolock_get_lock - get a lm_lock_t given a descripton of the lock + * @lockspace: the lockspace the lock lives in + * @name: the name of the lock + * @lockp: return the lm_lock_t here + * + * Returns: 0 on success, -EXXX on failure + */ + +static int nolock_get_lock(lm_lockspace_t *lockspace, struct lm_lockname *name, + lm_lock_t **lockp) +{ + *lockp = (lm_lock_t *)lockspace; + return 0; +} + +/** + * nolock_put_lock - get rid of a lock structure + * @lock: the lock to throw away + * + */ + +static void nolock_put_lock(lm_lock_t *lock) +{ +} + +/** + * nolock_lock - acquire a lock + * @lock: the lock to manipulate + * @cur_state: the current state + * @req_state: the requested state + * @flags: modifier flags + * + * Returns: A bitmap of LM_OUT_* + */ + +static unsigned int nolock_lock(lm_lock_t *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags) +{ + return req_state | LM_OUT_CACHEABLE; +} + +/** + * nolock_unlock - unlock a lock + * @lock: the lock to manipulate + * @cur_state: the current state + * + * Returns: 0 + */ + +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) +{ +} + +/** + * nolock_hold_lvb - hold on to a lock value block + * @lock: the lock the LVB is associated with + * @lvbp: return the lm_lvb_t here + * + * Returns: 0 on success, -EXXX on failure + */ + +static int nolock_hold_lvb(lm_lock_t *lock, char **lvbp) +{ + struct nolock_lockspace *nl = (struct nolock_lockspace *)lock; + int error = 0; + + *lvbp = kmalloc(nl->nl_lvb_size, GFP_KERNEL); + if (*lvbp) + memset(*lvbp, 0, nl->nl_lvb_size); + else + error = -ENOMEM; + + return error; +} + +/** + * nolock_unhold_lvb - release a LVB + * @lock: the lock the LVB is associated with + * @lvb: the lock value block + * + */ + +static void nolock_unhold_lvb(lm_lock_t *lock, char *lvb) +{ + kfree(lvb); +} + +/** + * nolock_sync_lvb - sync out the value of a lvb + * @lock: the lock the LVB is associated with + * @lvb: the lock value block + * + */ + +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) +{ + 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; +} + +/** + * 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) +{ + int error; + lock_kernel(); + error = posix_lock_file_wait(file, fl); + unlock_kernel(); + 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) +{ + int error; + lock_kernel(); + error = posix_lock_file_wait(file, fl); + unlock_kernel(); + 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) +{ +} + +struct lm_lockops nolock_ops = { + .lm_proto_name = "lock_nolock", + .lm_mount = nolock_mount, + .lm_others_may_mount = nolock_others_may_mount, + .lm_unmount = nolock_unmount, + .lm_withdraw = nolock_withdraw, + .lm_get_lock = nolock_get_lock, + .lm_put_lock = nolock_put_lock, + .lm_lock = nolock_lock, + .lm_unlock = nolock_unlock, + .lm_cancel = nolock_cancel, + .lm_hold_lvb = nolock_hold_lvb, + .lm_unhold_lvb = nolock_unhold_lvb, + .lm_sync_lvb = nolock_sync_lvb, + .lm_plock_get = nolock_plock_get, + .lm_plock = nolock_plock, + .lm_punlock = nolock_punlock, + .lm_recovery_done = nolock_recovery_done, + .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); + if (error) { + printk("lock_nolock: can't register protocol: %d\n", error); + return error; + } + + printk("Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__); + return 0; +} + +/** + * exit_nolock - cleanup the nolock module + * + */ + +void __exit exit_nolock(void) +{ + lm_unregister_proto(&nolock_ops); +} + +module_init(init_nolock); +module_exit(exit_nolock); + +MODULE_DESCRIPTION("GFS Nolock Locking Module"); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + -- GitLab From a8f2d64728d8b706392fc1cb0f2fd6852a5e27ae Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 17 Jan 2006 08:36:49 +0000 Subject: [PATCH 0006/1619] [GFS2] Fix typo in GFS2 Makefile A two line fix to the GFS2 Makefile. Signed-off-by: David Teigland Signed-off-by: Steve Whitehouse --- fs/gfs2/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index b1bac4f199d..974c76d0c6f 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -39,6 +39,6 @@ gfs2-y := \ unlinked.o \ util.o -obj-$(CONFIG_GFS2_LOCKING_NOLOCK) += locking/nolock/ -obj-$(CONFIG_GFS2_LOCKING_DLM) += locking/dlm/ +obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ +obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/ -- GitLab From 869d81df53ad28ce78fc92504b3365b8196a2fa1 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 17 Jan 2006 08:47:12 +0000 Subject: [PATCH 0007/1619] [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 diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile index d3bca02f7b3..a9733ff8037 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 daf59d504e2..d799865b64a 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 00000000000..fa545f7872e --- /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 3ced92ef1b1..2c13c916a35 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 92b1789deb8..bfb224638f2 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 00000000000..382847205bc --- /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 8964733f55e..e1e5186c97c 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 22bbe6d3a5a..6fe669cd334 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 ae92522b218..00000000000 --- 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 d3919e47116..b716e336c07 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 00000000000..007b07a178a --- /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 + -- GitLab From cd1344fe322cd9d95b2c0f011d6766677cfcb29b Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 08:53:38 +0000 Subject: [PATCH 0008/1619] [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(-) diff --git a/include/linux/gfs2_ioctl.h b/include/linux/gfs2_ioctl.h index dde9840b1c3..ca963286283 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__ */ -- GitLab From e47314207032cfd1157b8c377df162839b32ea6f Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 09:21:38 +0000 Subject: [PATCH 0009/1619] [GFS2] Add documentation for GFS2 Signed-off-by: David Teigland Signed-off-by: Steve Whitehouse --- Documentation/filesystems/gfs2.txt | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/filesystems/gfs2.txt diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt new file mode 100644 index 00000000000..4a060d38bed --- /dev/null +++ b/Documentation/filesystems/gfs2.txt @@ -0,0 +1,44 @@ +Global File System +------------------ + +http://sources.redhat.com/cluster/ + +GFS is a cluster file system. It 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 +file system, but also uses a lock module to allow the computers coordinate +their I/O so file system consistency is maintained. One of the nifty +features of GFS is perfect consistency -- changes made to the file system +on one machine show up immediately on all other machines in the cluster. + +GFS uses interchangable inter-node locking mechanisms. Different lock +modules can plug into GFS and each file system selects the appropriate +lock module at mount time. Lock modules include: + + lock_nolock -- allows gfs to be used as a local file system + + lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking + The dlm is found at linux/fs/dlm/ + +In addition to interfacing with an external locking manager, a gfs lock +module is responsible for interacting with external cluster management +systems. Lock_dlm depends on user space cluster management systems found +at the URL above. + +To use gfs as a local file system, no external clustering systems are +needed, simply: + + $ gfs2_mkfs -p lock_nolock -j 1 /dev/block_device + $ mount -t gfs2 /dev/block_device /dir + +GFS2 is not on-disk compatible with previous versions of GFS. + +The following man pages can be found at the URL above: + gfs2_mkfs to make a filesystem + gfs2_fsck to repair a filesystem + gfs2_grow to expand a filesystem online + gfs2_jadd to add journals to a filesystem online + gfs2_tool to manipulate, examine and tune a filesystem + gfs2_quota to examine and change quota values in a filesystem + mount.gfs2 to find mount options + -- GitLab From e7fd41792fc0ee52a05fcaac87511f118328d147 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 09:30:29 +0000 Subject: [PATCH 0010/1619] [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 diff --git a/fs/Kconfig b/fs/Kconfig index bec8afa5704..3a32f3f97e9 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 0922727732c..b298f4fdc6f 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 00000000000..d01f735e6e0 --- /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 00000000000..1e6232e7d8e --- /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 00000000000..2bd1c5e1a72 --- /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 00000000000..6ee276c74c5 --- /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 00000000000..024ace9973a --- /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 00000000000..9da7839958a --- /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 00000000000..98b49a1ece4 --- /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 00000000000..a8bf600ed13 --- /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 00000000000..0f1dde54bcd --- /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 00000000000..0b0eb1267b6 --- /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 00000000000..0020cd07baf --- /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 00000000000..81efb361f95 --- /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 00000000000..9e6499f773d --- /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 00000000000..fee4659b658 --- /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 00000000000..17bd3ba863a --- /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 00000000000..09b0124f7fc --- /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 00000000000..3af8035ff12 --- /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 00000000000..cc3e92f3fee --- /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 00000000000..81bf4cb2203 --- /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 00000000000..439249b62a5 --- /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 00000000000..927c08c1921 --- /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 00000000000..0b9851d0bdb --- /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 00000000000..7b235132b0b --- /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 00000000000..d96f9bbb407 --- /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 00000000000..95852a5f111 --- /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 00000000000..4c5c08a8860 --- /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 00000000000..d7984321ff4 --- /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 00000000000..1712c97bc22 --- /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 00000000000..ebd0363f1e0 --- /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 00000000000..06e4f7cab6e --- /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 00000000000..866657c5d69 --- /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 00000000000..36afe99e4f9 --- /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 00000000000..349f0d292d9 --- /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 00000000000..826d122edf5 --- /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 00000000000..2b25915161c --- /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 00000000000..dd324ba44d8 --- /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 00000000000..5e17d295544 --- /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 + -- GitLab From 5ddec5b3d79eed6df1a37be435f183915a4b696a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 09:34:14 +0000 Subject: [PATCH 0011/1619] [GFS2] Only two args for kobject_uevent() in locking/dlm/mount.c Update the dlm interface module to take account of the recently removed third argument to kobject_uevent() Signed-off-by: David Teigland Signed-off-by: Steve Whitehouse --- fs/gfs2/locking/dlm/mount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index bfb224638f2..042f3a75c44 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -195,14 +195,14 @@ static void gdlm_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, { struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; ls->recover_jid_done = jid; - kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL); + kobject_uevent(&ls->kobj, KOBJ_CHANGE); } static void gdlm_others_may_mount(lm_lockspace_t *lockspace) { struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; ls->first_done = 1; - kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL); + kobject_uevent(&ls->kobj, KOBJ_CHANGE); } /* Userspace gets the offline uevent, blocks new gfs locks on @@ -213,7 +213,7 @@ static void gdlm_withdraw(lm_lockspace_t *lockspace) { struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; - kobject_uevent(&ls->kobj, KOBJ_OFFLINE, NULL); + kobject_uevent(&ls->kobj, KOBJ_OFFLINE); wait_event_interruptible(ls->wait_control, test_bit(DFL_WITHDRAW, &ls->flags)); -- GitLab From c73530a1f9633b2e7e6e19d0274b575febf8e8dc Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 10:11:51 +0000 Subject: [PATCH 0012/1619] [GFS2] Remove remains of the GFS2 identify ioctl() We don't need this ioctl, we can use stat() to gain the same information. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 1e6f51b74f4..563c19d0d40 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -1214,16 +1214,9 @@ static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 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; -- GitLab From 666a2c534cc6238932296a95c9e9c06ca3b73d97 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 10:29:04 +0000 Subject: [PATCH 0013/1619] [GFS2] Remove unused code from various files Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 81 +------------------------------------------------ fs/gfs2/bmap.h | 2 -- fs/gfs2/dir.c | 51 ------------------------------- fs/gfs2/dir.h | 2 -- fs/gfs2/eattr.c | 57 ---------------------------------- fs/gfs2/eattr.h | 2 -- fs/gfs2/util.c | 30 ------------------ fs/gfs2/util.h | 8 ----- 8 files changed, 1 insertion(+), 232 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 4b4e295b3bf..bece3620f1c 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -999,7 +999,7 @@ static int do_shrink(struct gfs2_inode *ip, uint64_t size, } /** - * gfs2_truncatei - make a file a give size + * gfs2_truncatei - make a file a given size * @ip: the inode * @size: the size to make the file * @truncator: function to truncate the last partial block @@ -1125,82 +1125,3 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, 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 index de16e44f049..25ea32905c6 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -34,6 +34,4 @@ 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); -int gfs2_get_file_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub); - #endif /* __BMAP_DOT_H__ */ diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 6b1dc3dc3a2..f6304e55dbc 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -2104,54 +2104,3 @@ int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename, 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 index 79f77aab426..ff6d1c597ee 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -46,6 +46,4 @@ 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/eattr.c b/fs/gfs2/eattr.c index 63a5cf1e247..dec55dcb9db 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -1561,60 +1561,3 @@ int gfs2_ea_dealloc(struct gfs2_inode *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 index a6403929575..e5a42abf68a 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -74,8 +74,6 @@ 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, diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 74e2c62f237..ad49153c33d 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -221,36 +221,6 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, 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) { diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 21466fe9bf4..8d6eba3bdf0 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -152,14 +152,6 @@ 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) { -- GitLab From 3bd7662c4de28522d4709ab5a56033e3c33e1d4a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 10:40:17 +0000 Subject: [PATCH 0014/1619] [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(-) diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 2a1ef5aa7f0..0d54e082e62 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 213d664d495..8354b9c4f40 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 */ -- GitLab From b96ca4fa4e3b510d528a093a5bac0befbc2ba46d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 10:57:10 +0000 Subject: [PATCH 0015/1619] [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(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 73922dba539..aa5311ef7ba 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 0d54e082e62..854b5049b8d 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 8354b9c4f40..f1302e2616d 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); -- GitLab From d4e9c4c3bf861ef2ac96e0de659c75a00da92b28 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 11:19:28 +0000 Subject: [PATCH 0016/1619] [GFS2] Add an additional argument to gfs2_trans_add_bh() This adds an extra argument to gfs2_trans_add_bh() to indicate whether the bh being added to the transaction is metadata or data. Its currently unused since all existing callers set it to 1 (metadata) but following patches will make use of it. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 2 +- fs/gfs2/bmap.c | 24 ++++++++++++------------ fs/gfs2/dir.c | 32 ++++++++++++++++---------------- fs/gfs2/eattr.c | 38 +++++++++++++++++++------------------- fs/gfs2/inode.c | 16 ++++++++-------- fs/gfs2/jdata.c | 8 ++++---- fs/gfs2/meta_io.c | 2 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/ops_file.c | 10 +++++----- fs/gfs2/ops_inode.c | 4 ++-- fs/gfs2/quota.c | 2 +- fs/gfs2/resize.c | 2 +- fs/gfs2/rgrp.c | 16 ++++++++-------- fs/gfs2/super.c | 6 +++--- fs/gfs2/trans.c | 3 ++- fs/gfs2/trans.h | 2 +- fs/gfs2/unlinked.c | 2 +- 17 files changed, 86 insertions(+), 85 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 33c465a2ab5..9482a677ea4 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -202,7 +202,7 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index bece3620f1c..967cbc68195 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -124,7 +124,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, /* Set up the pointer to the new block */ - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); @@ -223,7 +223,7 @@ static int build_height(struct gfs2_inode *ip, int height) block = gfs2_alloc_meta(ip); bh = gfs2_meta_new(ip->i_gl, block); - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); @@ -236,7 +236,7 @@ static int build_height(struct gfs2_inode *ip, int height) /* Set up the new direct pointer and write it out to disk */ - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); @@ -382,7 +382,7 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, else *block = gfs2_alloc_meta(ip); - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); *ptr = cpu_to_be64(*block); ip->i_di.di_blocks++; @@ -490,7 +490,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, if (*new) { error = gfs2_meta_inode_buffer(ip, &bh); if (!error) { - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_dinode_out(&ip->i_di, bh->b_data); brelse(bh); } @@ -672,8 +672,8 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, down_write(&ip->i_rw_mutex); - gfs2_trans_add_bh(ip->i_gl, dibh); - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_trans_add_bh(ip->i_gl, bh, 1); bstart = 0; blen = 0; @@ -795,7 +795,7 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) if (error) goto out_end_trans; - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); @@ -833,7 +833,7 @@ static int truncator_journaled(struct gfs2_inode *ip, uint64_t size) if (error) return error; - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header) + off); brelse(bh); @@ -861,7 +861,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size, 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size); error = 1; @@ -879,7 +879,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size, 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); } } @@ -957,7 +957,7 @@ static int trunc_end(struct gfs2_inode *ip) 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f6304e55dbc..93d3704ac58 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -201,7 +201,7 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, return; } - gfs2_trans_add_bh(dip->i_gl, bh); + gfs2_trans_add_bh(dip->i_gl, bh, 1); /* 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 @@ -264,7 +264,7 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, return -EIO; } - gfs2_trans_add_bh(dip->i_gl, 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); @@ -282,7 +282,7 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, 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); + gfs2_trans_add_bh(dip->i_gl, bh, 1); if (dent->de_inum.no_addr) { new = (struct gfs2_dirent *)((char *)dent + @@ -552,7 +552,7 @@ static int dir_make_exhash(struct gfs2_inode *dip) /* Turn over a new leaf */ bh = gfs2_meta_new(dip->i_gl, bn); - gfs2_trans_add_bh(dip->i_gl, bh); + 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)); @@ -596,7 +596,7 @@ static int dir_make_exhash(struct gfs2_inode *dip) /* We're done with the new leaf block, now setup the new hash table. */ - gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); lp = (uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)); @@ -647,7 +647,7 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, /* Get the new leaf block */ nbh = gfs2_meta_new(dip->i_gl, bn); - gfs2_trans_add_bh(dip->i_gl, nbh); + 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)); @@ -661,7 +661,7 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, if (error) goto fail; - gfs2_trans_add_bh(dip->i_gl, obh); + gfs2_trans_add_bh(dip->i_gl, obh, 1); oleaf = (struct gfs2_leaf *)obh->b_data; @@ -1285,14 +1285,14 @@ static int dir_e_add(struct gfs2_inode *dip, struct qstr *filename, bn = gfs2_alloc_meta(dip); nbh = gfs2_meta_new(dip->i_gl, bn); - gfs2_trans_add_bh(dip->i_gl, nbh); + 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); + gfs2_trans_add_bh(dip->i_gl, bh, 1); leaf->lf_next = cpu_to_be64(bn); nleaf = (struct gfs2_leaf *)nbh->b_data; @@ -1330,7 +1330,7 @@ static int dir_e_add(struct gfs2_inode *dip, struct qstr *filename, 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_trans_add_bh(dip->i_gl, dibh, 1); gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); @@ -1376,7 +1376,7 @@ static int dir_e_del(struct gfs2_inode *dip, struct qstr *filename) 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_trans_add_bh(dip->i_gl, dibh, 1); gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); @@ -1481,7 +1481,7 @@ static int dir_e_mvino(struct gfs2_inode *dip, struct qstr *filename, if (error) return error; - gfs2_trans_add_bh(dip->i_gl, bh); + gfs2_trans_add_bh(dip->i_gl, bh, 1); gfs2_inum_out(inum, (char *)&dent->de_inum); dent->de_type = new_type; @@ -1494,7 +1494,7 @@ static int dir_e_mvino(struct gfs2_inode *dip, struct qstr *filename, dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); @@ -1681,7 +1681,7 @@ static int dir_l_mvino(struct gfs2_inode *dip, struct qstr *filename, if (error) goto out; - gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_inum_out(inum, (char *)&dent->de_inum); dent->de_type = new_type; @@ -1976,7 +1976,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, if (error) goto out_end_trans; - gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); @@ -2030,7 +2030,7 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) error = gfs2_meta_inode_buffer(dip, &bh); if (!error) { - gfs2_trans_add_bh(dip->i_gl, bh); + gfs2_trans_add_bh(dip->i_gl, bh, 1); ((struct gfs2_dinode *)bh->b_data)->di_mode = cpu_to_be32(S_IFREG); brelse(bh); } diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index dec55dcb9db..02e45c4ecbe 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -268,7 +268,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, if (error) goto out_gunlock; - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); dataptrs = GFS2_EA2DATAPTRS(ea); for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) { @@ -309,7 +309,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(); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -628,7 +628,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) block = gfs2_alloc_meta(ip); *bhp = gfs2_meta_new(ip->i_gl, block); - gfs2_trans_add_bh(ip->i_gl, *bhp); + gfs2_trans_add_bh(ip->i_gl, *bhp, 1); gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA); gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header)); @@ -686,7 +686,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, block = gfs2_alloc_meta(ip); bh = gfs2_meta_new(ip->i_gl, block); - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); ip->i_di.di_blocks++; @@ -759,7 +759,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ip->i_di.di_mode = er->er_mode; } ip->i_di.di_ctime = get_seconds(); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -839,7 +839,7 @@ static void ea_set_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_header *prev = el->el_prev; uint32_t len; - gfs2_trans_add_bh(ip->i_gl, el->el_bh); + gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); if (!prev || !GFS2_EA_IS_STUFFED(ea)) { ea->ea_type = GFS2_EATYPE_UNUSED; @@ -877,7 +877,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, if (error) return error; - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); if (es->ea_split) ea = ea_split_ea(ea); @@ -897,7 +897,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, ip->i_di.di_mode = er->er_mode; } ip->i_di.di_ctime = get_seconds(); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); out: @@ -913,7 +913,7 @@ static int ea_set_simple_alloc(struct gfs2_inode *ip, struct gfs2_ea_header *ea = es->es_ea; int error; - gfs2_trans_add_bh(ip->i_gl, es->es_bh); + gfs2_trans_add_bh(ip->i_gl, es->es_bh, 1); if (es->ea_split) ea = ea_split_ea(ea); @@ -1007,14 +1007,14 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, goto out; } - gfs2_trans_add_bh(ip->i_gl, indbh); + gfs2_trans_add_bh(ip->i_gl, indbh, 1); } 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_trans_add_bh(ip->i_gl, indbh, 1); gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(indbh, mh_size); @@ -1163,7 +1163,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) if (error) return error; - gfs2_trans_add_bh(ip->i_gl, el->el_bh); + gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); if (prev) { uint32_t len; @@ -1179,7 +1179,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(); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -1288,7 +1288,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, goto fail; } - gfs2_trans_add_bh(ip->i_gl, bh[x]); + gfs2_trans_add_bh(ip->i_gl, bh[x], 1); memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data, @@ -1323,7 +1323,7 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, if (error) return error; - gfs2_trans_add_bh(ip->i_gl, el->el_bh); + gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); memcpy(GFS2_EA2DATA(el->el_ea), data, GFS2_EA_DATA_LEN(el->el_ea)); @@ -1338,7 +1338,7 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -1416,7 +1416,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) if (error) goto out_gunlock; - gfs2_trans_add_bh(ip->i_gl, indbh); + gfs2_trans_add_bh(ip->i_gl, indbh, 1); eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs2_meta_header)); bstart = 0; @@ -1450,7 +1450,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); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -1502,7 +1502,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); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index aa5311ef7ba..9ed7c054106 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -691,7 +691,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) ip->i_di.di_nlink = nlink; ip->i_di.di_ctime = get_seconds(); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); @@ -786,7 +786,7 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) if (ir.ir_length) { *formal_ino = ir.ir_start++; ir.ir_length--; - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); brelse(bh); @@ -843,7 +843,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) if (x < y) gfs2_consist_inode(m_ip); x = cpu_to_be64(x); - gfs2_trans_add_bh(m_ip->i_gl, m_bh); + gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); *(uint64_t *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x; brelse(m_bh); @@ -852,7 +852,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) *formal_ino = ir.ir_start++; ir.ir_length--; - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); out_brelse: @@ -997,7 +997,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, struct buffer_head *dibh; dibh = gfs2_meta_new(gl, inum->no_addr); - gfs2_trans_add_bh(gl, dibh); + gfs2_trans_add_bh(gl, dibh, 1); gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); di = (struct gfs2_dinode *)dibh->b_data; @@ -1135,7 +1135,7 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, if (error) goto fail_end_trans; ip->i_di.di_nlink = 1; - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); @@ -1601,7 +1601,7 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) ip->i_di.di_atime = curtime; - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); @@ -1776,7 +1776,7 @@ __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) gfs2_assert_warn(ip->i_sbd, !error); gfs2_inode_attr_out(ip); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } diff --git a/fs/gfs2/jdata.c b/fs/gfs2/jdata.c index d4adbf171ed..6caa93e46ce 100644 --- a/fs/gfs2/jdata.c +++ b/fs/gfs2/jdata.c @@ -30,7 +30,7 @@ int gfs2_jdata_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, if (new) { bh = gfs2_meta_new(ip->i_gl, block); - gfs2_trans_add_bh(ip->i_gl, bh); + 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 { @@ -220,7 +220,7 @@ int gfs2_jdata_read(struct gfs2_inode *ip, char __user *buf, uint64_t offset, 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); + gfs2_trans_add_bh(ip->i_gl, bh, 1); memcpy(bh->b_data + offset, *buf, size); *buf += size; @@ -243,7 +243,7 @@ int gfs2_copy_from_user(struct gfs2_inode *ip, struct buffer_head *bh, { int error = 0; - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); if (copy_from_user(bh->b_data + offset, *buf, size)) error = -EFAULT; else @@ -368,7 +368,7 @@ int gfs2_jdata_write(struct gfs2_inode *ip, const char __user *buf, uint64_t off 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 177b0246d19..8bbe1185522 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -786,7 +786,7 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, brelse(bh); return -EIO; } - gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 0aa5f140ddb..d352b3528f5 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -368,7 +368,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, if (error) goto fail; - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); kaddr = kmap(page); memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 563c19d0d40..0f356fc4690 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -456,7 +456,7 @@ static ssize_t do_write_direct_alloc(struct file *file, const char __user *buf, 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -481,7 +481,7 @@ static ssize_t do_write_direct_alloc(struct file *file, const char __user *buf, 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); @@ -721,7 +721,7 @@ static ssize_t do_do_write_buf(struct file *file, const char __user *buf, size_t 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -752,7 +752,7 @@ static ssize_t do_do_write_buf(struct file *file, const char __user *buf, size_t 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_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -1177,7 +1177,7 @@ static int gfs2_ioctl_flags(struct gfs2_inode *ip, unsigned int cmd, unsigned lo ip->i_di.di_flags = flags; - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index d0f90b88380..89417a6cb72 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -839,7 +839,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_end_trans; ip->i_di.di_ctime = get_seconds(); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } @@ -1043,7 +1043,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) gfs2_assert_warn(sdp, !error); gfs2_inode_attr_out(ip); - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index a0320f22b57..5fb5a5305e0 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -527,7 +527,7 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) int64_t x; down(&sdp->sd_quota_mutex); - gfs2_trans_add_bh(ip->i_gl, qd->qd_bh); + gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1); if (!test_bit(QDF_CHANGE, &qd->qd_flags)) { qc->qc_change = 0; diff --git a/fs/gfs2/resize.c b/fs/gfs2/resize.c index 67d26b99a73..a5309668250 100644 --- a/fs/gfs2/resize.c +++ b/fs/gfs2/resize.c @@ -255,7 +255,7 @@ int gfs2_rename2system(struct gfs2_inode *ip, if (error) goto out_trans; ip->i_di.di_flags |= GFS2_DIF_SYSTEM; - gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 8df6fba20fa..87c80bbce1c 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -967,7 +967,7 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, if (gfs2_assert_withdraw(rgd->rd_sbd, x <= length)) blk = 0; - gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh); + gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, blk, new_state); @@ -1027,7 +1027,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len); } - gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh); + gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, buf_blk, new_state); @@ -1066,7 +1066,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip) 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_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); al->al_alloced++; @@ -1111,7 +1111,7 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) 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_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); al->al_alloced++; @@ -1153,7 +1153,7 @@ uint64_t gfs2_alloc_di(struct gfs2_inode *dip) rgd->rd_rg.rg_free--; rgd->rd_rg.rg_dinodes++; - gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + 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); al->al_alloced++; @@ -1187,7 +1187,7 @@ void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) rgd->rd_rg.rg_free += blen; - gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + 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); @@ -1216,7 +1216,7 @@ void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) rgd->rd_rg.rg_free += blen; - gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + 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); @@ -1242,7 +1242,7 @@ void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) rgd->rd_rg.rg_dinodes--; rgd->rd_rg.rg_free++; - gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + 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_statfs_change(sdp, 0, +1, -1); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index d37f203e133..cab7ab5fb50 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -608,7 +608,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, return; down(&sdp->sd_statfs_mutex); - gfs2_trans_add_bh(l_ip->i_gl, l_bh); + gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); up(&sdp->sd_statfs_mutex); spin_lock(&sdp->sd_statfs_spin); @@ -659,7 +659,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) goto out_bh2; down(&sdp->sd_statfs_mutex); - gfs2_trans_add_bh(l_ip->i_gl, l_bh); + gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); up(&sdp->sd_statfs_mutex); spin_lock(&sdp->sd_statfs_spin); @@ -671,7 +671,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) 0, sizeof(struct gfs2_statfs_change)); spin_unlock(&sdp->sd_statfs_spin); - gfs2_trans_add_bh(m_ip->i_gl, m_bh); + gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); gfs2_trans_end(sdp); diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index afa5408c000..82952fb6483 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -138,10 +138,11 @@ void gfs2_trans_add_gl(struct gfs2_glock *gl) * 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 + * @meta: True in the case of adding metadata * */ -void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh) +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; diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index ac615e9e852..5a7da1e853c 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -31,7 +31,7 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, 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_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); diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 4a993af58c1..b8d836e3a5c 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -47,7 +47,7 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, } down(&sdp->sd_unlinked_mutex); - gfs2_trans_add_bh(ip->i_gl, bh); + 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)); -- GitLab From 586dfdaaf328d79bb356d760db963b03a75a4131 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 11:32:00 +0000 Subject: [PATCH 0017/1619] [GFS2] Make the new argument to gfs2_trans_add_bh() actually do something Passes the flag through to ensure that the correct log operations are invoked when the flag is set. Signed-off-by: Steven Whitehouse: --- fs/gfs2/meta_io.c | 11 +++++++---- fs/gfs2/meta_io.h | 2 +- fs/gfs2/trans.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 8bbe1185522..134f31efe51 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -537,13 +537,13 @@ int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) } /** - * gfs2_meta_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer + * gfs2_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 - * + * @meta: Flag to indicate whether its metadata or not */ -void gfs2_meta_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh) +void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta) { struct gfs2_bufdata *bd; @@ -563,7 +563,10 @@ void gfs2_meta_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh) bd->bd_gl = gl; INIT_LIST_HEAD(&bd->bd_list_tr); - lops_init_le(&bd->bd_le, &gfs2_buf_lops); + if (meta) + lops_init_le(&bd->bd_le, &gfs2_buf_lops); + else + lops_init_le(&bd->bd_le, &gfs2_databuf_lops); set_v2bd(bh, bd); diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 5556df8cc6c..10fbf825c11 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -64,7 +64,7 @@ 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_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); 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); diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 82952fb6483..a9df4a34eba 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -151,7 +151,7 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) if (bd) gfs2_assert(sdp, bd->bd_gl == gl); else { - gfs2_meta_attach_bufdata(gl, bh); + gfs2_attach_bufdata(gl, bh, meta); bd = get_v2bd(bh); } -- GitLab From 64fb4eb7d4cc9de89f4d9b9061adde46ed3b5641 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 13:14:40 +0000 Subject: [PATCH 0018/1619] [GFS2] Remove gfs2_databuf in favour of gfs2_bufdata structure Removing the gfs2_databuf structure and using gfs2_bufdata instead is a step towards allowing journaling of data without requiring the metadata header on each journaled block. The idea is to merge the code paths for ordered data with that of journaled data, with the log operations in lops.c tacking account of the different types of buffers as they are presented to it. Largely the code path for metadata will be similar too, but obviously through a different set of log operations. Signed-off-by: Steven Whitehouse --- fs/gfs2/gfs2.h | 2 -- fs/gfs2/incore.h | 6 ------ fs/gfs2/lops.c | 20 ++++++++++---------- fs/gfs2/ops_address.c | 10 +++++----- fs/gfs2/trans.c | 18 +++++++++--------- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h index a5d11823846..6c53d080675 100644 --- a/fs/gfs2/gfs2.h +++ b/fs/gfs2/gfs2.h @@ -45,8 +45,6 @@ enum { #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) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 3ed0a7f26e4..3bc40ff5fdf 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -25,7 +25,6 @@ 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; @@ -116,11 +115,6 @@ struct gfs2_bufdata { 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); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index d501e8224ed..efb1087d0fa 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -442,15 +442,15 @@ 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 gfs2_bufdata *bd; 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); + bd = list_entry(head->prev, struct gfs2_bufdata, bd_le.le_list); + list_move(&bd->bd_le.le_list, &started); gfs2_log_lock(sdp); - bh = db->db_bh; + bh = bd->bd_bh; if (bh) { get_bh(bh); gfs2_log_unlock(sdp); @@ -464,22 +464,22 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } while (!list_empty(&started)) { - db = list_entry(started.next, struct gfs2_databuf, - db_le.le_list); - list_del(&db->db_le.le_list); + bd = list_entry(started.next, struct gfs2_bufdata, + bd_le.le_list); + list_del(&bd->bd_le.le_list); sdp->sd_log_num_databuf--; gfs2_log_lock(sdp); - bh = db->db_bh; + bh = bd->bd_bh; if (bh) { - set_v2db(bh, NULL); + set_v2bd(bh, NULL); gfs2_log_unlock(sdp); wait_on_buffer(bh); brelse(bh); } else gfs2_log_unlock(sdp); - kfree(db); + kfree(bd); } gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index d352b3528f5..db66d328755 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -429,13 +429,13 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) { - struct gfs2_databuf *db; + struct gfs2_bufdata *bd; gfs2_log_lock(sdp); - db = get_v2db(bh); - if (db) { - db->db_bh = NULL; - set_v2db(bh, NULL); + bd = get_v2bd(bh); + if (bd) { + bd->bd_bh = NULL; + set_v2bd(bh, NULL); gfs2_log_unlock(sdp); brelse(bh); } else diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index a9df4a34eba..b014591fa4a 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -199,17 +199,17 @@ void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd) void gfs2_trans_add_databuf(struct gfs2_sbd *sdp, struct buffer_head *bh) { - struct gfs2_databuf *db; + struct gfs2_bufdata *bd; - 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); + 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); - db->db_bh = bh; - set_v2db(bh, db); - lops_add(sdp, &db->db_le); + bd->bd_bh = bh; + set_v2bd(bh, bd); + lops_add(sdp, &bd->bd_le); } } -- GitLab From 4f3df04137d426a0ad1758ab744f5b6d658617bf Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 13:20:16 +0000 Subject: [PATCH 0019/1619] [GFS2] Change memory allocations to GFP_NOFS I'd like to be rid of these memory allocations entirely so far as is possible. For the moment though, mark them GFP_NOFS to make them less harmful. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 736d0d33dd1..f6d00130f96 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -350,7 +350,7 @@ struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) struct gfs2_log_buf *lb; struct buffer_head *bh; - lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_KERNEL | __GFP_NOFAIL); + lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); list_add(&lb->lb_list, &sdp->sd_log_flush_list); bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); @@ -380,7 +380,7 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct gfs2_log_buf *lb; struct buffer_head *bh; - lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_KERNEL | __GFP_NOFAIL); + lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); list_add(&lb->lb_list, &sdp->sd_log_flush_list); lb->lb_real = real; @@ -510,7 +510,7 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) atomic_inc(&sdp->sd_log_flush_incore); - ai = kzalloc(sizeof(struct gfs2_ail), GFP_KERNEL | __GFP_NOFAIL); + ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); INIT_LIST_HEAD(&ai->ai_ail1_list); INIT_LIST_HEAD(&ai->ai_ail2_list); -- GitLab From a98ab2204f8ed414c5e95fbca28a9f001c53bc7b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 13:38:44 +0000 Subject: [PATCH 0020/1619] [GFS2] Rename gfs2_meta_pin to gfs2_pin Since we'll need to pin data if we are going to journal it, then I'm renaming this function to make it less confusing. It might also be worth moving it into lops.c since there are no users outside that file. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 4 ++-- fs/gfs2/meta_io.c | 10 +++++----- fs/gfs2/meta_io.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index efb1087d0fa..a065f766723 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -79,7 +79,7 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_trans_add_gl(bd->bd_gl); gfs2_meta_check(sdp, bd->bd_bh); - gfs2_meta_pin(sdp, bd->bd_bh); + gfs2_pin(sdp, bd->bd_bh); gfs2_log_lock(sdp); sdp->sd_log_num_buf++; @@ -169,7 +169,7 @@ static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) list_del_init(&bd->bd_le.le_list); sdp->sd_log_num_buf--; - gfs2_meta_unpin(sdp, bd->bd_bh, ai); + gfs2_unpin(sdp, bd->bd_bh, ai); } gfs2_assert_warn(sdp, !sdp->sd_log_num_buf); } diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 134f31efe51..b6bd2ebfc2c 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -574,13 +574,13 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta } /** - * gfs2_meta_pin - Pin a metadata buffer in memory + * gfs2_pin - Pin a 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) +void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) { struct gfs2_bufdata *bd = get_v2bd(bh); @@ -609,15 +609,15 @@ void gfs2_meta_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) } /** - * gfs2_meta_unpin - Unpin a buffer + * gfs2_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) +void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct gfs2_ail *ai) { struct gfs2_bufdata *bd = get_v2bd(bh); diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 10fbf825c11..887cac302c1 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -65,9 +65,9 @@ int gfs2_meta_read(struct gfs2_glock *gl, uint64_t blkno, int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags); void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); -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_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); +void gfs2_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); -- GitLab From ec5800246607183a1d7fd0bae5f087c12439e9e7 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 14:21:40 +0000 Subject: [PATCH 0021/1619] [DLM] Export config_group_find_obj for use by the DLM Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/configfs/item.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/configfs/item.c b/fs/configfs/item.c index e07485ac50a..24421209f85 100644 --- a/fs/configfs/item.c +++ b/fs/configfs/item.c @@ -224,4 +224,4 @@ EXPORT_SYMBOL(config_item_init); EXPORT_SYMBOL(config_group_init); EXPORT_SYMBOL(config_item_get); EXPORT_SYMBOL(config_item_put); - +EXPORT_SYMBOL(config_group_find_obj); -- GitLab From 901359256b2666f52a3a7d3f31927677e91b3a2a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 20 Jan 2006 08:47:07 +0000 Subject: [PATCH 0022/1619] [DLM] Update DLM to the latest patch level Signed-off-by: David Teigland Signed-off-by: Steve Whitehouse --- fs/dlm/ast.c | 16 +++++----- fs/dlm/config.c | 20 ++++++------ fs/dlm/debug_fs.c | 4 +-- fs/dlm/device.c | 55 ++++++++++++++++++++------------- fs/dlm/dir.c | 4 +-- fs/dlm/dlm_internal.h | 23 +++----------- fs/dlm/lock.c | 72 +++++++++++++++++++++---------------------- fs/dlm/lock.h | 4 +-- fs/dlm/lockspace.c | 21 ++++++------- fs/dlm/member.c | 17 +++++----- fs/dlm/midcomms.c | 2 +- fs/dlm/recover.c | 18 +++++------ fs/dlm/recoverd.c | 16 +++++----- fs/dlm/requestqueue.c | 26 ++++++++-------- 14 files changed, 147 insertions(+), 151 deletions(-) diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index 2bd1c5e1a72..57bdf09b520 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -21,7 +21,7 @@ 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; +static struct mutex astd_running; void dlm_del_ast(struct dlm_lkb *lkb) @@ -56,7 +56,7 @@ static void process_asts(void) int type = 0, found, bmode; for (;;) { - found = FALSE; + found = 0; spin_lock(&ast_queue_lock); list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { r = lkb->lkb_resource; @@ -68,7 +68,7 @@ static void process_asts(void) list_del(&lkb->lkb_astqueue); type = lkb->lkb_ast_type; lkb->lkb_ast_type = 0; - found = TRUE; + found = 1; break; } spin_unlock(&ast_queue_lock); @@ -117,10 +117,10 @@ static int dlm_astd(void *data) schedule(); set_current_state(TASK_RUNNING); - down(&astd_running); + mutex_lock(&astd_running); if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) process_asts(); - up(&astd_running); + mutex_unlock(&astd_running); } return 0; } @@ -140,7 +140,7 @@ int dlm_astd_start(void) INIT_LIST_HEAD(&ast_queue); spin_lock_init(&ast_queue_lock); - init_MUTEX(&astd_running); + mutex_init(&astd_running); p = kthread_run(dlm_astd, NULL, "dlm_astd"); if (IS_ERR(p)) @@ -157,11 +157,11 @@ void dlm_astd_stop(void) void dlm_astd_suspend(void) { - down(&astd_running); + mutex_lock(&astd_running); } void dlm_astd_resume(void) { - up(&astd_running); + mutex_unlock(&astd_running); } diff --git a/fs/dlm/config.c b/fs/dlm/config.c index 024ace9973a..87df9616415 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -162,7 +162,7 @@ struct spaces { struct space { struct config_group group; struct list_head members; - struct semaphore members_lock; + struct mutex members_lock; int members_count; }; @@ -374,7 +374,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) sp->group.default_groups[1] = NULL; INIT_LIST_HEAD(&sp->members); - init_MUTEX(&sp->members_lock); + mutex_init(&sp->members_lock); sp->members_count = 0; return &sp->group; @@ -453,10 +453,10 @@ static struct config_item *make_node(struct config_group *g, const char *name) nd->nodeid = -1; nd->weight = 1; /* default weight of 1 if none is set */ - down(&sp->members_lock); + mutex_lock(&sp->members_lock); list_add(&nd->list, &sp->members); sp->members_count++; - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); return &nd->item; } @@ -466,10 +466,10 @@ 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); + mutex_lock(&sp->members_lock); list_del(&nd->list); sp->members_count--; - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); config_item_put(i); } @@ -677,7 +677,7 @@ int dlm_nodeid_list(char *lsname, int **ids_out) if (!sp) return -EEXIST; - down(&sp->members_lock); + mutex_lock(&sp->members_lock); if (!sp->members_count) { rv = 0; goto out; @@ -698,7 +698,7 @@ int dlm_nodeid_list(char *lsname, int **ids_out) *ids_out = ids; out: - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); put_space(sp); return rv; } @@ -713,14 +713,14 @@ int dlm_node_weight(char *lsname, int nodeid) if (!sp) goto out; - down(&sp->members_lock); + mutex_lock(&sp->members_lock); list_for_each_entry(nd, &sp->members, list) { if (nd->nodeid != nodeid) continue; w = nd->weight; break; } - up(&sp->members_lock); + mutex_unlock(&sp->members_lock); put_space(sp); out: return w; diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 98b49a1ece4..5080bbffd58 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -63,12 +63,12 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, /* FIXME: this warns on Alpha */ if (lkb->lkb_status == DLM_LKSTS_CONVERT || lkb->lkb_status == DLM_LKSTS_GRANTED) - seq_printf(s, " %" PRIx64 "-%" PRIx64, + 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, " (%" PRIx64 "-%" PRIx64 ")", + seq_printf(s, " (%llx-%llx)", lkb->lkb_range[RQ_RANGE_START], lkb->lkb_range[RQ_RANGE_END]); } diff --git a/fs/dlm/device.c b/fs/dlm/device.c index a8bf600ed13..899d4f92a4d 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -43,7 +43,7 @@ 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; +static struct mutex user_ls_lock; /* Lock infos are stored in here indexed by lock ID */ static DEFINE_IDR(lockinfo_idr); @@ -53,6 +53,7 @@ static rwlock_t lockinfo_lock; #define LI_FLAG_COMPLETE 1 #define LI_FLAG_FIRSTLOCK 2 #define LI_FLAG_PERSISTENT 3 +#define LI_FLAG_ONLIST 4 /* flags in ls_flags*/ #define LS_FLAG_DELETED 1 @@ -211,18 +212,18 @@ static struct user_ls *find_lockspace(int minor) { struct user_ls *lsinfo; - down(&user_ls_lock); + mutex_lock(&user_ls_lock); lsinfo = __find_lockspace(minor); - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); return lsinfo; } static void add_lockspace_to_list(struct user_ls *lsinfo) { - down(&user_ls_lock); + mutex_lock(&user_ls_lock); list_add(&lsinfo->ls_list, &user_ls_list); - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); } /* Register a lockspace with the DLM and create a misc @@ -235,12 +236,11 @@ static int register_lockspace(char *name, struct user_ls **ls, int flags) namelen = strlen(name)+strlen(name_prefix)+2; - newls = kmalloc(sizeof(struct user_ls), GFP_KERNEL); + newls = kzalloc(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); + newls->ls_miscinfo.name = kzalloc(namelen, GFP_KERNEL); if (!newls->ls_miscinfo.name) { kfree(newls); return -ENOMEM; @@ -277,7 +277,7 @@ static int register_lockspace(char *name, struct user_ls **ls, int flags) return 0; } -/* Called with the user_ls_lock semaphore held */ +/* Called with the user_ls_lock mutex held */ static int unregister_lockspace(struct user_ls *lsinfo, int force) { int status; @@ -305,11 +305,10 @@ static int unregister_lockspace(struct user_ls *lsinfo, int force) 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); + struct ast_info *ast = kzalloc(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; @@ -382,6 +381,7 @@ static void ast_routine(void *param) spin_lock(&li->li_file->fi_li_lock); list_del(&li->li_ownerqueue); + clear_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&li->li_file->fi_li_lock); release_lockinfo(li); return; @@ -437,7 +437,7 @@ static int dlm_open(struct inode *inode, struct file *file) if (!lsinfo) return -ENOENT; - f = kmalloc(sizeof(struct file_info), GFP_KERNEL); + f = kzalloc(sizeof(struct file_info), GFP_KERNEL); if (!f) return -ENOMEM; @@ -570,7 +570,7 @@ static int dlm_close(struct inode *inode, struct file *file) * then free the struct. If it's an AUTOFREE lockspace * then free the whole thing. */ - down(&user_ls_lock); + mutex_lock(&user_ls_lock); if (atomic_dec_and_test(&lsinfo->ls_refcnt)) { if (lsinfo->ls_lockspace) { @@ -582,7 +582,7 @@ static int dlm_close(struct inode *inode, struct file *file) kfree(lsinfo); } } - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); put_file_info(f); /* Restore signals */ @@ -620,10 +620,10 @@ static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - down(&user_ls_lock); + mutex_lock(&user_ls_lock); lsinfo = __find_lockspace(kparams->minor); if (!lsinfo) { - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); return -EINVAL; } @@ -631,7 +631,7 @@ static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, force = 2; status = unregister_lockspace(lsinfo, force); - up(&user_ls_lock); + mutex_unlock(&user_ls_lock); return status; } @@ -752,7 +752,7 @@ static struct lock_info *allocate_lockinfo(struct file_info *fi, uint8_t cmd, if (!try_module_get(THIS_MODULE)) return NULL; - li = kmalloc(sizeof(struct lock_info), GFP_KERNEL); + li = kzalloc(sizeof(struct lock_info), GFP_KERNEL); if (li) { li->li_magic = LOCKINFO_MAGIC; li->li_file = fi; @@ -800,8 +800,10 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, /* If this is a persistent lock we will have to create a lockinfo again */ - if (!li && DLM_LKF_PERSISTENT) { + if (!li && (kparams->flags & DLM_LKF_PERSISTENT)) { li = allocate_lockinfo(fi, cmd, kparams); + if (!li) + return -ENOMEM; li->li_lksb.sb_lkid = kparams->lkid; li->li_castaddr = kparams->castaddr; @@ -887,6 +889,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, spin_lock(&fi->fi_li_lock); list_add(&li->li_ownerqueue, &fi->fi_li_list); + set_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); if (add_lockinfo(li)) printk(KERN_WARNING "Add lockinfo failed\n"); @@ -914,12 +917,13 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, li = get_lockinfo(kparams->lkid); if (!li) { li = allocate_lockinfo(fi, cmd, kparams); + if (!li) + return -ENOMEM; spin_lock(&fi->fi_li_lock); list_add(&li->li_ownerqueue, &fi->fi_li_list); + set_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); } - if (!li) - return -ENOMEM; if (li->li_magic != LOCKINFO_MAGIC) return -EINVAL; @@ -932,6 +936,12 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, if (kparams->flags & DLM_LKF_CANCEL && li->li_grmode != -1) convert_cancel = 1; + /* Wait until dlm_lock() has completed */ + if (!test_bit(LI_FLAG_ONLIST, &li->li_flags)) { + down(&li->li_firstlock); + up(&li->li_firstlock); + } + /* 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 @@ -947,6 +957,7 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, if (!status && !convert_cancel) { spin_lock(&fi->fi_li_lock); list_del(&li->li_ownerqueue); + clear_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); } @@ -1055,7 +1066,7 @@ static int __init dlm_device_init(void) int r; INIT_LIST_HEAD(&user_ls_list); - init_MUTEX(&user_ls_lock); + mutex_init(&user_ls_lock); rwlock_init(&lockinfo_lock); ctl_device.name = "dlm-control"; diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c index 0f1dde54bcd..46754553fdc 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c @@ -33,7 +33,7 @@ static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de) static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) { - int found = FALSE; + int found = 0; struct dlm_direntry *de; spin_lock(&ls->ls_recover_list_lock); @@ -42,7 +42,7 @@ static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) list_del(&de->list); de->master_nodeid = 0; memset(de->name, 0, len); - found = TRUE; + found = 1; break; } } diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 0020cd07baf..16f20cfd919 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -42,20 +43,6 @@ #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? */ @@ -266,7 +253,7 @@ struct dlm_lkb { struct dlm_rsb { struct dlm_ls *res_ls; /* the lockspace */ struct kref res_ref; - struct semaphore res_sem; + struct mutex res_mutex; unsigned long res_flags; int res_length; /* length of rsb name */ int res_nodeid; @@ -449,7 +436,7 @@ struct dlm_ls { struct dlm_dirtable *ls_dirtbl; uint32_t ls_dirtbl_size; - struct semaphore ls_waiters_sem; + struct mutex ls_waiters_mutex; struct list_head ls_waiters; /* lkbs needing a reply */ struct list_head ls_nodes; /* current nodes in ls */ @@ -472,14 +459,14 @@ struct dlm_ls { struct timer_list ls_timer; struct task_struct *ls_recoverd_task; - struct semaphore ls_recoverd_active; + struct mutex 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; + struct mutex ls_requestqueue_mutex; char *ls_recover_buf; struct list_head ls_recover_list; spinlock_t ls_recover_list_lock; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 81efb361f95..29d3b95dbb6 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -215,15 +215,15 @@ 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; + return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0; } 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; + return 1; + return 0; } static inline int down_conversion(struct dlm_lkb *lkb) @@ -269,7 +269,7 @@ static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len) r->res_ls = ls; r->res_length = len; memcpy(r->res_name, name, len); - init_MUTEX(&r->res_sem); + mutex_init(&r->res_mutex); INIT_LIST_HEAD(&r->res_lookup); INIT_LIST_HEAD(&r->res_grantqueue); @@ -712,7 +712,7 @@ 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); + mutex_lock(&ls->ls_waiters_mutex); if (lkb->lkb_wait_type) { log_print("add_to_waiters error %d", lkb->lkb_wait_type); goto out; @@ -721,7 +721,7 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype) kref_get(&lkb->lkb_ref); list_add(&lkb->lkb_wait_reply, &ls->ls_waiters); out: - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); } static int _remove_from_waiters(struct dlm_lkb *lkb) @@ -745,9 +745,9 @@ 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); + mutex_lock(&ls->ls_waiters_mutex); error = _remove_from_waiters(lkb); - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); return error; } @@ -775,14 +775,14 @@ static int shrink_bucket(struct dlm_ls *ls, int b) int count = 0, found; for (;;) { - found = FALSE; + found = 0; 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; + found = 1; break; } @@ -1027,9 +1027,9 @@ 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 1; - return FALSE; + return 0; } /* Return 1 if the locks' ranges overlap. If the lkb has no range then it is @@ -1038,13 +1038,13 @@ static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) static inline int ranges_overlap(struct dlm_lkb *lkb1, struct dlm_lkb *lkb2) { if (!lkb1->lkb_range || !lkb2->lkb_range) - return TRUE; + 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 FALSE; + return 0; - return TRUE; + return 1; } /* Check if the given lkb conflicts with another lkb on the queue. */ @@ -1057,9 +1057,9 @@ static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) if (this == lkb) continue; if (ranges_overlap(lkb, this) && !modes_compat(this, lkb)) - return TRUE; + return 1; } - return FALSE; + return 0; } /* @@ -1103,7 +1103,7 @@ static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) continue; if (!modes_compat(this, lkb) && !modes_compat(lkb, this)) - return TRUE; + return 1; } /* if lkb is on the convert queue and is preventing the first @@ -1114,10 +1114,10 @@ static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) if (self && self != first) { if (!modes_compat(lkb, first) && !queue_conflict(&rsb->res_grantqueue, first)) - return TRUE; + return 1; } - return FALSE; + return 0; } /* @@ -1157,7 +1157,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (lkb->lkb_exflags & DLM_LKF_EXPEDITE) - return TRUE; + return 1; /* * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be @@ -1200,7 +1200,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT)) - return TRUE; + return 1; /* * When using range locks the NOORDER flag is set to avoid the standard @@ -1208,7 +1208,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (lkb->lkb_exflags & DLM_LKF_NOORDER) - return TRUE; + return 1; /* * 6-3: Once in that queue [CONVERTING], a conversion request cannot be @@ -1217,7 +1217,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) */ if (!now && conv && first_in_list(lkb, &r->res_convertqueue)) - return TRUE; + return 1; /* * 6-4: By default, a new request is immediately granted only if all @@ -1232,7 +1232,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) if (now && !conv && list_empty(&r->res_convertqueue) && list_empty(&r->res_waitqueue)) - return TRUE; + return 1; /* * 6-4: Once a lock request is in the queue of ungranted new requests, @@ -1244,7 +1244,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) if (!now && !conv && list_empty(&r->res_convertqueue) && first_in_list(lkb, &r->res_waitqueue)) - return TRUE; + return 1; out: /* @@ -1257,7 +1257,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) lkb->lkb_sbflags |= DLM_SBF_DEMOTED; } - return FALSE; + return 0; } /* @@ -1308,7 +1308,7 @@ static int grant_pending_convert(struct dlm_rsb *r, int high) list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) { demoted = is_demoted(lkb); - if (can_be_granted(r, lkb, FALSE)) { + if (can_be_granted(r, lkb, 0)) { grant_lock_pending(r, lkb); grant_restart = 1; } else { @@ -1333,7 +1333,7 @@ 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)) + if (can_be_granted(r, lkb, 0)) grant_lock_pending(r, lkb); else high = max_t(int, lkb->lkb_rqmode, high); @@ -1705,7 +1705,7 @@ static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb) { int error = 0; - if (can_be_granted(r, lkb, TRUE)) { + if (can_be_granted(r, lkb, 1)) { grant_lock(r, lkb); queue_cast(r, lkb, 0); goto out; @@ -1733,7 +1733,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) /* changing an existing lock may allow others to be granted */ - if (can_be_granted(r, lkb, TRUE)) { + if (can_be_granted(r, lkb, 1)) { grant_lock(r, lkb); queue_cast(r, lkb, 0); grant_pending_locks(r); @@ -2556,7 +2556,7 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms) { struct dlm_lkb *lkb; struct dlm_rsb *r; - int error, reply = TRUE; + int error, reply = 1; error = find_lkb(ls, ms->m_remid, &lkb); if (error) @@ -3205,7 +3205,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) { struct dlm_lkb *lkb, *safe; - down(&ls->ls_waiters_sem); + mutex_lock(&ls->ls_waiters_mutex); 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", @@ -3253,7 +3253,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) lkb->lkb_wait_type); } } - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); } static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) @@ -3261,7 +3261,7 @@ 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); + mutex_lock(&ls->ls_waiters_mutex); list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { if (lkb->lkb_flags & DLM_IFL_RESEND) { rv = lkb->lkb_wait_type; @@ -3270,7 +3270,7 @@ static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) break; } } - up(&ls->ls_waiters_sem); + mutex_unlock(&ls->ls_waiters_mutex); if (!rv) lkb = NULL; diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 9e6499f773d..bffab9c88b1 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -38,12 +38,12 @@ static inline int is_master(struct dlm_rsb *r) static inline void lock_rsb(struct dlm_rsb *r) { - down(&r->res_sem); + mutex_lock(&r->res_mutex); } static inline void unlock_rsb(struct dlm_rsb *r) { - up(&r->res_sem); + mutex_unlock(&r->res_mutex); } #endif diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index fee4659b658..d2ff505d51c 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -31,7 +31,7 @@ static inline void dlm_delete_debug_file(struct dlm_ls *ls) { } #endif static int ls_count; -static struct semaphore ls_lock; +static struct mutex ls_lock; static struct list_head lslist; static spinlock_t lslist_lock; static struct task_struct * scand_task; @@ -177,7 +177,7 @@ int dlm_lockspace_init(void) int error; ls_count = 0; - init_MUTEX(&ls_lock); + mutex_init(&ls_lock); INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); @@ -351,10 +351,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, return -EEXIST; } - ls = kmalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); + ls = kzalloc(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; @@ -398,7 +397,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, } INIT_LIST_HEAD(&ls->ls_waiters); - init_MUTEX(&ls->ls_waiters_sem); + mutex_init(&ls->ls_waiters_mutex); INIT_LIST_HEAD(&ls->ls_nodes); INIT_LIST_HEAD(&ls->ls_nodes_gone); @@ -416,14 +415,14 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_uevent_result = 0; ls->ls_recoverd_task = NULL; - init_MUTEX(&ls->ls_recoverd_active); + mutex_init(&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); + mutex_init(&ls->ls_requestqueue_mutex); ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL); if (!ls->ls_recover_buf) @@ -493,7 +492,7 @@ int dlm_new_lockspace(char *name, int namelen, void **lockspace, { int error = 0; - down(&ls_lock); + mutex_lock(&ls_lock); if (!ls_count) error = threads_start(); if (error) @@ -503,7 +502,7 @@ int dlm_new_lockspace(char *name, int namelen, void **lockspace, if (!error) ls_count++; out: - up(&ls_lock); + mutex_unlock(&ls_lock); return error; } @@ -629,11 +628,11 @@ static int release_lockspace(struct dlm_ls *ls, int force) kobject_unregister(&ls->ls_kobj); kfree(ls); - down(&ls_lock); + mutex_lock(&ls_lock); ls_count--; if (!ls_count) threads_stop(); - up(&ls_lock); + mutex_unlock(&ls_lock); module_put(THIS_MODULE); return 0; diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 439249b62a5..926cd0cb6bf 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -52,7 +52,7 @@ 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); + memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL); if (!memb) return -ENOMEM; @@ -79,9 +79,9 @@ static int dlm_is_member(struct dlm_ls *ls, int nodeid) list_for_each_entry(memb, &ls->ls_nodes, list) { if (memb->nodeid == nodeid) - return TRUE; + return 1; } - return FALSE; + return 0; } int dlm_is_removed(struct dlm_ls *ls, int nodeid) @@ -90,9 +90,9 @@ int dlm_is_removed(struct dlm_ls *ls, int nodeid) list_for_each_entry(memb, &ls->ls_nodes_gone, list) { if (memb->nodeid == nodeid) - return TRUE; + return 1; } - return FALSE; + return 0; } static void clear_memb_list(struct list_head *head) @@ -178,10 +178,10 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) /* move departed members from ls_nodes to ls_nodes_gone */ list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { - found = FALSE; + found = 0; for (i = 0; i < rv->node_count; i++) { if (memb->nodeid == rv->nodeids[i]) { - found = TRUE; + found = 1; break; } } @@ -271,10 +271,9 @@ int dlm_ls_start(struct dlm_ls *ls) int *ids = NULL; int error, count; - rv = kmalloc(sizeof(struct dlm_recover), GFP_KERNEL); + rv = kzalloc(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) diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index d96f9bbb407..c9b1c3d535f 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -119,7 +119,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, switch (msg->h_cmd) { case DLM_MSG: - dlm_receive_message(msg, nodeid, FALSE); + dlm_receive_message(msg, nodeid, 0); break; case DLM_RCOM: diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index 1712c97bc22..b036ee7dcb3 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -420,7 +420,7 @@ int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc) r = recover_list_find(ls, rc->rc_id); if (!r) { - log_error(ls, "dlm_recover_master_reply no id %"PRIx64"", + log_error(ls, "dlm_recover_master_reply no id %llx", rc->rc_id); goto out; } @@ -477,8 +477,8 @@ 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; + return 0; + return 1; } static int recover_locks(struct dlm_rsb *r) @@ -586,18 +586,18 @@ 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 lock_lvb_exists = 0; + int big_lock_exists = 0; 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; + lock_lvb_exists = 1; if (lkb->lkb_grmode > DLM_LOCK_CR) { - big_lock_exists = TRUE; + big_lock_exists = 1; goto setflag; } @@ -611,10 +611,10 @@ static void recover_lvb(struct dlm_rsb *r) if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) continue; - lock_lvb_exists = TRUE; + lock_lvb_exists = 1; if (lkb->lkb_grmode > DLM_LOCK_CR) { - big_lock_exists = TRUE; + big_lock_exists = 1; goto setflag; } diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 06e4f7cab6e..70103533677 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -45,9 +45,9 @@ 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); + log_debug(ls, "recover %llx", rv->seq); - down(&ls->ls_recoverd_active); + mutex_lock(&ls->ls_recoverd_active); /* * Suspending and resuming dlm_astd ensures that no lkb's from this ls @@ -199,16 +199,16 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) dlm_astd_wake(); - log_debug(ls, "recover %"PRIx64" done: %u ms", rv->seq, + log_debug(ls, "recover %llx done: %u ms", rv->seq, jiffies_to_msecs(jiffies - start)); - up(&ls->ls_recoverd_active); + mutex_unlock(&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); + log_debug(ls, "recover %llx error %d", rv->seq, error); + mutex_unlock(&ls->ls_recoverd_active); return error; } @@ -275,11 +275,11 @@ void dlm_recoverd_stop(struct dlm_ls *ls) void dlm_recoverd_suspend(struct dlm_ls *ls) { - down(&ls->ls_recoverd_active); + mutex_lock(&ls->ls_recoverd_active); } void dlm_recoverd_resume(struct dlm_ls *ls) { - up(&ls->ls_recoverd_active); + mutex_unlock(&ls->ls_recoverd_active); } diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index 36afe99e4f9..7b2b089634a 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c @@ -47,9 +47,9 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) e->nodeid = nodeid; memcpy(e->request, hd, length); - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); list_add_tail(&e->list, &ls->ls_requestqueue); - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); } int dlm_process_requestqueue(struct dlm_ls *ls) @@ -58,19 +58,19 @@ int dlm_process_requestqueue(struct dlm_ls *ls) struct dlm_header *hd; int error = 0; - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); for (;;) { if (list_empty(&ls->ls_requestqueue)) { - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); error = 0; break; } e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list); - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); hd = (struct dlm_header *) e->request; - error = dlm_receive_message(hd, e->nodeid, TRUE); + error = dlm_receive_message(hd, e->nodeid, 1); if (error == -EINTR) { /* entry is left on requestqueue */ @@ -78,13 +78,13 @@ int dlm_process_requestqueue(struct dlm_ls *ls) break; } - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); list_del(&e->list); kfree(e); if (dlm_locking_stopped(ls)) { log_debug(ls, "process_requestqueue abort running"); - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); error = -EINTR; break; } @@ -105,15 +105,15 @@ int dlm_process_requestqueue(struct dlm_ls *ls) void dlm_wait_requestqueue(struct dlm_ls *ls) { for (;;) { - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); if (list_empty(&ls->ls_requestqueue)) break; if (dlm_locking_stopped(ls)) break; - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); schedule(); } - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); } static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid) @@ -170,7 +170,7 @@ void dlm_purge_requestqueue(struct dlm_ls *ls) struct dlm_message *ms; struct rq_entry *e, *safe; - down(&ls->ls_requestqueue_lock); + mutex_lock(&ls->ls_requestqueue_mutex); list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) { ms = (struct dlm_message *) e->request; @@ -179,6 +179,6 @@ void dlm_purge_requestqueue(struct dlm_ls *ls) kfree(e); } } - up(&ls->ls_requestqueue_lock); + mutex_unlock(&ls->ls_requestqueue_mutex); } -- GitLab From 8ca05c60de49c3bb523a435abc216b6b6eeb1067 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 24 Jan 2006 10:03:04 +0000 Subject: [PATCH 0023/1619] [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(-) diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index aa7ba00ec08..7d5ce496f39 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 ca963286283..fb7c0cf72c5 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__ */ -- GitLab From aa6a85a971065b013a71a399c3fc4312e2dd81eb Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 24 Jan 2006 10:37:06 +0000 Subject: [PATCH 0024/1619] [GFS2] Remove pointless argument relating to truncate For some reason a function pointer was being passed through the truncate code which only ever took one value. This removes the function pointer and replaces it with a single call to the function in question. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 15 ++++++--------- fs/gfs2/bmap.h | 3 +-- fs/gfs2/ops_inode.c | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 967cbc68195..ff4a9175b4e 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -841,8 +841,7 @@ static int truncator_journaled(struct gfs2_inode *ip, uint64_t size) return 0; } -static int trunc_start(struct gfs2_inode *ip, uint64_t size, - gfs2_truncator_t truncator) +static int trunc_start(struct gfs2_inode *ip, uint64_t size) { struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head *dibh; @@ -873,7 +872,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size, 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); + error = gfs2_truncator_page(ip, size); if (!error) { ip->i_di.di_size = size; @@ -980,12 +979,11 @@ static int trunc_end(struct gfs2_inode *ip) * Returns: errno */ -static int do_shrink(struct gfs2_inode *ip, uint64_t size, - gfs2_truncator_t truncator) +static int do_shrink(struct gfs2_inode *ip, uint64_t size) { int error; - error = trunc_start(ip, size, truncator); + error = trunc_start(ip, size); if (error < 0) return error; if (error > 0) @@ -1009,8 +1007,7 @@ static int do_shrink(struct gfs2_inode *ip, uint64_t size, * Returns: errno */ -int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size, - gfs2_truncator_t truncator) +int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size) { int error; @@ -1020,7 +1017,7 @@ int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size, if (size > ip->i_di.di_size) error = do_grow(ip, size); else - error = do_shrink(ip, size, truncator); + error = do_shrink(ip, size); return error; } diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 25ea32905c6..b83b5924828 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -23,8 +23,7 @@ int gfs2_block_map(struct gfs2_inode *ip, 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(struct gfs2_inode *ip, uint64_t size); int gfs2_truncatei_resume(struct gfs2_inode *ip); int gfs2_file_dealloc(struct gfs2_inode *ip); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 89417a6cb72..6fff30ef8b7 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -994,7 +994,7 @@ static int setattr_size(struct inode *inode, struct iattr *attr) return error; } - error = gfs2_truncatei(ip, attr->ia_size, gfs2_truncator_page); + error = gfs2_truncatei(ip, attr->ia_size); if (error) return error; -- GitLab From b381beadee8a3d6e690d30bdccddd08ab024945e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 08:47:14 +0000 Subject: [PATCH 0025/1619] [GFS2] Remove unused file resize.c The code in this file is no longer used as the rindex file is now accessible to userspace, so can be read/written directly. Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 1 - fs/gfs2/resize.c | 291 ----------------------------------------------- fs/gfs2/resize.h | 19 ---- 3 files changed, 311 deletions(-) delete mode 100644 fs/gfs2/resize.c delete mode 100644 fs/gfs2/resize.h diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 974c76d0c6f..4e87b8661af 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -30,7 +30,6 @@ gfs2-y := \ ops_vm.o \ page.o \ quota.o \ - resize.o \ recovery.o \ rgrp.o \ super.o \ diff --git a/fs/gfs2/resize.c b/fs/gfs2/resize.c deleted file mode 100644 index a5309668250..00000000000 --- a/fs/gfs2/resize.c +++ /dev/null @@ -1,291 +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 "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, 1); - 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 deleted file mode 100644 index bb97f050159..00000000000 --- a/fs/gfs2/resize.h +++ /dev/null @@ -1,19 +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 __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__ */ -- GitLab From d41cc702cc4ba3782ebe3b2e189633607d5ccd6a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 08:53:33 +0000 Subject: [PATCH 0026/1619] [GFS2] Export file_ra_state_init Export file_ra_state_init so that its possible to use the already exported functions which require a struct ra_state as an argument from a module. Signed-off-by: Steven Whitehouse --- mm/readahead.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/readahead.c b/mm/readahead.c index 8d6eeaaa629..9f0b98227b4 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -38,6 +38,7 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping) ra->ra_pages = mapping->backing_dev_info->ra_pages; ra->prev_page = -1; } +EXPORT_SYMBOL_GPL(file_ra_state_init); /* * Return max readahead size for this inode in number-of-pages. -- GitLab From c25ec8f5684cb3c5dde6a67c1bbc33a449eefbe2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 08:57:31 +0000 Subject: [PATCH 0027/1619] [GFS2] Export file_read_actor Export file_read_actor so that it can be used from modules since functions which take this function as an argument are already exported. Signed-off-by: Steven Whitehouse --- mm/filemap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/filemap.c b/mm/filemap.c index 44da3d47699..7624c26fcea 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -981,6 +981,7 @@ success: desc->arg.buf += size; return size; } +EXPORT_SYMBOL(file_read_actor); /* * This is the "read()" routine for all filesystems -- GitLab From 4ff14670ee2a8229381ff295eaae84aa51beff43 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 09:39:10 +0000 Subject: [PATCH 0028/1619] [GFS2] Rename get_block and make it extern This renames get_block to gfs2_get_block and makes it accessible from outside ops_address.c. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 14 +++++++------- fs/gfs2/ops_address.h | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index db66d328755..a7fbfa0bbaf 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -28,7 +28,7 @@ #include "trans.h" /** - * get_block - Fills in a buffer head with details about a block + * gfs2_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 @@ -37,8 +37,8 @@ * Returns: errno */ -static int get_block(struct inode *inode, sector_t lblock, - struct buffer_head *bh_result, int create) +int gfs2_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; @@ -286,7 +286,7 @@ static int gfs2_readpage(struct file *file, struct page *page) } else error = zero_readpage(page); } else - error = block_read_full_page(page, get_block); + error = block_read_full_page(page, gfs2_get_block); } else error = jdata_readpage(ip, page); @@ -328,11 +328,11 @@ static int gfs2_prepare_write(struct file *file, struct page *page, page); if (!error) error = block_prepare_write(page, from, to, - get_block); + gfs2_get_block); } else if (!PageUptodate(page)) error = stuffed_readpage(ip, page); } else - error = block_prepare_write(page, from, to, get_block); + error = block_prepare_write(page, from, to, gfs2_get_block); return error; } @@ -420,7 +420,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) return 0; if (!gfs2_is_stuffed(ip)) - dblock = generic_block_bmap(mapping, lblock, get_block); + dblock = generic_block_bmap(mapping, lblock, gfs2_get_block); gfs2_glock_dq_uninit(&i_gh); diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index ced9ea0fdd3..f201a059fd9 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -11,5 +11,7 @@ #define __OPS_ADDRESS_DOT_H__ extern 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); #endif /* __OPS_ADDRESS_DOT_H__ */ -- GitLab From 2442a098be6b38ee3abe8edda3224b48ff4d604a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 11:49:32 +0000 Subject: [PATCH 0029/1619] [GFS2] Bug fix relating to endian conversion in inode.c A two line fix to get endian conversion correct. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9ed7c054106..e4ba380b286 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1002,7 +1002,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); di = (struct gfs2_dinode *)dibh->b_data; - di->di_num = *inum; + di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino); + di->di_num.no_addr = cpu_to_be64(inum->no_addr); di->di_mode = cpu_to_be32(mode); di->di_uid = cpu_to_be32(uid); di->di_gid = cpu_to_be32(gid); -- GitLab From 9b124fbb8ddb3d0b17f5a807414d85cbaf527a56 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 11:55:32 +0000 Subject: [PATCH 0030/1619] [GFS2] Use mpage_readpage() in gfs2_readpage() Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index a7fbfa0bbaf..da5a0b44518 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -286,7 +287,7 @@ static int gfs2_readpage(struct file *file, struct page *page) } else error = zero_readpage(page); } else - error = block_read_full_page(page, gfs2_get_block); + error = mpage_readpage(page, gfs2_get_block); } else error = jdata_readpage(ip, page); -- GitLab From e13940ba56157a663944f2a827be96b6b787e260 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 13:31:50 +0000 Subject: [PATCH 0031/1619] [GFS2] Make dir.c independant of jdata.c Copy & rename various jdata functions into dir.c. The plan being that directory metadata format will not change although the journalled data format for "normal" files will change. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 255 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 93d3704ac58..ada283a0f5f 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -65,11 +65,11 @@ #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" +#include "bmap.h" #define IS_LEAF 1 /* Hashed (leaf) directory */ #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ @@ -86,6 +86,252 @@ 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) +{ + 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; +} + + + +static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, + unsigned int offset, unsigned int size) + +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + memcpy(dibh->b_data + offset + sizeof(struct gfs2_inode), 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(); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + + brelse(dibh); + + return size; +} + + + +/** + * gfs2_dir_write_data - Write directory information to the inode + * @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 + * + * Returns: The number of bytes correctly written or error code + */ +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 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 gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset, size); + + 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_dir_get_buffer(ip, dblock, (amount == sdp->sd_jbsize) ? 1 : new, &bh); + if (error) + goto fail; + + gfs2_trans_add_bh(ip->i_gl, bh, 1); + memcpy(bh->b_data + o, buf, 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; +} + +static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, + unsigned int offset, unsigned int size) +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + offset += sizeof(struct gfs2_dinode); + memcpy(buf, dibh->b_data + offset, size); + brelse(dibh); + } + + return (error) ? error : size; +} + + +/** + * gfs2_dir_read_data - Read a data from a directory inode + * @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 + * + * Returns: The amount of data actually copied or the error + */ +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; + 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 gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset, size); + + 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_dir_get_buffer(ip, dblock, new, &bh); + if (error) + goto fail; + dblock++; + extlen--; + } else + bh = NULL; + + memcpy(buf, bh->b_data + o, amount); + brelse(bh); + if (error) + goto fail; + + copied += amount; + lblock++; + + o = sizeof(struct gfs2_meta_header); + } + + return copied; +fail: + return (copied) ? copied : error; +} + /** * int gfs2_filecmp - Compare two filenames * @file1: The first filename @@ -428,7 +674,7 @@ static int get_leaf_nr(struct gfs2_inode *dip, uint32_t index, uint64_t leaf_no; int error; - error = gfs2_jdata_read_mem(dip, (char *)&leaf_no, + error = gfs2_dir_read_data(dip, (char *)&leaf_no, index * sizeof(uint64_t), sizeof(uint64_t)); if (error != sizeof(uint64_t)) @@ -683,7 +929,7 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, lp = kcalloc(half_len, sizeof(uint64_t), GFP_KERNEL | __GFP_NOFAIL); - error = gfs2_jdata_read_mem(dip, (char *)lp, start * sizeof(uint64_t), + 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) @@ -696,7 +942,7 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, 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), + error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), half_len * sizeof(uint64_t)); if (error != half_len * sizeof(uint64_t)) { if (error >= 0) @@ -816,7 +1062,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) 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, + error = gfs2_dir_read_data(dip, (char *)buf, block * sdp->sd_hash_bsize, sdp->sd_hash_bsize); if (error != sdp->sd_hash_bsize) { @@ -833,7 +1079,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) *to++ = *from; } - error = gfs2_jdata_write_mem(dip, + error = gfs2_dir_write_data(dip, (char *)buf + sdp->sd_hash_bsize, block * sdp->sd_sb.sb_bsize, sdp->sd_sb.sb_bsize); @@ -1424,7 +1670,7 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, ht_offset = index - lp_offset; if (ht_offset_cur != ht_offset) { - error = gfs2_jdata_read_mem(dip, (char *)lp, + error = gfs2_dir_read_data(dip, (char *)lp, ht_offset * sizeof(uint64_t), sdp->sd_hash_bsize); if (error != sdp->sd_hash_bsize) { @@ -1839,7 +2085,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) ht_offset = index - lp_offset; if (ht_offset_cur != ht_offset) { - error = gfs2_jdata_read_mem(dip, (char *)lp, + error = gfs2_dir_read_data(dip, (char *)lp, ht_offset * sizeof(uint64_t), sdp->sd_hash_bsize); if (error != sdp->sd_hash_bsize) { @@ -1965,7 +2211,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, dip->i_di.di_blocks--; } - error = gfs2_jdata_write_mem(dip, ht, index * sizeof(uint64_t), size); + error = gfs2_dir_write_data(dip, ht, index * sizeof(uint64_t), size); if (error != size) { if (error >= 0) error = -EIO; -- GitLab From fd2ee6bb1ef02dfe1f1e1f5b44322e0854596e9a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 13:36:53 +0000 Subject: [PATCH 0032/1619] [GFS2] Remove unused prototype Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index b83b5924828..ee9ec8d7515 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -22,7 +22,6 @@ 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); int gfs2_truncatei_resume(struct gfs2_inode *ip); int gfs2_file_dealloc(struct gfs2_inode *ip); -- GitLab From f42faf4fa4eaf7e108dd60f3f2ca5c6e9b45352c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 30 Jan 2006 18:34:10 +0000 Subject: [PATCH 0033/1619] [GFS2] Add gfs2_internal_read() Add the new external read function. Its temporarily in jdata.c even though the protoype is in ops_file.h - this will change shortly. The current implementation will change to a page cache one when that happens. In order to effect the above changes, the various internal inodes now have Linux inodes attached to them. We keep the references to the Linux inodes, rather than the gfs2_inodes in the super block. In order to get everything to work correctly I've had to reorder the init sequence on mount (which I should probably have done earlier when .gfs2_admin was made visible). Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 29 ++++--- fs/gfs2/inode.c | 10 +-- fs/gfs2/inode.h | 15 +++- fs/gfs2/jdata.c | 7 ++ fs/gfs2/ops_export.c | 2 +- fs/gfs2/ops_file.h | 4 + fs/gfs2/ops_fstype.c | 184 ++++++++++++++++++++++--------------------- fs/gfs2/ops_super.c | 22 +++--- fs/gfs2/quota.c | 27 ++++--- fs/gfs2/rgrp.c | 13 +-- fs/gfs2/super.c | 19 ++--- fs/gfs2/unlinked.c | 4 +- 12 files changed, 187 insertions(+), 149 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 3bc40ff5fdf..d1954e2bb90 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -98,10 +98,13 @@ struct gfs2_rgrpd { enum gfs2_state_bits { BH_Pinned = BH_PrivateStart, + BH_Escaped = BH_PrivateStart + 1, }; BUFFER_FNS(Pinned, pinned) TAS_BUFFER_FNS(Pinned, pinned) +BUFFER_FNS(Escaped, escaped) +TAS_BUFFER_FNS(Escaped, escaped) struct gfs2_bufdata { struct buffer_head *bd_bh; @@ -254,7 +257,7 @@ struct gfs2_inode { struct inode *i_vnode; struct gfs2_holder i_iopen_gh; - + struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_alloc i_alloc; uint64_t i_last_rg_alloc; @@ -511,17 +514,17 @@ struct gfs2_sbd { /* 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; + struct inode *sd_master_dir; + struct inode *sd_jindex; + struct inode *sd_inum_inode; + 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; + struct inode *sd_root_dir; /* Inum stuff */ @@ -615,6 +618,8 @@ struct gfs2_sbd { unsigned int sd_log_num_revoke; unsigned int sd_log_num_rg; unsigned int sd_log_num_databuf; + unsigned int sd_log_num_jdata; + struct list_head sd_log_le_gl; struct list_head sd_log_le_buf; struct list_head sd_log_le_revoke; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index e4ba380b286..4c193e38f8e 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -725,7 +725,7 @@ int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root, return -ENAMETOOLONG; if (gfs2_filecmp(name, ".", 1) || - (gfs2_filecmp(name, "..", 2) && dip == sdp->sd_root_dir)) { + (gfs2_filecmp(name, "..", 2) && dip == get_v2ip(sdp->sd_root_dir))) { gfs2_inode_hold(dip); *ipp = dip; return 0; @@ -764,7 +764,7 @@ int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root, static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) { - struct gfs2_inode *ip = sdp->sd_ir_inode; + struct gfs2_inode *ip = get_v2ip(sdp->sd_ir_inode); struct buffer_head *bh; struct gfs2_inum_range ir; int error; @@ -805,8 +805,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; - struct gfs2_inode *m_ip = sdp->sd_inum_inode; + struct gfs2_inode *ip = get_v2ip(sdp->sd_ir_inode); + struct gfs2_inode *m_ip = get_v2ip(sdp->sd_inum_inode); struct gfs2_holder gh; struct buffer_head *bh; struct gfs2_inum_range ir; @@ -1460,7 +1460,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) error = -EINVAL; break; } - if (to == sdp->sd_root_dir) { + if (to == get_v2ip(sdp->sd_root_dir)) { error = 0; break; } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 4df7da51f71..e42ae38d677 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -60,14 +60,23 @@ 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) +static inline int gfs2_lookup_simple(struct inode *dip, char *name, + struct inode **ipp) { + struct gfs2_inode *ip; struct qstr qstr; + int err; memset(&qstr, 0, sizeof(struct qstr)); qstr.name = name; qstr.len = strlen(name); - return gfs2_lookupi(dip, &qstr, 1, ipp); + err = gfs2_lookupi(get_v2ip(dip), &qstr, 1, &ip); + if (err == 0) { + *ipp = gfs2_ip2v(ip); + if (*ipp == NULL) + err = -ENOMEM; + gfs2_inode_put(ip); + } + return err; } #endif /* __INODE_DOT_H__ */ diff --git a/fs/gfs2/jdata.c b/fs/gfs2/jdata.c index 6caa93e46ce..e43eaf133f1 100644 --- a/fs/gfs2/jdata.c +++ b/fs/gfs2/jdata.c @@ -22,6 +22,13 @@ #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) { diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 0ae3a0af192..335448d3be2 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -81,7 +81,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[3] = cpu_to_be32(fh[3]); *len = 4; - if (!connectable || ip == sdp->sd_root_dir) + if (!connectable || ip == get_v2ip(sdp->sd_root_dir)) return *len; spin_lock(&dentry->d_lock); diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index 95123d7bbcd..3c237bfc143 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -10,6 +10,10 @@ #ifndef __OPS_FILE_DOT_H__ #define __OPS_FILE_DOT_H__ +extern int gfs2_internal_read(struct gfs2_inode *ip, + struct file_ra_state *ra_state, + char *buf, loff_t *pos, unsigned size); + extern struct file_operations gfs2_file_fops; extern struct file_operations gfs2_dir_fops; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c61a80c439a..139cef8fff3 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -275,14 +275,38 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, return error; } +int gfs2_lookup_root(struct gfs2_sbd *sdp) +{ + int error; + struct gfs2_glock *gl; + struct gfs2_inode *ip; + + 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, &ip); + if (!error) { + if (!error) + gfs2_inode_min_init(ip, DT_DIR); + sdp->sd_root_dir = gfs2_ip2v(ip); + gfs2_inode_put(ip); + } + gfs2_glock_put(gl); + } + + 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; + struct inode *inode; int error = 0; if (undo) { - gfs2_inode_put(sdp->sd_master_dir); + iput(sdp->sd_master_dir); return 0; } @@ -321,14 +345,35 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) 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); + /* Get the root inode */ + error = gfs2_lookup_root(sdp); + if (error) { + fs_err(sdp, "can't read in root inode: %d\n", error); + goto out; + } - out: + /* Get the root inode/dentry */ + inode = sdp->sd_root_dir; + if (!inode) { + fs_err(sdp, "can't get root inode\n"); + error = -ENOMEM; + goto out_rooti; + } + + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) { + fs_err(sdp, "can't get root dentry\n"); + error = -ENOMEM; + goto out_rooti; + } + +out: gfs2_glock_dq_uninit(&sb_gh); return error; +out_rooti: + iput(sdp->sd_root_dir); + goto out; } static int init_journal(struct gfs2_sbd *sdp, int undo) @@ -349,7 +394,7 @@ 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, &sdp->sd_jindex->i_gl->gl_flags); + set_bit(GLF_STICKY, &get_v2ip(sdp->sd_jindex)->i_gl->gl_flags); /* Load in the journal index special file */ @@ -465,53 +510,44 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) gfs2_glock_dq_uninit(&ji_gh); fail: - gfs2_inode_put(sdp->sd_jindex); + iput(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; + goto fail_qinode; + + error = gfs2_lookup_master_dir(sdp); + if (error) { + fs_err(sdp, "can't read in master directory: %d\n", error); + goto fail; + } + + error = init_journal(sdp, undo); + if (error) + 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) { fs_err(sdp, "can't read in inum inode: %d\n", error); - return 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) { fs_err(sdp, "can't read in statfs inode: %d\n", error); - goto fail; + goto fail_inum; } /* Read in the resource index inode */ @@ -521,8 +557,8 @@ 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, &sdp->sd_rindex->i_gl->gl_flags); - sdp->sd_rindex_vn = sdp->sd_rindex->i_gl->gl_vn - 1; + 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; /* Read in the quota inode */ error = gfs2_lookup_simple(sdp->sd_master_dir, "quota", @@ -531,58 +567,31 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) 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_qinode: + iput(sdp->sd_quota_inode); - fail_rooti: - gfs2_inode_put(sdp->sd_root_dir); - - fail_qinode: - gfs2_inode_put(sdp->sd_quota_inode); - - fail_rindex: +fail_rindex: gfs2_clear_rgrpd(sdp); - gfs2_inode_put(sdp->sd_rindex); - - fail_statfs: - gfs2_inode_put(sdp->sd_statfs_inode); + iput(sdp->sd_rindex); - fail: - gfs2_inode_put(sdp->sd_inum_inode); +fail_statfs: + iput(sdp->sd_statfs_inode); +fail_inum: + iput(sdp->sd_inum_inode); +fail_journal: + init_journal(sdp, UNDO); +fail_master: + iput(sdp->sd_master_dir); +fail: return error; } static int init_per_node(struct gfs2_sbd *sdp, int undo) { - struct gfs2_inode *pn = NULL; + struct inode *pn = NULL; char buf[30]; int error = 0; @@ -626,10 +635,10 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_ut_i; } - gfs2_inode_put(pn); + iput(pn); pn = NULL; - error = gfs2_glock_nq_init(sdp->sd_ir_inode->i_gl, + error = gfs2_glock_nq_init(get_v2ip(sdp->sd_ir_inode)->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_ir_gh); if (error) { @@ -637,7 +646,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_qc_i; } - error = gfs2_glock_nq_init(sdp->sd_sc_inode->i_gl, + error = gfs2_glock_nq_init(get_v2ip(sdp->sd_sc_inode)->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_sc_gh); if (error) { @@ -645,7 +654,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_ir_gh; } - error = gfs2_glock_nq_init(sdp->sd_ut_inode->i_gl, + error = gfs2_glock_nq_init(get_v2ip(sdp->sd_ut_inode)->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_ut_gh); if (error) { @@ -653,7 +662,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_sc_gh; } - error = gfs2_glock_nq_init(sdp->sd_qc_inode->i_gl, + error = gfs2_glock_nq_init(get_v2ip(sdp->sd_qc_inode)->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_qc_gh); if (error) { @@ -676,20 +685,20 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) gfs2_glock_dq_uninit(&sdp->sd_ir_gh); fail_qc_i: - gfs2_inode_put(sdp->sd_qc_inode); + iput(sdp->sd_qc_inode); fail_ut_i: - gfs2_inode_put(sdp->sd_ut_inode); + iput(sdp->sd_ut_inode); fail_sc_i: - gfs2_inode_put(sdp->sd_sc_inode); + iput(sdp->sd_sc_inode); fail_ir_i: - gfs2_inode_put(sdp->sd_ir_inode); + iput(sdp->sd_ir_inode); fail: if (pn) - gfs2_inode_put(pn); + iput(pn); return error; } @@ -793,14 +802,10 @@ static int fill_super(struct super_block *sb, void *data, int silent) 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; + goto fail_sb; error = init_per_node(sdp, DO); if (error) @@ -837,9 +842,6 @@ static int fill_super(struct super_block *sb, void *data, int silent) fail_inodes: init_inodes(sdp, UNDO); - fail_journals: - init_journal(sdp, UNDO); - fail_sb: init_sb(sdp, 0, UNDO); diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index ca6a4d81bc2..e06ef8dbd4d 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -97,13 +97,13 @@ static void gfs2_put_super(struct super_block *sb) /* 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); + iput(sdp->sd_master_dir); + iput(sdp->sd_jindex); + iput(sdp->sd_inum_inode); + iput(sdp->sd_statfs_inode); + iput(sdp->sd_rindex); + iput(sdp->sd_quota_inode); + iput(sdp->sd_root_dir); gfs2_glock_put(sdp->sd_rename_gl); gfs2_glock_put(sdp->sd_trans_gl); @@ -115,10 +115,10 @@ static void gfs2_put_super(struct super_block *sb) 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); + iput(sdp->sd_ir_inode); + iput(sdp->sd_sc_inode); + iput(sdp->sd_ut_inode); + iput(sdp->sd_qc_inode); } gfs2_glock_dq_uninit(&sdp->sd_live_gh); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 5fb5a5305e0..69e8f4e92e5 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -56,6 +56,7 @@ #include "rgrp.h" #include "super.h" #include "trans.h" +#include "ops_file.h" #define QUOTA_USER 1 #define QUOTA_GROUP 0 @@ -241,7 +242,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; + struct gfs2_inode *ip = get_v2ip(sdp->sd_qc_inode); unsigned int block, offset; uint64_t dblock; int new = 0; @@ -522,7 +523,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; + struct gfs2_inode *ip = get_v2ip(sdp->sd_qc_inode); struct gfs2_quota_change *qc = qd->qd_bh_qc; int64_t x; @@ -563,12 +564,13 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) 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; + struct gfs2_inode *ip = get_v2ip(sdp->sd_quota_inode); unsigned int data_blocks, ind_blocks; + struct file_ra_state ra_state; struct gfs2_holder *ghs, i_gh; unsigned int qx, x; struct gfs2_quota_data *qd; - uint64_t offset; + loff_t offset; unsigned int nalloc = 0; struct gfs2_alloc *al = NULL; int error; @@ -631,6 +633,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); for (x = 0; x < num_qd; x++) { char buf[sizeof(struct gfs2_quota)]; struct gfs2_quota q; @@ -642,7 +645,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) sizeof(struct gfs2_quota) bytes. */ memset(buf, 0, sizeof(struct gfs2_quota)); - error = gfs2_jdata_read_mem(ip, buf, offset, + error = gfs2_internal_read(ip, &ra_state, buf, &offset, sizeof(struct gfs2_quota)); if (error < 0) goto out_end_trans; @@ -703,8 +706,10 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder i_gh; struct gfs2_quota q; char buf[sizeof(struct gfs2_quota)]; + struct file_ra_state ra_state; int error; + file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping); restart: error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); if (error) @@ -713,6 +718,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, gfs2_quota_lvb_in(&qd->qd_qb, qd->qd_gl->gl_lvb); if (force_refresh || qd->qd_qb.qb_magic != GFS2_MAGIC) { + loff_t pos; gfs2_glock_dq_uninit(q_gh); error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, @@ -720,16 +726,17 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, if (error) return error; - error = gfs2_glock_nq_init(sdp->sd_quota_inode->i_gl, + error = gfs2_glock_nq_init(get_v2ip(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), + pos = qd2offset(qd); + error = gfs2_internal_read(get_v2ip(sdp->sd_quota_inode), + &ra_state, buf, + &pos, sizeof(struct gfs2_quota)); if (error < 0) goto fail_gunlock; @@ -1059,7 +1066,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; + struct gfs2_inode *ip = get_v2ip(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; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 87c80bbce1c..758cc565813 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -12,19 +12,20 @@ #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" +#include "ops_file.h" /** * gfs2_rgrp_verify - Verify that a resource group is consistent @@ -268,8 +269,10 @@ 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_rgrpd *rgd; char buf[sizeof(struct gfs2_rindex)]; + struct file_ra_state ra_state; uint64_t junk = ip->i_di.di_size; int error; @@ -280,10 +283,10 @@ static int gfs2_ri_update(struct gfs2_inode *ip) clear_rgrpdi(sdp); + file_ra_state_init(&ra_state, inode->i_mapping); for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) { - error = gfs2_jdata_read_mem(ip, buf, - sdp->sd_rgrps * - sizeof(struct gfs2_rindex), + loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex); + error = gfs2_internal_read(ip, &ra_state, buf, &pos, sizeof(struct gfs2_rindex)); if (!error) break; @@ -350,7 +353,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; + struct gfs2_inode *ip = get_v2ip(sdp->sd_rindex); struct gfs2_glock *gl = ip->i_gl; int error; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index cab7ab5fb50..bae32ba0c48 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -271,7 +271,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 = sdp->sd_jindex; + struct gfs2_inode *dip = get_v2ip(sdp->sd_jindex); struct qstr name; char buf[20]; struct gfs2_jdesc *jd; @@ -289,7 +289,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(sdp->sd_jindex, &name, NULL, NULL); + error = gfs2_dir_search(get_v2ip(sdp->sd_jindex), &name, NULL, NULL); if (error == -ENOENT) { error = 0; break; @@ -437,6 +437,7 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd) int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) { + struct inode *inode = NULL; struct gfs2_glock *gl; int error; @@ -444,8 +445,8 @@ int gfs2_lookup_master_dir(struct gfs2_sbd *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); + error = gfs2_lookup_simple(sdp->sd_root_dir, ".gfs2_admin", &inode); + sdp->sd_master_dir = inode; gfs2_glock_put(gl); } @@ -549,9 +550,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; + struct gfs2_inode *m_ip = get_v2ip(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_inode *l_ip = get_v2ip(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; @@ -598,7 +599,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; + struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct buffer_head *l_bh; int error; @@ -624,8 +625,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; - struct gfs2_inode *l_ip = sdp->sd_sc_inode; + struct gfs2_inode *m_ip = get_v2ip(sdp->sd_statfs_inode); + struct gfs2_inode *l_ip = get_v2ip(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; diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index b8d836e3a5c..405b91b0295 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -25,7 +25,7 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, struct gfs2_unlinked_tag *ut) { - struct gfs2_inode *ip = sdp->sd_ut_inode; + struct gfs2_inode *ip = get_v2ip(sdp->sd_ut_inode); unsigned int block, offset; uint64_t dblock; int new = 0; @@ -312,7 +312,7 @@ int gfs2_unlinked_dealloc(struct gfs2_sbd *sdp) int gfs2_unlinked_init(struct gfs2_sbd *sdp) { - struct gfs2_inode *ip = sdp->sd_ut_inode; + struct gfs2_inode *ip = get_v2ip(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; -- GitLab From 257f9b4e97e9a6cceeb247cead92119a4396d37b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 31 Jan 2006 10:00:25 +0000 Subject: [PATCH 0034/1619] [GFS2] Update truncate function (shrinking partial blocks) Update the function in GFS2 which deals with truncation of partial blocks. Some of the code is "borrowed" from ext3 since it appears to give a good model of how to do this operation. The function is renamed gfs2_block_truncate_page accordingly. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 2 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/page.c | 112 ++++++++++++++++++++++-------------------- fs/gfs2/page.h | 4 +- 4 files changed, 63 insertions(+), 57 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index ff4a9175b4e..bd194f645c5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -872,7 +872,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size) if (do_div(junk, sdp->sd_jbsize)) error = truncator_journaled(ip, size); } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) - error = gfs2_truncator_page(ip, size); + error = gfs2_block_truncate_page(ip->i_vnode->i_mapping); if (!error) { ip->i_di.di_size = size; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index da5a0b44518..d611b2ad2e9 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -385,7 +385,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, i_size_write(inode, file_size); } else { if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) - gfs2_page_add_databufs(sdp, page, from, to); + gfs2_page_add_databufs(ip, page, from, to); error = generic_commit_write(file, page, from, to); if (error) goto fail; diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index 05453c5a06f..ea31bceac4f 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -21,6 +21,7 @@ #include "inode.h" #include "page.h" #include "trans.h" +#include "ops_address.h" /** * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock @@ -184,76 +185,81 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, } /** - * gfs2_truncator_page - truncate a partial data block in the page cache - * @ip: the inode - * @size: the size the file should be + * gfs2_block_truncate_page - Deal with zeroing out data for truncate * - * Returns: errno + * This is partly borrowed from ext3. */ - -int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size) +int gfs2_block_truncate_page(struct address_space *mapping) { + struct inode *inode = mapping->host; + struct gfs2_inode *ip = get_v2ip(inode); struct gfs2_sbd *sdp = ip->i_sbd; - struct inode *inode = ip->i_vnode; - struct page *page; + loff_t from = inode->i_size; + unsigned long index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + unsigned blocksize, iblock, length, pos; struct buffer_head *bh; + struct page *page; 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; - } + int err; + + page = grab_cache_page(mapping, index); + if (!page) + return 0; - kaddr = kmap(page); - memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); - kunmap(page); + blocksize = inode->i_sb->s_blocksize; + length = blocksize - (offset & (blocksize - 1)); + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); if (!page_has_buffers(page)) - create_empty_buffers(page, 1 << inode->i_blkbits, - (1 << BH_Uptodate)); + create_empty_buffers(page, blocksize, 0); - for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) - /* Do nothing */; + /* Find the buffer that contains "offset" */ + bh = page_buffers(page); + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } - if (!buffer_mapped(bh)) - map_bh(bh, inode->i_sb, dbn); + err = 0; - set_buffer_uptodate(bh); - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) + if (!buffer_mapped(bh)) { + gfs2_get_block(inode, iblock, bh, 0); + /* unmapped? It's a hole - nothing to do */ + if (!buffer_mapped(bh)) + 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 (sdp->sd_args.ar_data == GFS2_DATA_ORDERED/* || gfs2_is_jdata(ip)*/) gfs2_trans_add_databuf(sdp, bh); - mark_buffer_dirty(bh); - out: + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, length); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + +unlock: unlock_page(page); page_cache_release(page); - - return error; + return err; } -void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, +void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, unsigned int from, unsigned int to) { struct buffer_head *head = page_buffers(page); @@ -267,7 +273,7 @@ void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, end = start + bsize; if (end <= from || start >= to) continue; - gfs2_trans_add_databuf(sdp, bh); + gfs2_trans_add_databuf(ip->i_sbd, bh); } } diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h index 7ad8c99ee0e..346e296420c 100644 --- a/fs/gfs2/page.h +++ b/fs/gfs2/page.h @@ -16,8 +16,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); -int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size); -void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, +int gfs2_block_truncate_page(struct address_space *mapping); +void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, unsigned int from, unsigned int to); #endif /* __PAGE_DOT_H__ */ -- GitLab From 18ec7d5c3f434aed9661ed10a9e1f48cdeb4981d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 8 Feb 2006 11:50:51 +0000 Subject: [PATCH 0035/1619] [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 diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 4e87b8661af..88f92794811 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 bd194f645c5..4efcd8a39e9 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 ada283a0f5f..c77e18048d9 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 ff6d1c597ee..5b01497b3ab 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 e42ae38d677..214975c6bb2 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 e43eaf133f1..00000000000 --- 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 95e18fcb8f8..00000000000 --- 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 f6d00130f96..9b4484d366c 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 a065f766723..dd41863810d 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 b6bd2ebfc2c..ef58d43b67e 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 d611b2ad2e9..b14357e8942 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 0f356fc4690..56820b39a99 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 a1b409ce75e..8f77bb7896b 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 ea31bceac4f..3542aa6b01c 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 69e8f4e92e5..138fdf559a9 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 b014591fa4a..104e664fa18 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 5a7da1e853c..f7f3e2a3d59 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 ad49153c33d..4fb1704aac1 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 f1302e2616d..99d7ae4f6b7 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__ */ -- GitLab From 7359a19cc758946aba0e45233b8641256b194884 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 13 Feb 2006 12:27:43 +0000 Subject: [PATCH 0036/1619] [GFS2] Fix for root inode ref count bug Umount is now working correctly again. The bug was due to not getting an extra ref count when mounting the fs. We should have bumped it by two (once for the internal pointer to the root inode from the super block and once for the inode hanging off the dcache entry for root). Also this patch tidys up the code dealing with looking up and creating inodes. We now pass Linux inodes (with gfs2_inodes attached) rather than the other way around and this reduces code duplication in various places. Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 4 +-- fs/gfs2/incore.h | 2 +- fs/gfs2/inode.c | 70 +++++++++++++++++++++++++++----------------- fs/gfs2/inode.h | 15 +++------- fs/gfs2/log.c | 2 +- fs/gfs2/lops.c | 30 +++++++++---------- fs/gfs2/ops_export.c | 9 +----- fs/gfs2/ops_fstype.c | 3 +- fs/gfs2/ops_inode.c | 67 ++++++++++++------------------------------ fs/gfs2/quota.c | 2 +- fs/gfs2/recovery.c | 20 ++++++------- fs/gfs2/super.c | 12 ++++---- 12 files changed, 103 insertions(+), 133 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 127008146a5..27374306ecd 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -358,13 +358,13 @@ 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 = sdp->sd_jdesc->jd_inode->i_gl; + struct gfs2_glock *j_gl = get_v2ip(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); + gfs2_meta_cache_flush(get_v2ip(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 d1954e2bb90..e43a0475d0d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -378,7 +378,7 @@ struct gfs2_ail { struct gfs2_jdesc { struct list_head jd_list; - struct gfs2_inode *jd_inode; + struct inode *jd_inode; unsigned int jd_jid; int jd_dirty; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 4c193e38f8e..2a00b96eac0 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -711,24 +711,28 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) * Returns: errno */ -int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root, - struct gfs2_inode **ipp) +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_sbd *sdp = dip->i_sbd; struct gfs2_holder d_gh; struct gfs2_inum inum; unsigned int type; struct gfs2_glock *gl; - int error; + int error = 0; + + *inodep = NULL; if (!name->len || name->len > GFS2_FNAMESIZE) return -ENAMETOOLONG; if (gfs2_filecmp(name, ".", 1) || - (gfs2_filecmp(name, "..", 2) && dip == get_v2ip(sdp->sd_root_dir))) { + (gfs2_filecmp(name, "..", 2) && dir == sdp->sd_root_dir)) { gfs2_inode_hold(dip); - *ipp = dip; - return 0; + ipp = dip; + goto done; } error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); @@ -750,15 +754,21 @@ int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root, if (error) goto out; - error = gfs2_inode_get(gl, &inum, CREATE, ipp); + error = gfs2_inode_get(gl, &inum, CREATE, &ipp); if (!error) - gfs2_inode_min_init(*ipp, type); + gfs2_inode_min_init(ipp, type); gfs2_glock_put(gl); - out: +out: gfs2_glock_dq_uninit(&d_gh); - +done: + if (error == 0) { + *inodep = gfs2_ip2v(ipp); + if (!*inodep) + error = -ENOMEM; + gfs2_inode_put(ipp); + } return error; } @@ -1171,15 +1181,16 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, * @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 + * If the return value is not NULL, 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 + * Returns: An inode */ -int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) +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_sbd *sdp = dip->i_sbd; struct gfs2_unlinked *ul; @@ -1187,11 +1198,11 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) int error; if (!name->len || name->len > GFS2_FNAMESIZE) - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); error = gfs2_unlinked_get(sdp, &ul); if (error) - return error; + return ERR_PTR(error); gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); error = gfs2_glock_nq(ghs); @@ -1220,7 +1231,7 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) ghs + 1); if (error) { gfs2_unlinked_put(sdp, ul); - return error; + return ERR_PTR(error); } gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); @@ -1228,7 +1239,7 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) if (error) { gfs2_glock_dq_uninit(ghs + 1); gfs2_unlinked_put(sdp, ul); - return error; + return ERR_PTR(error); } error = create_ok(dip, name, mode); @@ -1266,7 +1277,11 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) gfs2_unlinked_put(sdp, ul); - return 0; + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + if (!inode) + return ERR_PTR(-ENOMEM); + return inode; fail_iput: gfs2_inode_put(ip); @@ -1280,7 +1295,7 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) fail: gfs2_unlinked_put(sdp, ul); - return error; + return ERR_PTR(error); } /** @@ -1445,7 +1460,8 @@ 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 gfs2_sbd *sdp = this->i_sbd; - struct gfs2_inode *tmp; + struct inode *dir = to->i_vnode; + struct inode *tmp; struct qstr dotdot; int error = 0; @@ -1453,27 +1469,27 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) dotdot.name = ".."; dotdot.len = 2; - gfs2_inode_hold(to); + igrab(dir); for (;;) { - if (to == this) { + if (dir == this->i_vnode) { error = -EINVAL; break; } - if (to == get_v2ip(sdp->sd_root_dir)) { + if (dir == sdp->sd_root_dir) { error = 0; break; } - error = gfs2_lookupi(to, &dotdot, 1, &tmp); + error = gfs2_lookupi(dir, &dotdot, 1, &tmp); if (error) break; - gfs2_inode_put(to); - to = tmp; + iput(dir); + dir = tmp; } - gfs2_inode_put(to); + iput(dir); return error; } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 214975c6bb2..8ef85f5feb1 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -44,9 +44,9 @@ 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_lookupi(struct inode *dir, struct qstr *name, int is_root, + struct inode **ipp); +struct inode *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, @@ -68,19 +68,12 @@ 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 gfs2_inode *ip; struct qstr qstr; int err; memset(&qstr, 0, sizeof(struct qstr)); qstr.name = name; qstr.len = strlen(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; - } + err = gfs2_lookupi(dip, &qstr, 1, ipp); return err; } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 9b4484d366c..49190a29dd4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -274,7 +274,7 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) uint64_t dbn; int error; - error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, NULL); + error = gfs2_block_map(get_v2ip(sdp->sd_jdesc->jd_inode), lbn, &new, &dbn, NULL); gfs2_assert_withdraw(sdp, !error && dbn); return dbn; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index dd41863810d..23be0014190 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -177,7 +177,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_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; if (pass != 0) return; @@ -190,8 +190,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_sbd *sdp = jd->jd_inode->i_sbd; - struct gfs2_glock *gl = jd->jd_inode->i_gl; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; uint64_t blkno; @@ -236,16 +236,16 @@ 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 = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; if (error) { - gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(get_v2ip(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); + gfs2_meta_sync(get_v2ip(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); @@ -320,7 +320,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_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; if (pass != 0) return; @@ -333,7 +333,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_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(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; @@ -379,7 +379,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_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; if (error) { gfs2_revoke_clean(sdp); @@ -458,8 +458,6 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) 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) @@ -630,8 +628,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_sbd *sdp = jd->jd_inode->i_sbd; - struct gfs2_glock *gl = jd->jd_inode->i_gl; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; uint64_t blkno; @@ -680,17 +678,17 @@ 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 = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; if (error) { - gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(get_v2ip(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); + gfs2_meta_sync(get_v2ip(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); diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 335448d3be2..8389f771d28 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -169,23 +169,16 @@ 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); + error = gfs2_lookupi(child->d_inode, &dotdot, 1, &inode); 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); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 139cef8fff3..80d5582d9d9 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -360,6 +360,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) goto out_rooti; } + igrab(inode); sb->s_root = d_alloc_root(inode); if (!sb->s_root) { fs_err(sdp, "can't get root dentry\n"); @@ -434,7 +435,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) goto fail_jindex; } - error = gfs2_glock_nq_init(sdp->sd_jdesc->jd_inode->i_gl, + error = gfs2_glock_nq_init(get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, &sdp->sd_jinode_gh); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 6fff30ef8b7..9fb9490eb67 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -49,7 +49,7 @@ 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_inode *dip = get_v2ip(dir); struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_holder ghs[2]; struct inode *inode; @@ -61,9 +61,8 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, 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); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode); + if (!IS_ERR(inode)) { gfs2_trans_end(sdp); if (dip->i_alloc.al_rgd) gfs2_inplace_release(dip); @@ -71,13 +70,13 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, gfs2_alloc_put(dip); gfs2_glock_dq_uninit_m(2, ghs); break; - } else if (error != -EEXIST || + } else if (PTR_ERR(inode) != -EEXIST || (nd->intent.open.flags & O_EXCL)) { gfs2_holder_uninit(ghs); - return error; + return PTR_ERR(inode); } - error = gfs2_lookupi(dip, &dentry->d_name, 0, &ip); + error = gfs2_lookupi(dir, &dentry->d_name, 0, &inode); if (!error) { new = 0; gfs2_holder_uninit(ghs); @@ -88,12 +87,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, } } - inode = gfs2_ip2v(ip); - gfs2_inode_put(ip); - - if (!inode) - return -ENOMEM; - d_instantiate(dentry, inode); if (new) mark_inode_dirty(inode); @@ -115,7 +108,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), *ip; + struct gfs2_inode *dip = get_v2ip(dir); struct gfs2_sbd *sdp = dip->i_sbd; struct inode *inode = NULL; int error; @@ -125,14 +118,8 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, 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) + error = gfs2_lookupi(dir, &dentry->d_name, 0, &inode); + if (error && error != -ENOENT) return ERR_PTR(error); if (inode) @@ -367,10 +354,10 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, gfs2_holder_init(dip->i_gl, 0, 0, ghs); - error = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO); - if (error) { + inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO); + if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); - return error; + return PTR_ERR(inode); } ip = get_gl2ip(ghs[1].gh_gl); @@ -394,12 +381,6 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, 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); @@ -428,10 +409,10 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) gfs2_holder_init(dip->i_gl, 0, 0, ghs); - error = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode); - if (error) { + inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode); + if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); - return error; + return PTR_ERR(inode); } ip = get_gl2ip(ghs[1].gh_gl); @@ -481,12 +462,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) 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); @@ -598,10 +573,10 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, gfs2_holder_init(dip->i_gl, 0, 0, ghs); - error = gfs2_createi(ghs, &dentry->d_name, mode); - if (error) { + inode = gfs2_createi(ghs, &dentry->d_name, mode); + if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); - return error; + return PTR_ERR(inode); } ip = get_gl2ip(ghs[1].gh_gl); @@ -624,12 +599,6 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, 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); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 138fdf559a9..7b5573946f1 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -572,7 +572,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 = gfs2_ip2v(ip); + struct inode *inode = ip->i_vnode; struct address_space *mapping = inode->i_mapping; unsigned long index = loc >> PAGE_CACHE_SHIFT; unsigned offset = loc & (PAGE_CACHE_SHIFT - 1); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 15cd26fbcff..bcb81c768c8 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -27,17 +27,17 @@ 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; + struct gfs2_glock *gl = get_v2ip(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); + error = gfs2_block_map(get_v2ip(jd->jd_inode), blk, &new, &dblock, &extlen); if (error) return error; if (!dblock) { - gfs2_consist_inode(jd->jd_inode); + gfs2_consist_inode(get_v2ip(jd->jd_inode)); return -EIO; } @@ -184,7 +184,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); + gfs2_consist_inode(get_v2ip(jd->jd_inode)); return -EIO; } } @@ -218,7 +218,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); + gfs2_consist_inode(get_v2ip(jd->jd_inode)); return -EIO; } if (lh.lh_sequence < head->lh_sequence) @@ -294,7 +294,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_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; struct buffer_head *bh; struct gfs2_log_descriptor *ld; int error = 0; @@ -323,7 +323,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, continue; } if (error == 1) { - gfs2_consist_inode(jd->jd_inode); + gfs2_consist_inode(get_v2ip(jd->jd_inode)); error = -EIO; } brelse(bh); @@ -360,7 +360,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 = jd->jd_inode; + struct gfs2_inode *ip = get_v2ip(jd->jd_inode); struct gfs2_sbd *sdp = ip->i_sbd; unsigned int lblock; int new = 0; @@ -419,7 +419,7 @@ 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 = jd->jd_inode->i_sbd; + struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; struct gfs2_log_header head; struct gfs2_holder j_gh, ji_gh, t_gh; unsigned long t; @@ -449,7 +449,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) goto fail; }; - error = gfs2_glock_nq_init(jd->jd_inode->i_gl, LM_ST_SHARED, + error = gfs2_glock_nq_init(get_v2ip(jd->jd_inode)->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP, &ji_gh); if (error) goto fail_gunlock_j; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index bae32ba0c48..9b5c31952c5 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -305,7 +305,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) if (!jd) break; - error = gfs2_lookupi(dip, &name, 1, &jd->jd_inode); + error = gfs2_lookupi(sdp->sd_jindex, &name, 1, &jd->jd_inode); if (error) { kfree(jd); break; @@ -342,7 +342,7 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp) 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); + iput(jd->jd_inode); kfree(jd); } } @@ -411,7 +411,7 @@ 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; + struct gfs2_inode *ip = get_v2ip(jd->jd_inode); struct gfs2_sbd *sdp = ip->i_sbd; int ar; int error; @@ -462,7 +462,7 @@ int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) int gfs2_make_fs_rw(struct gfs2_sbd *sdp) { - struct gfs2_glock *j_gl = sdp->sd_jdesc->jd_inode->i_gl; + struct gfs2_glock *j_gl = get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl; struct gfs2_holder t_gh; struct gfs2_log_header head; int error; @@ -472,7 +472,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) if (error) return error; - gfs2_meta_cache_flush(sdp->sd_jdesc->jd_inode); + gfs2_meta_cache_flush(get_v2ip(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); @@ -854,7 +854,7 @@ int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) error = -ENOMEM; goto out; } - error = gfs2_glock_nq_init(jd->jd_inode->i_gl, LM_ST_SHARED, 0, + error = gfs2_glock_nq_init(get_v2ip(jd->jd_inode)->i_gl, LM_ST_SHARED, 0, &lfcc->gh); if (error) { kfree(lfcc); -- GitLab From fc69d0d336214219abb521d8ff060f786d7f369e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 13 Feb 2006 16:21:47 +0000 Subject: [PATCH 0037/1619] [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(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index c77e18048d9..c32f7b3de66 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 99d7ae4f6b7..ec432e0c208 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]; }; /* -- GitLab From d1665e414297c3a46fd80cb8242ad0c8e82acae7 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 14 Feb 2006 11:54:42 +0000 Subject: [PATCH 0038/1619] [GFS2] Put back O_DIRECT support This patch adds back O_DIRECT support with various caveats attached: 1. Journaled data can be read via O_DIRECT since its now the same on disk format as normal data files. 2. Journaled data writes with O_DIRECT will be failed sliently back to normal writes (should we really do this I wonder or should we return an error instead?) 3. Stuffed files will be failed back to normal buffered I/O 4. All the usual corner cases (write beyond current end of file, write to an unallocated block) will also revert to normal buffered I/O. The I/O path is slightly odd as reads arrive at the page cache layer with the lock for the file already held, but writes arrive unlocked. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 72 ++++++++++++++++++++++++++++++++++--------- fs/gfs2/ops_file.c | 29 +++++++++-------- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index b14357e8942..74706f35278 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -555,30 +556,73 @@ static int gfs2_invalidatepage(struct page *page, unsigned long offset) return ret; } -static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +static ssize_t gfs2_direct_IO_write(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_holder gh; + int rv; + + /* + * Shared lock, even though its write, since we do no allocation + * on this path. All we need change is atime. + */ + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + rv = gfs2_glock_nq_m_atime(1, &gh); + if (rv) + goto out; + + /* + * Should we return an error here? I can't see that O_DIRECT for + * a journaled file makes any sense. For now we'll silently fall + * back to buffered I/O, likewise we do the same for stuffed + * files since they are (a) small and (b) unaligned. + */ + if (gfs2_is_jdata(ip)) + goto out; + + if (gfs2_is_stuffed(ip)) + goto out; + + rv = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, + iov, offset, nr_segs, get_blocks_noalloc, + NULL, DIO_OWN_LOCKING); +out: + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); + + return rv; +} + +/** + * gfs2_direct_IO + * + * This is called with a shared lock already held for the read path. + * Currently, no locks are held when the write path is called. + */ +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_is_jdata(ip)) - return -EINVAL; + if (rw == WRITE) + return gfs2_direct_IO_write(iocb, iov, offset, nr_segs); - 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; - } + 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); + return __blockdev_direct_IO(READ, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, get_blocks, NULL, + DIO_OWN_LOCKING); } struct address_space_operations gfs2_file_aops = { diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 56820b39a99..bcde7a0b76f 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -176,16 +176,16 @@ static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, * 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, 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; + count += iv->iov_len; + if (unlikely((ssize_t)(count|iv->iov_len) < 0)) + return -EINVAL; + 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 */ @@ -204,10 +204,14 @@ static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, retval = gfs2_glock_nq_m_atime(1, &gh); if (retval) goto out; - + if (gfs2_is_stuffed(ip)) { + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); + goto fallback_to_normal; + } size = i_size_read(inode); if (pos < size) { - retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); + retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); if (retval > 0 && !is_sync_kiocb(iocb)) retval = -EIOCBQUEUED; if (retval > 0) @@ -219,6 +223,7 @@ static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, goto out; } +fallback_to_normal: retval = 0; if (count) { for (seg = 0; seg < nr_segs; seg++) { -- GitLab From 4dd651adbb4898d3200426c197b26c99d2209d8d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 14 Feb 2006 15:56:44 +0000 Subject: [PATCH 0039/1619] [GFS2] Fix the bugs I introduced in the last patch but one Various endianess changes required in the directory code. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 56 ++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index c32f7b3de66..65871a2b460 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -417,6 +417,12 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, gfs2_consist_inode(dip); return -EIO; } + + if (cur_rec_len == 0) { + 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); @@ -512,9 +518,8 @@ 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_be16(dent->de_rec_len); - dent->de_name_len = name_len; + 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; @@ -522,10 +527,10 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, do { uint16_t cur_rec_len; - uint32_t cur_name_len; + uint16_t cur_name_len; cur_rec_len = be16_to_cpu(dent->de_rec_len); - cur_name_len = dent->de_name_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)) { @@ -536,18 +541,16 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, 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_be16(new->de_rec_len); - new->de_name_len = name_len; + 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 = cur_rec_len - be16_to_cpu(new->de_rec_len); - dent->de_rec_len = cpu_to_be16(dent->de_rec_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 = name_len; + dent->de_name_len = cpu_to_be16(name_len); *dent_out = dent; return 0; @@ -594,7 +597,7 @@ static int dirent_fits(struct gfs2_inode *dip, struct buffer_head *bh, uint32_t cur_name_len; cur_rec_len = be16_to_cpu(dent->de_rec_len); - cur_name_len = dent->de_name_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)) @@ -635,7 +638,7 @@ static int leaf_search(struct gfs2_inode *dip, struct buffer_head *bh, if (be32_to_cpu(dent->de_hash) == hash && gfs2_filecmp(filename, (char *)(dent + 1), - dent->de_name_len)) { + be16_to_cpu(dent->de_name_len))) { *dent_out = dent; if (dent_prev) *dent_prev = prev; @@ -834,10 +837,9 @@ 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 = be16_to_cpu(dent->de_rec_len) + + dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) + sizeof(struct gfs2_dinode) - - sizeof(struct gfs2_leaf); - dent->de_rec_len = cpu_to_be16(dent->de_rec_len); + sizeof(struct gfs2_leaf)); brelse(bh); @@ -969,7 +971,7 @@ 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 = dent->de_name_len; + name_len = be16_to_cpu(dent->de_name_len); gfs2_dirent_alloc(dip, nbh, name_len, &new); @@ -1139,8 +1141,8 @@ static int compare_dents(const void *a, const void *b) 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; + unsigned int len_a = be16_to_cpu(dent_a->de_name_len); + unsigned int len_b = be16_to_cpu(dent_b->de_name_len); if (len_a > len_b) ret = 1; @@ -1219,9 +1221,9 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, gfs2_inum_in(&inum, (char *)&dent->de_inum); error = filldir(opaque, (char *)(dent + 1), - dent->de_name_len, + be16_to_cpu(dent->de_name_len), off, &inum, - dent->de_type); + be16_to_cpu(dent->de_type)); if (error) return 1; @@ -1454,7 +1456,7 @@ static int dir_e_search(struct gfs2_inode *dip, struct qstr *filename, if (inum) gfs2_inum_in(inum, (char *)&dent->de_inum); if (type) - *type = dent->de_type; + *type = be16_to_cpu(dent->de_type); brelse(bh); @@ -1563,7 +1565,7 @@ static int dir_e_add(struct gfs2_inode *dip, struct qstr *filename, gfs2_inum_out(inum, (char *)&dent->de_inum); dent->de_hash = cpu_to_be32(hash); - dent->de_type = type; + 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; @@ -1732,7 +1734,7 @@ static int dir_e_mvino(struct gfs2_inode *dip, struct qstr *filename, gfs2_trans_add_bh(dip->i_gl, bh, 1); gfs2_inum_out(inum, (char *)&dent->de_inum); - dent->de_type = new_type; + dent->de_type = cpu_to_be16(new_type); brelse(bh); @@ -1780,7 +1782,7 @@ static int dir_l_search(struct gfs2_inode *dip, struct qstr *filename, if (inum) gfs2_inum_in(inum, (char *)&dent->de_inum); if (type) - *type = dent->de_type; + *type = be16_to_cpu(dent->de_type); } brelse(dibh); @@ -1819,7 +1821,7 @@ static int dir_l_add(struct gfs2_inode *dip, struct qstr *filename, 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; + dent->de_type = cpu_to_be16(type); memcpy((char *)(dent + 1), filename->name, filename->len); dip->i_di.di_entries++; @@ -1932,7 +1934,7 @@ static int dir_l_mvino(struct gfs2_inode *dip, struct qstr *filename, gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_inum_out(inum, (char *)&dent->de_inum); - dent->de_type = new_type; + dent->de_type = cpu_to_be16(new_type); dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); -- GitLab From 61a30dcb5866eb7e92796b2988ddb4c94b9f78ac Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 15 Feb 2006 10:15:18 +0000 Subject: [PATCH 0040/1619] [GFS2] Fix for lock recursion problem for internal files Two internal files which are read through the gfs2_internal_read() routine were already locked when the routine was called and this do not need locking at the redapages level. This patch introduces a struct file which is used as a sentinal so that readpage will only perform locking in the case that the struct file passed to it is _not_ equal to this sentinal. Since the comments in the generic kernel code indicate that the struct file will never be used for anything other than passing straight through to readpage(), this should be ok. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 17 +++++++++++------ fs/gfs2/ops_file.c | 14 +++++++++++++- fs/gfs2/ops_file.h | 2 +- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 74706f35278..39d03f3f2d5 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -28,6 +28,7 @@ #include "quota.h" #include "trans.h" #include "rgrp.h" +#include "ops_file.h" /** * gfs2_get_block - Fills in a buffer head with details about a block @@ -267,10 +268,12 @@ static int gfs2_readpage(struct file *file, struct page *page) atomic_inc(&sdp->sd_ops_address); - 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 (file != &gfs2_internal_file_sentinal) { + 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_stuffed(ip)) { if (!page->index) { @@ -284,8 +287,10 @@ static int gfs2_readpage(struct file *file, struct page *page) if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = -EIO; - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); + if (file != &gfs2_internal_file_sentinal) { + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); + } out: return error; out_unlock: diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index bcde7a0b76f..b8603783229 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -67,6 +67,16 @@ struct filldir_reg { void *fdr_opaque; }; +/* + * Most fields left uninitialised to catch anybody who tries to + * use them. f_flags set to prevent file_accessed() from touching + * any other part of this. Its use is purely as a flag so that we + * know (in readpage()) whether or not do to locking. + */ +struct file gfs2_internal_file_sentinal = { + .f_flags = O_NOATIME|O_RDONLY, +}; + static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size) { @@ -95,7 +105,9 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, 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); + do_generic_mapping_read(inode->i_mapping, ra_state, + &gfs2_internal_file_sentinal, pos, &desc, + gfs2_read_actor); return desc.written ? desc.written : desc.error; } diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index 3c237bfc143..192577b411f 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -9,7 +9,7 @@ #ifndef __OPS_FILE_DOT_H__ #define __OPS_FILE_DOT_H__ - +extern struct file gfs2_internal_file_sentinal; extern int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, char *buf, loff_t *pos, unsigned size); -- GitLab From 5c4e9e036678fae65c9288e1c00a6f33cd447283 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 15 Feb 2006 12:26:19 +0000 Subject: [PATCH 0041/1619] [GFS2] Fix a case where we didn't get unstuffing right There was a bug in the unstuffing logic which caused a crash under certain circumstances. This is now fixed. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 39d03f3f2d5..1ccc2642682 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -220,14 +220,14 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) if (error) return error; - kaddr = kmap(page); + kaddr = kmap_atomic(page, KM_USER0); 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); + kunmap_atomic(page, KM_USER0); brelse(dibh); @@ -240,9 +240,9 @@ static int zero_readpage(struct page *page) { void *kaddr; - kaddr = kmap(page); + kaddr = kmap_atomic(page, KM_USER0); memset(kaddr, 0, PAGE_CACHE_SIZE); - kunmap(page); + kunmap_atomic(page, KM_USER0); SetPageUptodate(page); unlock_page(page); @@ -364,14 +364,14 @@ static int gfs2_prepare_write(struct file *file, struct page *page, 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)) { + if (error == 0) + goto prepare_write; + } else if (!PageUptodate(page)) error = stuffed_readpage(ip, page); - goto out; - } + goto out; } +prepare_write: error = block_prepare_write(page, from, to, gfs2_get_block); out: -- GitLab From f55ab26a8f92a23988c3e6da28dae4741933a4e2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 21 Feb 2006 12:51:39 +0000 Subject: [PATCH 0042/1619] [GFS2] Use mutices rather than semaphores As well as a number of minor bug fixes, this patch changes GFS to use mutices rather than semaphores. This results in better information in case there are any locking problems. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 8 +++---- fs/gfs2/incore.h | 22 +++++++++--------- fs/gfs2/inode.c | 12 +++++----- fs/gfs2/log.c | 54 +++++++++++++++---------------------------- fs/gfs2/log.h | 3 --- fs/gfs2/lops.c | 36 ++++++++++++++++++++++------- fs/gfs2/meta_io.c | 2 +- fs/gfs2/ops_address.c | 1 - fs/gfs2/ops_file.c | 10 ++++---- fs/gfs2/ops_fstype.c | 18 +++++++-------- fs/gfs2/ops_super.c | 4 ++-- fs/gfs2/quota.c | 16 ++++++------- fs/gfs2/rgrp.c | 18 +++++++-------- fs/gfs2/super.c | 20 ++++++++-------- fs/gfs2/sys.c | 4 ++-- fs/gfs2/trans.c | 4 ++-- fs/gfs2/unlinked.c | 4 ++-- 17 files changed, 118 insertions(+), 118 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 321945fde12..4df78ecfeeb 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -149,7 +149,7 @@ int gfs2_glock_put(struct gfs2_glock *gl) struct gfs2_gl_hash_bucket *bucket = gl->gl_bucket; int rv = 0; - down(&sdp->sd_invalidate_inodes_mutex); + mutex_lock(&sdp->sd_invalidate_inodes_mutex); write_lock(&bucket->hb_lock); if (kref_put(&gl->gl_ref, kill_glock)) { @@ -161,7 +161,7 @@ int gfs2_glock_put(struct gfs2_glock *gl) } write_unlock(&bucket->hb_lock); out: - up(&sdp->sd_invalidate_inodes_mutex); + mutex_unlock(&sdp->sd_invalidate_inodes_mutex); return rv; } @@ -2312,9 +2312,9 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) invalidate_inodes_mutex prevents glock_put()'s during an invalidate_inodes() */ - down(&sdp->sd_invalidate_inodes_mutex); + mutex_lock(&sdp->sd_invalidate_inodes_mutex); invalidate_inodes(sdp->sd_vfs); - up(&sdp->sd_invalidate_inodes_mutex); + mutex_unlock(&sdp->sd_invalidate_inodes_mutex); yield(); } } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e43a0475d0d..7fe422537ff 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -88,7 +88,7 @@ struct gfs2_rgrpd { uint64_t rd_rg_vn; struct gfs2_bitmap *rd_bits; unsigned int rd_bh_count; - struct semaphore rd_mutex; + struct mutex rd_mutex; uint32_t rd_free_clone; struct gfs2_log_element rd_le; uint32_t rd_last_alloc_data; @@ -277,7 +277,7 @@ enum { struct gfs2_file { unsigned long f_flags; /* GFF_... */ - struct semaphore f_fl_mutex; + struct mutex f_fl_mutex; struct gfs2_holder f_fl_gh; struct gfs2_inode *f_inode; @@ -510,7 +510,7 @@ struct gfs2_sbd { struct gfs2_holder sd_live_gh; struct gfs2_glock *sd_rename_gl; struct gfs2_glock *sd_trans_gl; - struct semaphore sd_invalidate_inodes_mutex; + struct mutex sd_invalidate_inodes_mutex; /* Inode Stuff */ @@ -528,12 +528,12 @@ struct gfs2_sbd { /* Inum stuff */ - struct semaphore sd_inum_mutex; + struct mutex sd_inum_mutex; /* StatFS stuff */ spinlock_t sd_statfs_spin; - struct semaphore sd_statfs_mutex; + struct mutex sd_statfs_mutex; struct gfs2_statfs_change sd_statfs_master; struct gfs2_statfs_change sd_statfs_local; unsigned long sd_statfs_sync_time; @@ -542,7 +542,7 @@ struct gfs2_sbd { uint64_t sd_rindex_vn; spinlock_t sd_rindex_spin; - struct semaphore sd_rindex_mutex; + struct mutex sd_rindex_mutex; struct list_head sd_rindex_list; struct list_head sd_rindex_mru_list; struct list_head sd_rindex_recent_list; @@ -553,7 +553,7 @@ struct gfs2_sbd { struct list_head sd_jindex_list; spinlock_t sd_jindex_spin; - struct semaphore sd_jindex_mutex; + struct mutex sd_jindex_mutex; unsigned int sd_journals; unsigned long sd_jindex_refresh_time; @@ -581,7 +581,7 @@ struct gfs2_sbd { struct list_head sd_unlinked_list; atomic_t sd_unlinked_count; spinlock_t sd_unlinked_spin; - struct semaphore sd_unlinked_mutex; + struct mutex sd_unlinked_mutex; unsigned int sd_unlinked_slots; unsigned int sd_unlinked_chunks; @@ -592,7 +592,7 @@ struct gfs2_sbd { struct list_head sd_quota_list; atomic_t sd_quota_count; spinlock_t sd_quota_spin; - struct semaphore sd_quota_mutex; + struct mutex sd_quota_mutex; unsigned int sd_quota_slots; unsigned int sd_quota_chunks; @@ -637,7 +637,7 @@ struct gfs2_sbd { int sd_log_idle; unsigned long sd_log_flush_time; - struct semaphore sd_log_flush_lock; + struct mutex sd_log_flush_lock; struct list_head sd_log_flush_list; unsigned int sd_log_flush_head; @@ -659,7 +659,7 @@ struct gfs2_sbd { /* For quiescing the filesystem */ struct gfs2_holder sd_freeze_gh; - struct semaphore sd_freeze_lock; + struct mutex sd_freeze_lock; unsigned int sd_freeze_count; /* Counters */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2a00b96eac0..30ca82a1add 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -782,11 +782,11 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) return error; - down(&sdp->sd_inum_mutex); + mutex_lock(&sdp->sd_inum_mutex); error = gfs2_meta_inode_buffer(ip, &bh); if (error) { - up(&sdp->sd_inum_mutex); + mutex_unlock(&sdp->sd_inum_mutex); gfs2_trans_end(sdp); return error; } @@ -800,14 +800,14 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); brelse(bh); - up(&sdp->sd_inum_mutex); + mutex_unlock(&sdp->sd_inum_mutex); gfs2_trans_end(sdp); return 0; } brelse(bh); - up(&sdp->sd_inum_mutex); + mutex_unlock(&sdp->sd_inum_mutex); gfs2_trans_end(sdp); return 1; @@ -829,7 +829,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0); if (error) goto out; - down(&sdp->sd_inum_mutex); + mutex_lock(&sdp->sd_inum_mutex); error = gfs2_meta_inode_buffer(ip, &bh); if (error) @@ -869,7 +869,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) brelse(bh); out_end_trans: - up(&sdp->sd_inum_mutex); + mutex_unlock(&sdp->sd_inum_mutex); gfs2_trans_end(sdp); out: diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 49190a29dd4..e6acb41332e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -23,29 +23,16 @@ #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); + wait_event(*wq, atomic_read(a) ? 0 : 1); } 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) @@ -55,15 +42,13 @@ static void unlock_from_trans(struct gfs2_sbd *sdp) wake_up(&sdp->sd_log_flush_wq); } -void gfs2_lock_for_flush(struct gfs2_sbd *sdp) +static 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) +static 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)) @@ -209,7 +194,6 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) 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) { @@ -225,7 +209,6 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) 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) { @@ -237,14 +220,12 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) } 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; @@ -512,22 +493,26 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __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); + + if (gl) { + gfs2_log_lock(sdp); + if (list_empty(&gl->gl_le.le_list)) { + gfs2_log_unlock(sdp); + gfs2_unlock_from_flush(sdp); + kfree(ai); + return; + } + gfs2_log_unlock(sdp); + } + + mutex_lock(&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; @@ -538,7 +523,6 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) 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++; @@ -554,7 +538,7 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) } gfs2_log_unlock(sdp); - up(&sdp->sd_log_flush_lock); + mutex_unlock(&sdp->sd_log_flush_lock); sdp->sd_vfs->s_dirt = 0; gfs2_unlock_from_flush(sdp); @@ -627,7 +611,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) void gfs2_log_shutdown(struct gfs2_sbd *sdp) { - down(&sdp->sd_log_flush_lock); + mutex_lock(&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); @@ -654,6 +638,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) sdp->sd_log_wraps++; sdp->sd_log_tail = sdp->sd_log_head; - up(&sdp->sd_log_flush_lock); + mutex_unlock(&sdp->sd_log_flush_lock); } diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 4413cda8115..e7a6a65c530 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -42,9 +42,6 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp, 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); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 23be0014190..5e7e7d91fc5 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -502,7 +502,8 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) unsigned int total_dbuf = sdp->sd_log_num_databuf; unsigned int total_jdata = sdp->sd_log_num_jdata; unsigned int num, n; - __be64 *ptr; + __be64 *ptr = NULL; + unsigned i; offset += (2*sizeof(__be64) - 1); offset &= ~(2*sizeof(__be64) - 1); @@ -513,14 +514,17 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) * Start writing ordered buffers, write journaled buffers * into the log along with a header */ + gfs2_log_lock(sdp); + /* printk(KERN_INFO "locked in lops databuf_before_commit\n"); */ 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; + /* printk(KERN_INFO "total_dbuf=%u num=%u\n", total_dbuf, num); */ n = 0; + i = 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); @@ -531,20 +535,28 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) total_dbuf--; if (bd1->bd_bh) { get_bh(bd1->bd_bh); - gfs2_log_unlock(sdp); if (buffer_dirty(bd1->bd_bh)) { + gfs2_log_unlock(sdp); wait_on_buffer(bd1->bd_bh); ll_rw_block(WRITE, 1, &bd1->bd_bh); + gfs2_log_lock(sdp); } brelse(bd1->bd_bh); + /* printk(KERN_INFO "db write %p\n", bd1); */ + if (++i > 100000) { + printk(KERN_INFO "looping bd1=%p bdt=%p eol=%p started=%p\n", bd1, bdt, &sdp->sd_log_le_databuf, &started); + dump_stack(); + BUG(); + } continue; } - gfs2_log_unlock(sdp); + /* printk(KERN_INFO "db skip\n"); */ continue; } else if (bd1->bd_bh) { /* A journaled buffer */ int magic; gfs2_log_unlock(sdp); - /* printk(KERN_INFO "journaled buffer\n"); */ + printk(KERN_INFO "journaled buffer %p\n", bd1->bd_bh); + printk(KERN_INFO "%lu %u %p %p\n", bd1->bd_bh->b_blocknr, bd1->bd_bh->b_size, bd1->bd_bh->b_data, bd1->bd_bh->b_page); if (!bh) { bh = gfs2_log_get_buf(sdp); ld = (struct gfs2_log_descriptor *)bh->b_data; @@ -558,16 +570,21 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) ld->ld_data2 = cpu_to_be32(0); memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); } + /* printk(KERN_INFO "check_magic\n"); */ magic = gfs2_check_magic(bd1->bd_bh); + /* printk(KERN_INFO "write data\n"); */ *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr); *ptr++ = cpu_to_be64((__u64)magic); + /* printk(KERN_INFO "mark escaped or not\n"); */ clear_buffer_escaped(bd1->bd_bh); if (unlikely(magic != 0)) set_buffer_escaped(bd1->bd_bh); + gfs2_log_lock(sdp); if (n++ > num) break; } } + gfs2_log_unlock(sdp); if (bh) { set_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); @@ -575,10 +592,12 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } n = 0; /* printk(KERN_INFO "totals2: jdata=%u dbuf=%u\n", total_jdata, total_dbuf); */ + gfs2_log_lock(sdp); 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 */ + gfs2_log_unlock(sdp); if (unlikely(buffer_escaped(bd2->bd_bh))) { void *kaddr; struct page *page = bd2->bd_bh->b_page; @@ -592,6 +611,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } set_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); + gfs2_log_lock(sdp); if (++n >= num) break; } @@ -599,6 +619,8 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) total_dbuf -= num; total_jdata -= num; } + gfs2_log_unlock(sdp); + /* printk(KERN_INFO "wait on ordered data buffers\n"); */ /* Wait on all ordered buffers */ while (!list_empty(&started)) { @@ -701,12 +723,10 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) while (!list_empty(head)) { bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); - list_del_init(&bd->bd_le.le_list); + list_del(&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); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index ef58d43b67e..8fba8430675 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -556,7 +556,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta return; } - bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_KERNEL | __GFP_NOFAIL), + bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), atomic_inc(&gl->gl_sbd->sd_bufdata_count); memset(bd, 0, sizeof(struct gfs2_bufdata)); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 1ccc2642682..c719a2a4069 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -189,7 +189,6 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) 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); diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index b8603783229..cf2e26e0724 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -688,7 +688,7 @@ static int gfs2_open(struct inode *inode, struct file *file) if (!fp) return -ENOMEM; - init_MUTEX(&fp->f_fl_mutex); + mutex_init(&fp->f_fl_mutex); fp->f_inode = ip; fp->f_vfile = file; @@ -858,7 +858,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) 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); + mutex_lock(&fp->f_fl_mutex); gl = fl_gh->gh_gl; if (gl) { @@ -890,7 +890,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) } out: - up(&fp->f_fl_mutex); + mutex_unlock(&fp->f_fl_mutex); return error; } @@ -900,11 +900,11 @@ 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); + mutex_lock(&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); + mutex_unlock(&fp->f_fl_mutex); } /** diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 80d5582d9d9..751178ab497 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -59,29 +59,29 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) 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); + mutex_init(&sdp->sd_invalidate_inodes_mutex); - init_MUTEX(&sdp->sd_inum_mutex); + mutex_init(&sdp->sd_inum_mutex); spin_lock_init(&sdp->sd_statfs_spin); - init_MUTEX(&sdp->sd_statfs_mutex); + mutex_init(&sdp->sd_statfs_mutex); spin_lock_init(&sdp->sd_rindex_spin); - init_MUTEX(&sdp->sd_rindex_mutex); + mutex_init(&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); + mutex_init(&sdp->sd_jindex_mutex); INIT_LIST_HEAD(&sdp->sd_unlinked_list); spin_lock_init(&sdp->sd_unlinked_spin); - init_MUTEX(&sdp->sd_unlinked_mutex); + mutex_init(&sdp->sd_unlinked_mutex); INIT_LIST_HEAD(&sdp->sd_quota_list); spin_lock_init(&sdp->sd_quota_spin); - init_MUTEX(&sdp->sd_quota_mutex); + mutex_init(&sdp->sd_quota_mutex); spin_lock_init(&sdp->sd_log_lock); init_waitqueue_head(&sdp->sd_log_trans_wq); @@ -99,12 +99,12 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_ail1_list); INIT_LIST_HEAD(&sdp->sd_ail2_list); - init_MUTEX(&sdp->sd_log_flush_lock); + mutex_init(&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); + mutex_init(&sdp->sd_freeze_lock); return sdp; } diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index e06ef8dbd4d..9130d0d0df3 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -74,10 +74,10 @@ static void gfs2_put_super(struct super_block *sb) /* Unfreeze the filesystem, if we need to */ - down(&sdp->sd_freeze_lock); + mutex_lock(&sdp->sd_freeze_lock); if (sdp->sd_freeze_count) gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); - up(&sdp->sd_freeze_lock); + mutex_unlock(&sdp->sd_freeze_lock); kthread_stop(sdp->sd_inoded_process); kthread_stop(sdp->sd_quotad_process); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 7b5573946f1..c0352cf330a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -251,10 +251,10 @@ static int bh_get(struct gfs2_quota_data *qd) struct buffer_head *bh; int error; - down(&sdp->sd_quota_mutex); + mutex_lock(&sdp->sd_quota_mutex); if (qd->qd_bh_count++) { - up(&sdp->sd_quota_mutex); + mutex_unlock(&sdp->sd_quota_mutex); return 0; } @@ -276,7 +276,7 @@ static int bh_get(struct gfs2_quota_data *qd) (bh->b_data + sizeof(struct gfs2_meta_header) + offset * sizeof(struct gfs2_quota_change)); - up(&sdp->sd_quota_mutex); + mutex_lock(&sdp->sd_quota_mutex); return 0; @@ -285,7 +285,7 @@ static int bh_get(struct gfs2_quota_data *qd) fail: qd->qd_bh_count--; - up(&sdp->sd_quota_mutex); + mutex_unlock(&sdp->sd_quota_mutex); return error; } @@ -293,14 +293,14 @@ static void bh_put(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - down(&sdp->sd_quota_mutex); + mutex_lock(&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); + mutex_unlock(&sdp->sd_quota_mutex); } static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) @@ -529,7 +529,7 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) struct gfs2_quota_change *qc = qd->qd_bh_qc; int64_t x; - down(&sdp->sd_quota_mutex); + mutex_lock(&sdp->sd_quota_mutex); gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1); if (!test_bit(QDF_CHANGE, &qd->qd_flags)) { @@ -560,7 +560,7 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) slot_hold(qd); } - up(&sdp->sd_quota_mutex); + mutex_unlock(&sdp->sd_quota_mutex); } /** diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 758cc565813..2e69e5cda96 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -182,9 +182,9 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp) void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) { - down(&sdp->sd_rindex_mutex); + mutex_lock(&sdp->sd_rindex_mutex); clear_rgrpdi(sdp); - up(&sdp->sd_rindex_mutex); + mutex_unlock(&sdp->sd_rindex_mutex); } /** @@ -301,7 +301,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) if (!rgd) goto fail; - init_MUTEX(&rgd->rd_mutex); + mutex_init(&rgd->rd_mutex); lops_init_le(&rgd->rd_le, &gfs2_rg_lops); rgd->rd_sbd = sdp; @@ -363,13 +363,13 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) /* 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); + mutex_lock(&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); + mutex_unlock(&sdp->sd_rindex_mutex); } return error; @@ -394,13 +394,13 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) unsigned int x, y; int error; - down(&rgd->rd_mutex); + mutex_lock(&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); + mutex_unlock(&rgd->rd_mutex); return 0; } spin_unlock(&sdp->sd_rindex_spin); @@ -436,7 +436,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) rgd->rd_bh_count++; spin_unlock(&sdp->sd_rindex_spin); - up(&rgd->rd_mutex); + mutex_unlock(&rgd->rd_mutex); return 0; @@ -447,7 +447,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) bi->bi_bh = NULL; gfs2_assert_warn(sdp, !bi->bi_clone); } - up(&rgd->rd_mutex); + mutex_unlock(&rgd->rd_mutex); return error; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 9b5c31952c5..be80771c414 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -279,7 +279,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) name.name = buf; - down(&sdp->sd_jindex_mutex); + mutex_lock(&sdp->sd_jindex_mutex); for (;;) { error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, @@ -317,7 +317,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) spin_unlock(&sdp->sd_jindex_spin); } - up(&sdp->sd_jindex_mutex); + mutex_unlock(&sdp->sd_jindex_mutex); return error; } @@ -608,9 +608,9 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, if (error) return; - down(&sdp->sd_statfs_mutex); + mutex_lock(&sdp->sd_statfs_mutex); gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); - up(&sdp->sd_statfs_mutex); + mutex_unlock(&sdp->sd_statfs_mutex); spin_lock(&sdp->sd_statfs_spin); l_sc->sc_total += total; @@ -659,9 +659,9 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) if (error) goto out_bh2; - down(&sdp->sd_statfs_mutex); + mutex_lock(&sdp->sd_statfs_mutex); gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); - up(&sdp->sd_statfs_mutex); + mutex_unlock(&sdp->sd_statfs_mutex); spin_lock(&sdp->sd_statfs_spin); m_sc->sc_total += l_sc->sc_total; @@ -910,7 +910,7 @@ int gfs2_freeze_fs(struct gfs2_sbd *sdp) { int error = 0; - down(&sdp->sd_freeze_lock); + mutex_lock(&sdp->sd_freeze_lock); if (!sdp->sd_freeze_count++) { error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh); @@ -918,7 +918,7 @@ int gfs2_freeze_fs(struct gfs2_sbd *sdp) sdp->sd_freeze_count--; } - up(&sdp->sd_freeze_lock); + mutex_unlock(&sdp->sd_freeze_lock); return error; } @@ -935,11 +935,11 @@ int gfs2_freeze_fs(struct gfs2_sbd *sdp) void gfs2_unfreeze_fs(struct gfs2_sbd *sdp) { - down(&sdp->sd_freeze_lock); + mutex_lock(&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); + mutex_unlock(&sdp->sd_freeze_lock); } diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 75e9a3231b8..c5984351e4d 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -41,9 +41,9 @@ static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) { unsigned int count; - down(&sdp->sd_freeze_lock); + mutex_lock(&sdp->sd_freeze_lock); count = sdp->sd_freeze_count; - up(&sdp->sd_freeze_lock); + mutex_unlock(&sdp->sd_freeze_lock); return sprintf(buf, "%u\n", count); } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 104e664fa18..0a0ea70eac4 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -33,7 +33,7 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, return -EINVAL; } - tr = kzalloc(sizeof(struct gfs2_trans), GFP_KERNEL); + tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS); if (!tr) return -ENOMEM; @@ -51,7 +51,7 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, error = -ENOMEM; tr->tr_t_gh = gfs2_holder_get(sdp->sd_trans_gl, LM_ST_SHARED, - GL_NEVER_RECURSE, GFP_KERNEL); + GL_NEVER_RECURSE, GFP_NOFS); if (!tr->tr_t_gh) goto fail; diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 405b91b0295..e92a3a11815 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -46,12 +46,12 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, goto out; } - down(&sdp->sd_unlinked_mutex); + 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)); - up(&sdp->sd_unlinked_mutex); + mutex_unlock(&sdp->sd_unlinked_mutex); out: brelse(bh); -- GitLab From 13538b8e46022b6a3721cda097fe3e0d91f16959 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 22 Feb 2006 11:15:03 +0000 Subject: [PATCH 0043/1619] [GFS2] Add list empty test to databuf_lo_add Heinz had spotted that I'd forgotten to test in databuf_lo_add() that the data buffer in question hadn't already been added to the list. This was causing an infinite loop later on in the "before commit" routine. This means that GFS2 is now ready to be tested by everybody. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 5e7e7d91fc5..ef39fb2e723 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -291,7 +291,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) while (!list_empty(head)) { rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list); - list_del(&rv->rv_le.le_list); + list_del_init(&rv->rv_le.le_list); sdp->sd_log_num_revoke--; if (offset + sizeof(uint64_t) > sdp->sd_sb.sb_bsize) { @@ -460,10 +460,12 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_pin(sdp, 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); + if (!list_empty(&le->le_list)) { + 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); } @@ -503,25 +505,21 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) unsigned int total_jdata = sdp->sd_log_num_jdata; unsigned int num, n; __be64 *ptr = NULL; - unsigned i; offset += (2*sizeof(__be64) - 1); offset &= ~(2*sizeof(__be64) - 1); limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64); - /* 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 */ gfs2_log_lock(sdp); - /* printk(KERN_INFO "locked in lops databuf_before_commit\n"); */ 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; - /* printk(KERN_INFO "total_dbuf=%u num=%u\n", total_dbuf, num); */ n = 0; i = 0; list_for_each_entry_safe_continue(bd1, bdt, &sdp->sd_log_le_databuf, bd_le.le_list) { @@ -542,21 +540,12 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) gfs2_log_lock(sdp); } brelse(bd1->bd_bh); - /* printk(KERN_INFO "db write %p\n", bd1); */ - if (++i > 100000) { - printk(KERN_INFO "looping bd1=%p bdt=%p eol=%p started=%p\n", bd1, bdt, &sdp->sd_log_le_databuf, &started); - dump_stack(); - BUG(); - } continue; } - /* printk(KERN_INFO "db skip\n"); */ continue; } else if (bd1->bd_bh) { /* A journaled buffer */ int magic; gfs2_log_unlock(sdp); - printk(KERN_INFO "journaled buffer %p\n", bd1->bd_bh); - printk(KERN_INFO "%lu %u %p %p\n", bd1->bd_bh->b_blocknr, bd1->bd_bh->b_size, bd1->bd_bh->b_data, bd1->bd_bh->b_page); if (!bh) { bh = gfs2_log_get_buf(sdp); ld = (struct gfs2_log_descriptor *)bh->b_data; @@ -570,12 +559,9 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) ld->ld_data2 = cpu_to_be32(0); memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); } - /* printk(KERN_INFO "check_magic\n"); */ magic = gfs2_check_magic(bd1->bd_bh); - /* printk(KERN_INFO "write data\n"); */ *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr); *ptr++ = cpu_to_be64((__u64)magic); - /* printk(KERN_INFO "mark escaped or not\n"); */ clear_buffer_escaped(bd1->bd_bh); if (unlikely(magic != 0)) set_buffer_escaped(bd1->bd_bh); @@ -591,7 +577,6 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) bh = NULL; } n = 0; - /* printk(KERN_INFO "totals2: jdata=%u dbuf=%u\n", total_jdata, total_dbuf); */ gfs2_log_lock(sdp); list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf, bd_le.le_list) { if (!bd2->bd_bh) @@ -621,14 +606,13 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } gfs2_log_unlock(sdp); - /* printk(KERN_INFO "wait on ordered data buffers\n"); */ /* Wait on all ordered buffers */ while (!list_empty(&started)) { + gfs2_log_lock(sdp); 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 = bd1->bd_bh; if (bh) { set_v2bd(bh, NULL); @@ -641,7 +625,6 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) 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); } -- GitLab From 91ffd7db71e7451f89941a8f428b4daa2a7c1e38 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 22 Feb 2006 16:41:45 +0000 Subject: [PATCH 0044/1619] [GFS2] Missed deletion of debugging code One line which should have been deleted in the last patch was missed. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index ef39fb2e723..3d792f81e48 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -521,7 +521,6 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) if (num > limit) num = limit; n = 0; - i = 0; list_for_each_entry_safe_continue(bd1, bdt, &sdp->sd_log_le_databuf, bd_le.le_list) { /* An ordered write buffer */ if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) { -- GitLab From 3bcd3687f895f178fa8480a7bcc47a363817354a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 23 Feb 2006 09:56:38 +0000 Subject: [PATCH 0045/1619] [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(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 5080bbffd58..49deca845db 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 899d4f92a4d..99d8b6b07fb 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 16f20cfd919..c3299020c8f 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 29d3b95dbb6..80487703d58 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 0b9851d0bdb..f7cf4589fae 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 7b235132b0b..6ead158ccc5 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 4c5c08a8860..55fbe313340 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 826d122edf5..767197db994 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 dd324ba44d8..1b1dcb9a40b 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 5e17d295544..f8ba1981aa9 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; -- GitLab From 8d3b35a4af87965d1873872b21e504558f62116a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 23 Feb 2006 10:00:56 +0000 Subject: [PATCH 0046/1619] [DLM] Remove support for range locks (II) This is the second of two patches removing support for range locks from the DLM Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/lock.c | 10 +++++----- fs/gfs2/locking/dlm/lock_dlm.h | 2 +- fs/gfs2/locking/dlm/thread.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index d799865b64a..666d696dc8c 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -223,7 +223,7 @@ void gdlm_put_lock(lm_lock_t *lock) gdlm_delete_lp((struct gdlm_lock *) lock); } -unsigned int gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) +unsigned int gdlm_do_lock(struct gdlm_lock *lp) { struct gdlm_ls *ls = lp->ls; struct gdlm_strname str; @@ -258,7 +258,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf, str.name, str.namelen, 0, gdlm_ast, (void *) lp, - bast ? gdlm_bast : NULL, range); + bast ? gdlm_bast : NULL); if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) { lp->lksb.sb_status = -EAGAIN; @@ -316,7 +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); - return gdlm_do_lock(lp, NULL); + return gdlm_do_lock(lp); } unsigned int gdlm_unlock(lm_lock_t *lock, unsigned int cur_state) @@ -425,7 +425,7 @@ static int hold_null_lock(struct gdlm_lock *lp) set_bit(LFL_INLOCK, &lpn->flags); init_completion(&lpn->ast_wait); - gdlm_do_lock(lpn, NULL); + gdlm_do_lock(lpn); wait_for_completion(&lpn->ast_wait); error = lp->lksb.sb_status; if (error) { @@ -499,7 +499,7 @@ void gdlm_sync_lvb(lm_lock_t *lock, char *lvb) lp->req = DLM_LOCK_EX; lp->lkf = make_flags(lp, 0, lp->cur, lp->req); - gdlm_do_lock(lp, NULL); + gdlm_do_lock(lp); wait_for_completion(&lp->ast_wait); } diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index fa545f7872e..6d76146953c 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -165,7 +165,7 @@ 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_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 **); diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 6fe669cd334..3e2edcc2dbf 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -308,7 +308,7 @@ static int gdlm_thread(void *data) process_blocking(lp, blocking); else if (submit) - gdlm_do_lock(lp, NULL); + gdlm_do_lock(lp); if (drop) ls->fscb(ls->fsdata, LM_CB_DROPLOCKS, NULL); -- GitLab From 6a6b3d018f4781f108d170f2181281a3c5589dc8 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 23 Feb 2006 10:11:47 +0000 Subject: [PATCH 0047/1619] [GFS2] Patch to remove stats gathering from GFS2 Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 23 ++------------ fs/gfs2/incore.h | 20 ------------ fs/gfs2/log.c | 4 --- fs/gfs2/meta_io.c | 3 -- fs/gfs2/ops_address.c | 12 ------- fs/gfs2/ops_dentry.c | 2 -- fs/gfs2/ops_export.c | 12 ------- fs/gfs2/ops_file.c | 29 ++--------------- fs/gfs2/ops_inode.c | 36 --------------------- fs/gfs2/ops_super.c | 17 ---------- fs/gfs2/ops_vm.c | 4 --- fs/gfs2/sys.c | 74 ++++--------------------------------------- 12 files changed, 10 insertions(+), 226 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 4df78ecfeeb..cf1dc17faf4 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -106,8 +106,6 @@ static void glock_free(struct gfs2_glock *gl) gfs2_aspace_put(aspace); kmem_cache_free(gfs2_glock_cachep, gl); - - atomic_dec(&sdp->sd_glock_count); } /** @@ -316,8 +314,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, if (error) goto fail_aspace; - atomic_inc(&sdp->sd_glock_count); - write_lock(&bucket->hb_lock); tmp = search_bucket(bucket, &name); if (tmp) { @@ -836,13 +832,10 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) held2 = (new_state != LM_ST_UNLOCKED); if (held1 != held2) { - if (held2) { - atomic_inc(&sdp->sd_glock_held_count); + if (held2) gfs2_glock_hold(gl); - } else { - atomic_dec(&sdp->sd_glock_held_count); + else gfs2_glock_put(gl); - } } gl->gl_state = new_state; @@ -994,8 +987,6 @@ void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags) 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); @@ -1087,8 +1078,6 @@ void gfs2_glock_drop_th(struct gfs2_glock *gl) 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))) @@ -1313,8 +1302,6 @@ int gfs2_glock_nq(struct gfs2_holder *gh) 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); @@ -1406,8 +1393,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh) 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); @@ -1469,8 +1454,6 @@ void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags) spin_unlock(&gl->gl_spin); glops->go_xmote_th(gl, state, flags); - - atomic_inc(&gl->gl_sbd->sd_glock_prefetch_calls); } /** @@ -1916,8 +1899,6 @@ 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); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 7fe422537ff..0e550e8e5be 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -667,27 +667,7 @@ struct gfs2_sbd { 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]; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index e6acb41332e..2483f0c2c50 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -408,8 +408,6 @@ static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) 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); @@ -488,8 +486,6 @@ 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_NOFS | __GFP_NOFAIL); INIT_LIST_HEAD(&ai->ai_ail1_list); INIT_LIST_HEAD(&ai->ai_ail2_list); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 8fba8430675..f4c4dfbf698 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -146,7 +146,6 @@ static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) 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); } @@ -557,8 +556,6 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta } bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), - atomic_inc(&gl->gl_sbd->sd_bufdata_count); - memset(bd, 0, sizeof(struct gfs2_bufdata)); bd->bd_bh = bh; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index c719a2a4069..8f839120a47 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -166,7 +166,6 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) 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; @@ -265,8 +264,6 @@ static int gfs2_readpage(struct file *file, struct page *page) struct gfs2_holder gh; int error; - atomic_inc(&sdp->sd_ops_address); - if (file != &gfs2_internal_file_sentinal) { gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); error = gfs2_glock_nq_m_atime(1, &gh); @@ -319,8 +316,6 @@ static int gfs2_prepare_write(struct file *file, struct page *page, loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; struct gfs2_alloc *al; - atomic_inc(&sdp->sd_ops_address); - 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) @@ -412,9 +407,6 @@ static int gfs2_commit_write(struct file *file, struct page *page, 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; @@ -493,8 +485,6 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) 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; @@ -615,8 +605,6 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, struct gfs2_inode *ip = get_v2ip(inode); struct gfs2_sbd *sdp = ip->i_sbd; - atomic_inc(&sdp->sd_ops_address); - 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 5c618611c11..fb8f70d225b 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -45,8 +45,6 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) lock_kernel(); - atomic_inc(&sdp->sd_ops_dentry); - inode = dentry->d_inode; if (inode && is_bad_inode(inode)) goto invalid; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 8389f771d28..611252b7a0d 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -32,8 +32,6 @@ static struct dentry *gfs2_decode_fh(struct super_block *sb, { struct gfs2_inum this, parent; - atomic_inc(&get_v2sdp(sb)->sd_ops_export); - if (fh_type != fh_len) return NULL; @@ -66,8 +64,6 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, 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; @@ -139,8 +135,6 @@ static int gfs2_get_name(struct dentry *parent, char *name, if (!dir) return -EINVAL; - atomic_inc(&get_v2sdp(dir->i_sb)->sd_ops_export); - if (!S_ISDIR(dir->i_mode) || !inode) return -EINVAL; @@ -173,8 +167,6 @@ static struct dentry *gfs2_get_parent(struct dentry *child) struct dentry *dentry; int error; - atomic_inc(&dip->i_sbd->sd_ops_export); - error = gfs2_lookupi(child->d_inode, &dotdot, 1, &inode); if (error) return ERR_PTR(error); @@ -199,8 +191,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) struct dentry *dentry; int error; - atomic_inc(&sdp->sd_ops_export); - /* System files? */ inode = gfs2_iget(sb, inum); @@ -256,8 +246,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) goto fail; } - atomic_inc(&sdp->sd_fh2dentry_misses); - out_ip: error = -EIO; if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) { diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index cf2e26e0724..0f80e930601 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -129,8 +129,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) 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); @@ -278,8 +276,6 @@ static ssize_t gfs2_read(struct file *filp, char __user *buf, size_t size, struct kiocb kiocb; ssize_t ret; - atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - init_sync_kiocb(&kiocb, filp); ret = __gfs2_file_aio_read(&kiocb, &local_iov, 1, offset); if (-EIOCBQUEUED == ret) @@ -293,8 +289,6 @@ static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, struct kiocb kiocb; ssize_t ret; - atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - init_sync_kiocb(&kiocb, filp); ret = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); if (-EIOCBQUEUED == ret) @@ -308,8 +302,6 @@ static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, struct file *filp = iocb->ki_filp; struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - BUG_ON(iocb->ki_pos != pos); return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); } @@ -529,8 +521,6 @@ 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 @@ -539,7 +529,8 @@ 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) +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; @@ -618,8 +609,6 @@ static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, { struct gfs2_inode *ip = get_v2ip(inode); - atomic_inc(&ip->i_sbd->sd_ops_file); - switch (cmd) { case GFS2_IOCTL_SETFLAGS: case GFS2_IOCTL_GETFLAGS: @@ -644,8 +633,6 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) 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) { @@ -682,8 +669,6 @@ static int gfs2_open(struct inode *inode, struct file *file) 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; @@ -741,8 +726,6 @@ 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); @@ -766,7 +749,6 @@ 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; @@ -789,8 +771,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) { .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) @@ -839,9 +819,6 @@ 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); - - atomic_inc(&ip->i_sbd->sd_ops_file); - return generic_file_sendfile(in_file, offset, count, actor, target); } @@ -921,8 +898,6 @@ 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) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 9fb9490eb67..9971a30eb78 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -56,8 +56,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, int new = 1; int error; - atomic_inc(&sdp->sd_ops_inode); - gfs2_holder_init(dip->i_gl, 0, 0, ghs); for (;;) { @@ -113,8 +111,6 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int error; - atomic_inc(&sdp->sd_ops_inode); - if (!sdp->sd_args.ar_localcaching) dentry->d_op = &gfs2_dops; @@ -152,8 +148,6 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, int alloc_required; int error; - atomic_inc(&sdp->sd_ops_inode); - if (S_ISDIR(ip->i_di.di_mode)) return -EPERM; @@ -287,8 +281,6 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) struct gfs2_holder ghs[2]; int error; - atomic_inc(&sdp->sd_ops_inode); - error = gfs2_unlinked_get(sdp, &ul); if (error) return error; @@ -345,8 +337,6 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, 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) @@ -405,8 +395,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) struct buffer_head *dibh; int error; - atomic_inc(&sdp->sd_ops_inode); - gfs2_holder_init(dip->i_gl, 0, 0, ghs); inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode); @@ -487,8 +475,6 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) struct gfs2_holder ghs[2]; int error; - atomic_inc(&sdp->sd_ops_inode); - error = gfs2_unlinked_get(sdp, &ul); if (error) return error; @@ -556,8 +542,6 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, uint32_t major = 0, minor = 0; int error; - atomic_inc(&sdp->sd_ops_inode); - switch (mode & S_IFMT) { case S_IFBLK: case S_IFCHR: @@ -631,8 +615,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, unsigned int x; int error; - atomic_inc(&sdp->sd_ops_inode); - if (ndentry->d_inode) { nip = get_v2ip(ndentry->d_inode); if (ip == nip) @@ -871,8 +853,6 @@ static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, 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; @@ -909,8 +889,6 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) 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); @@ -936,8 +914,6 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) 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); @@ -1053,8 +1029,6 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) 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; @@ -1102,8 +1076,6 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, 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); @@ -1119,8 +1091,6 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, 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) @@ -1140,8 +1110,6 @@ static ssize_t gfs2_getxattr(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) @@ -1157,8 +1125,6 @@ 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; @@ -1170,8 +1136,6 @@ 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) diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 9130d0d0df3..cd45ec93a04 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -46,8 +46,6 @@ 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) @@ -70,8 +68,6 @@ static void gfs2_put_super(struct super_block *sb) if (!sdp) return; - atomic_inc(&sdp->sd_ops_super); - /* Unfreeze the filesystem, if we need to */ mutex_lock(&sdp->sd_freeze_lock); @@ -156,7 +152,6 @@ 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); - atomic_inc(&sdp->sd_ops_super); gfs2_log_flush(sdp); } @@ -171,8 +166,6 @@ 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) @@ -202,8 +195,6 @@ 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); - - atomic_inc(&sdp->sd_ops_super); gfs2_unfreeze_fs(sdp); } @@ -221,8 +212,6 @@ static int gfs2_statfs(struct super_block *sb, struct kstatfs *buf) 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 @@ -259,8 +248,6 @@ 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; @@ -298,8 +285,6 @@ 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; @@ -324,8 +309,6 @@ 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]) diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 8f77bb7896b..808110e3ec5 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -48,8 +48,6 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, 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; @@ -149,8 +147,6 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, 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; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c5984351e4d..f87df8ec041 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -319,85 +319,23 @@ struct counters_attr { ssize_t (*show)(struct gfs2_sbd *, char *); }; -#define COUNTERS_ATTR_GENERAL(name, fmt, val) \ +#define COUNTERS_ATTR(name, fmt) \ static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ { \ - return sprintf(buf, fmt, val); \ + return sprintf(buf, fmt, (unsigned int)atomic_read(&sdp->sd_##name)); \ } \ 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"); +COUNTERS_ATTR(glock_count, "%u\n"); +COUNTERS_ATTR(glock_held_count, "%u\n"); +COUNTERS_ATTR(inode_count, "%u\n"); +COUNTERS_ATTR(reclaimed, "%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 }; -- GitLab From d95cb943f5b217c5b5f97f5af0fea3c511ed9c97 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 23 Feb 2006 10:13:13 +0000 Subject: [PATCH 0048/1619] [GFS2] Patch to remove stats counters from GFS2 (II) Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 2 -- fs/gfs2/ops_dentry.c | 1 - fs/gfs2/ops_export.c | 1 - fs/gfs2/ops_file.c | 2 -- 4 files changed, 6 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index cf1dc17faf4..d4fa395ed39 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -825,7 +825,6 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int 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); @@ -1390,7 +1389,6 @@ int gfs2_glock_wait(struct gfs2_holder *gh) 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; if (gh->gh_flags & GL_SYNC) diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index fb8f70d225b..b020ad8f180 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -35,7 +35,6 @@ 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; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 611252b7a0d..60d00640255 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -161,7 +161,6 @@ static int gfs2_get_name(struct dentry *parent, char *name, 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 inode *inode; struct dentry *dentry; diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 0f80e930601..989f0f70fc2 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -299,7 +299,6 @@ static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) { - struct file *filp = iocb->ki_filp; struct iovec local_iov = { .iov_base = buf, .iov_len = count }; BUG_ON(iocb->ki_pos != pos); @@ -818,7 +817,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) 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); return generic_file_sendfile(in_file, offset, count, actor, target); } -- GitLab From 2fcb4a1278ec41508d76786f4c5d23bff3b378ee Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 24 Feb 2006 10:42:20 -0500 Subject: [PATCH 0049/1619] [GFS2] Update documentation Change from gfs2_mkfs to mkfs -t gfs2 in the documentation. Signed-off-by: Steven Whitehouse --- Documentation/filesystems/gfs2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt index 4a060d38bed..a20ba19e9fe 100644 --- a/Documentation/filesystems/gfs2.txt +++ b/Documentation/filesystems/gfs2.txt @@ -28,7 +28,7 @@ at the URL above. To use gfs as a local file system, no external clustering systems are needed, simply: - $ gfs2_mkfs -p lock_nolock -j 1 /dev/block_device + $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device $ mount -t gfs2 /dev/block_device /dir GFS2 is not on-disk compatible with previous versions of GFS. -- GitLab From d92a8d48085df863032110d9ccb221cde98d14e1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 10:57:14 -0500 Subject: [PATCH 0050/1619] [GFS2] Audit printk and kmalloc All printk calls now have KERN_ set where required and a couple of kmalloc(), memset(.., 0, ...) calls changed to kzalloc(). This is in response to comments from: Pekka Enberg and Eric Sesterhenn Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 52 +++++++++++++++++------------------ fs/gfs2/locking.c | 9 +++--- fs/gfs2/locking/dlm/lock.c | 7 +++-- fs/gfs2/locking/dlm/main.c | 4 +-- fs/gfs2/locking/dlm/plock.c | 13 +++++---- fs/gfs2/locking/nolock/main.c | 13 ++++----- fs/gfs2/ondisk.c | 10 +++---- fs/gfs2/ops_fstype.c | 4 +-- fs/gfs2/ops_super.c | 2 +- fs/gfs2/super.c | 16 +++++------ 10 files changed, 64 insertions(+), 66 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index d4fa395ed39..f30fde91d14 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2315,17 +2315,17 @@ static int dump_holder(char *str, struct gfs2_holder *gh) unsigned int x; int error = -ENOBUFS; - printk(" %s\n", str); - printk(" owner = %ld\n", + printk(KERN_INFO " %s\n", str); + printk(KERN_INFO " owner = %ld\n", (gh->gh_owner) ? (long)gh->gh_owner->pid : -1); - printk(" gh_state = %u\n", gh->gh_state); - printk(" gh_flags ="); + printk(KERN_INFO " gh_state = %u\n", gh->gh_state); + printk(KERN_INFO " 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 ="); + printk(KERN_INFO " error = %d\n", gh->gh_error); + printk(KERN_INFO " gh_iflags ="); for (x = 0; x < 32; x++) if (test_bit(x, &gh->gh_iflags)) printk(" %u", x); @@ -2348,17 +2348,17 @@ static int dump_inode(struct gfs2_inode *ip) unsigned int x; int error = -ENOBUFS; - printk(" Inode:\n"); - printk(" num = %llu %llu\n", + printk(KERN_INFO " Inode:\n"); + printk(KERN_INFO " 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 ="); + 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(" vnode = %s\n", (ip->i_vnode) ? "yes" : "no"); + printk(KERN_INFO " vnode = %s\n", (ip->i_vnode) ? "yes" : "no"); error = 0; @@ -2381,30 +2381,30 @@ static int dump_glock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); - printk("Glock (%u, %llu)\n", + printk(KERN_INFO "Glock (%u, %llu)\n", gl->gl_name.ln_type, gl->gl_name.ln_number); - printk(" gl_flags ="); + printk(KERN_INFO " 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", + printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref.refcount)); + printk(KERN_INFO " gl_state = %u\n", gl->gl_state); + printk(KERN_INFO " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no"); + printk(KERN_INFO " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no"); + printk(KERN_INFO " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); + printk(KERN_INFO " object = %s\n", (gl->gl_object) ? "yes" : "no"); + printk(KERN_INFO " le = %s\n", (list_empty(&gl->gl_le.le_list)) ? "no" : "yes"); - printk(" reclaim = %s\n", + printk(KERN_INFO " reclaim = %s\n", (list_empty(&gl->gl_reclaim)) ? "no" : "yes"); if (gl->gl_aspace) - printk(" aspace = %lu\n", + printk(KERN_INFO " aspace = %lu\n", gl->gl_aspace->i_mapping->nrpages); else - printk(" aspace = no\n"); - printk(" ail = %d\n", atomic_read(&gl->gl_ail_count)); + printk(KERN_INFO " aspace = no\n"); + printk(KERN_INFO " ail = %d\n", atomic_read(&gl->gl_ail_count)); if (gl->gl_req_gh) { error = dump_holder("Request", gl->gl_req_gh); if (error) @@ -2438,7 +2438,7 @@ static int dump_glock(struct gfs2_glock *gl) goto out; } else { error = -ENOBUFS; - printk(" Inode: busy\n"); + printk(KERN_INFO " Inode: busy\n"); } } diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 2d2f8fe5399..0f4c50ebcba 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -46,18 +46,17 @@ int gfs_register_lockproto(struct lm_lockops *proto) 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", + printk(KERN_INFO "GFS2: protocol %s already exists\n", proto->lm_proto_name); return -EEXIST; } } - lw = kmalloc(sizeof(struct lmh_wrapper), GFP_KERNEL); + lw = kzalloc(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); @@ -90,7 +89,7 @@ void gfs_unregister_lockproto(struct lm_lockops *proto) up(&lmh_lock); - printk("GFS2: can't unregister lock protocol %s\n", + printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n", proto->lm_proto_name); } @@ -136,7 +135,7 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, request_module(proto_name); goto retry; } - printk("GFS2: can't find protocol %s\n", proto_name); + printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name); error = -ENOENT; goto out; } diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 666d696dc8c..1799d2237e7 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -34,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,%llx\n", + printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n", lp->lockname.ln_type, lp->lockname.ln_number); return; } @@ -408,7 +408,7 @@ static int hold_null_lock(struct gdlm_lock *lp) int error; if (lp->hold_null) { - printk("lock_dlm: lvb already held\n"); + printk(KERN_INFO "lock_dlm: lvb already held\n"); return 0; } @@ -429,7 +429,8 @@ static int hold_null_lock(struct gdlm_lock *lp) wait_for_completion(&lpn->ast_wait); error = lp->lksb.sb_status; if (error) { - printk("lock_dlm: hold_null_lock dlm error %d\n", error); + printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n", + error); gdlm_delete_lp(lpn); lpn = NULL; } diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 2c13c916a35..1c0943de940 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -22,7 +22,7 @@ int __init init_lock_dlm(void) error = gfs_register_lockproto(&gdlm_ops); if (error) { - printk("lock_dlm: can't register protocol: %d\n", error); + printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n", error); return error; } @@ -42,7 +42,7 @@ int __init init_lock_dlm(void) gdlm_drop_count = GDLM_DROP_COUNT; gdlm_drop_period = GDLM_DROP_PERIOD; - printk("Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); + printk(KERN_INFO "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); return 0; } diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 382847205bc..f7ac5821def 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -83,7 +83,7 @@ int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, spin_lock(&ops_lock); if (!list_empty(&op->list)) { - printk("plock op on list\n"); + printk(KERN_INFO "plock op on list\n"); list_del(&op->list); } spin_unlock(&ops_lock); @@ -127,7 +127,7 @@ int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, spin_lock(&ops_lock); if (!list_empty(&op->list)) { - printk("punlock op on list\n"); + printk(KERN_INFO "punlock op on list\n"); list_del(&op->list); } spin_unlock(&ops_lock); @@ -162,7 +162,7 @@ int gdlm_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, spin_lock(&ops_lock); if (!list_empty(&op->list)) { - printk("plock_get op on list\n"); + printk(KERN_INFO "plock_get op on list\n"); list_del(&op->list); } spin_unlock(&ops_lock); @@ -242,7 +242,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, if (found) wake_up(&recv_wq); else - printk("gdlm dev_write no op %x %llx\n", info.fsid, + printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, info.number); return count; } @@ -285,13 +285,14 @@ int gdlm_plock_init(void) rv = misc_register(&plock_dev_misc); if (rv) - printk("gdlm_plock_init: misc_register failed %d", rv); + printk(KERN_INFO "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"); + printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed"); } diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index b716e336c07..7ede0906b2c 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -44,11 +44,10 @@ static int nolock_mount(char *table_name, char *host_data, sscanf(c, "%u", &jid); } - nl = kmalloc(sizeof(struct nolock_lockspace), GFP_KERNEL); + nl = kzalloc(sizeof(struct nolock_lockspace), GFP_KERNEL); if (!nl) return -ENOMEM; - memset(nl, 0, sizeof(struct nolock_lockspace)); nl->nl_lvb_size = min_lvb_size; lockstruct->ls_jid = jid; @@ -147,10 +146,8 @@ static int nolock_hold_lvb(lm_lock_t *lock, char **lvbp) struct nolock_lockspace *nl = (struct nolock_lockspace *)lock; int error = 0; - *lvbp = kmalloc(nl->nl_lvb_size, GFP_KERNEL); - if (*lvbp) - memset(*lvbp, 0, nl->nl_lvb_size); - else + *lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL); + if (!*lvbp) error = -ENOMEM; return error; @@ -246,11 +243,11 @@ int __init init_nolock(void) error = gfs_register_lockproto(&nolock_ops); if (error) { - printk("lock_nolock: can't register protocol: %d\n", error); + printk(KERN_WARNING "lock_nolock: can't register protocol: %d\n", error); return error; } - printk("Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__); + printk(KERN_INFO "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__); return 0; } diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 854b5049b8d..964abd2760f 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -17,7 +17,7 @@ #include "gfs2.h" #include -#define pv(struct, member, fmt) printk(" "#member" = "fmt"\n", struct->member); +#define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", struct->member); #define pa(struct, member, count) print_array(#member, struct->member, count); /** @@ -32,11 +32,11 @@ static void print_array(char *title, char *buf, int count) { int x; - printk(" %s =\n", title); + printk(KERN_INFO " %s =\n" KERN_INFO, title); for (x = 0; x < count; x++) { printk("%.2X ", (unsigned char)buf[x]); if (x % 16 == 15) - printk("\n"); + printk("\n" KERN_INFO); } if (x % 16) printk("\n"); @@ -338,7 +338,7 @@ void gfs2_dirent_print(struct gfs2_dirent *de, char *name) memset(buf, 0, GFS2_FNAMESIZE + 1); memcpy(buf, name, de->de_name_len); - printk(" name = %s\n", buf); + printk(KERN_INFO " name = %s\n", buf); } void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf) @@ -401,7 +401,7 @@ void gfs2_ea_header_print(struct gfs2_ea_header *ea, char *name) memset(buf, 0, GFS2_EA_MAX_NAME_LEN + 1); memcpy(buf, name, ea->ea_name_len); - printk(" name = %s\n", buf); + printk(KERN_INFO " name = %s\n", buf); } void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 751178ab497..a85f1a2676f 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -772,13 +772,13 @@ static int fill_super(struct super_block *sb, void *data, int silent) sdp = init_sbd(sb); if (!sdp) { - printk("GFS2: can't alloc struct gfs2_sbd\n"); + printk(KERN_WARNING "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"); + printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); goto fail; } diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index cd45ec93a04..48a94522406 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index be80771c414..60e26661872 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -94,7 +94,7 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) 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"); + printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n"); return -EINVAL; } @@ -110,11 +110,11 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) break; if (!gfs2_old_fs_formats[x]) { - printk("GFS2: code version (%u, %u) is incompatible " + printk(KERN_WARNING "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"); + printk(KERN_WARNING "GFS2: I don't know how to upgrade this FS\n"); return -EINVAL; } } @@ -125,23 +125,23 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) break; if (!gfs2_old_multihost_formats[x]) { - printk("GFS2: code version (%u, %u) is incompatible " + printk(KERN_WARNING "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"); + printk(KERN_WARNING "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 " + printk(KERN_WARNING "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 " + printk(KERN_INFO "GFS2: Use the \"upgrade\" mount option to upgrade " "the FS\n"); - printk("GFS2: See the manual for more details\n"); + printk(KERN_INFO "GFS2: See the manual for more details\n"); return -EINVAL; } -- GitLab From 3a8fe9be6c9794e55ac2253eab91d42b28a9dab6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 11:00:37 -0500 Subject: [PATCH 0051/1619] [GFS2] Use BUG_ON() rather then if (...) BUG(); This issue was raised by: Eric Sesterhenn Signed-off-by: Steven Whitehouse --- fs/gfs2/lm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index cc7442261b2..f86f11f3973 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -101,8 +101,8 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) va_end(args); fs_err(sdp, "about to withdraw from the cluster\n"); - if (sdp->sd_args.ar_debug) - BUG(); + BUG_ON(sdp->sd_args.ar_debug); + fs_err(sdp, "waiting for outstanding I/O\n"); -- GitLab From 568f4c9659a2225b0d29cf86feecbcf25c9045c8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 12:00:42 -0500 Subject: [PATCH 0052/1619] [GFS2] 80 Column audit of GFS2 Requested by: Prarit Bhargava Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 10 +++++--- fs/gfs2/dir.c | 30 ++++++++++++++++-------- fs/gfs2/eattr.c | 4 ++-- fs/gfs2/inode.c | 9 +++++--- fs/gfs2/inode.h | 3 ++- fs/gfs2/lm.c | 9 +++++--- fs/gfs2/log.c | 12 ++++++---- fs/gfs2/lops.c | 54 +++++++++++++++++++++++++++++-------------- fs/gfs2/lvb.c | 3 ++- fs/gfs2/meta_io.c | 6 +++-- fs/gfs2/meta_io.h | 3 ++- fs/gfs2/ondisk.c | 3 ++- fs/gfs2/ops_address.c | 6 +++-- fs/gfs2/ops_file.c | 6 +++-- fs/gfs2/ops_fstype.c | 6 +++-- fs/gfs2/ops_vm.c | 6 +++-- fs/gfs2/quota.c | 12 ++++++---- fs/gfs2/recovery.c | 3 ++- fs/gfs2/rgrp.c | 3 ++- fs/gfs2/super.c | 30 ++++++++++++++++-------- 20 files changed, 146 insertions(+), 72 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 4efcd8a39e9..e132d8a4100 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -129,7 +129,8 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, 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); + *(uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)) = + cpu_to_be64(block); ip->i_di.di_blocks++; } @@ -241,7 +242,9 @@ static int build_height(struct gfs2_inode *ip, int height) 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); + *(uint64_t *)(dibh->b_data + + sizeof(struct gfs2_dinode)) = + cpu_to_be64(block); ip->i_di.di_blocks++; } @@ -313,7 +316,8 @@ static int build_height(struct gfs2_inode *ip, int height) * */ -static void find_metapath(struct gfs2_inode *ip, uint64_t block, struct metapath *mp) +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; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 65871a2b460..56683788a6c 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -98,7 +98,8 @@ int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, 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); + 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)) { @@ -163,7 +164,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, if (gfs2_is_stuffed(ip) && offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) - return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset, size); + return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset, + size); if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; @@ -188,7 +190,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, if (!extlen) { new = 1; - error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + error = gfs2_block_map(ip, lblock, &new, &dblock, + &extlen); if (error) goto fail; error = -EIO; @@ -196,7 +199,9 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, goto fail; } - error = gfs2_dir_get_buffer(ip, dblock, (amount == sdp->sd_jbsize) ? 1 : new, &bh); + error = gfs2_dir_get_buffer(ip, dblock, + (amount == sdp->sd_jbsize) ? + 1 : new, &bh); if (error) goto fail; @@ -280,7 +285,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, return 0; if (gfs2_is_stuffed(ip)) - return gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset, size); + return gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset, + size); if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; @@ -299,7 +305,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, if (!extlen) { new = 0; - error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + error = gfs2_block_map(ip, lblock, &new, &dblock, + &extlen); if (error) goto fail; } @@ -538,13 +545,15 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, if (dent->de_inum.no_addr) { new = (struct gfs2_dirent *)((char *)dent + - GFS2_DIRENT_SIZE(cur_name_len)); + 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_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->de_rec_len = cpu_to_be16(cur_rec_len - + be16_to_cpu(new->de_rec_len)); *dent_out = new; return 0; @@ -2281,7 +2290,8 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) error = gfs2_meta_inode_buffer(dip, &bh); if (!error) { gfs2_trans_add_bh(dip->i_gl, bh, 1); - ((struct gfs2_dinode *)bh->b_data)->di_mode = cpu_to_be32(S_IFREG); + ((struct gfs2_dinode *)bh->b_data)->di_mode = + cpu_to_be32(S_IFREG); brelse(bh); } diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 02e45c4ecbe..146995d9cd6 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -354,7 +354,6 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, return error; } -/******************************************************************************/ static int gfs2_ea_repack_i(struct gfs2_inode *ip) { @@ -819,7 +818,8 @@ static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) 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); + 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; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 30ca82a1add..51ecdb8503b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1034,8 +1034,10 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, gfs2_tune_get(sdp, gt_new_files_directio)) di->di_flags |= cpu_to_be32(GFS2_DIF_DIRECTIO); } else if (S_ISDIR(mode)) { - 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); + 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); } di->__pad1 = 0; @@ -1188,7 +1190,8 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, * Returns: An inode */ -struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) +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); diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 8ef85f5feb1..069f0e21db6 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -46,7 +46,8 @@ 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_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode); +struct inode *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, diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index f86f11f3973..3df8fa00442 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -80,7 +80,8 @@ int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) 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); + sdp->sd_lockstruct.ls_ops->lm_others_may_mount( + sdp->sd_lockstruct.ls_lockspace); } void gfs2_lm_unmount(struct gfs2_sbd *sdp) @@ -124,7 +125,8 @@ int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, 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); + error = sdp->sd_lockstruct.ls_ops->lm_get_lock( + sdp->sd_lockstruct.ls_lockspace, name, lockp); return error; } @@ -230,6 +232,7 @@ 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); + sdp->sd_lockstruct.ls_ops->lm_recovery_done( + sdp->sd_lockstruct.ls_lockspace, jid, message); } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 2483f0c2c50..0e31d46edd4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -74,10 +74,12 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, unsigned int first, second; blks = 1; - first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize; + 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; + second = (sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_meta_header)) / ssize; blks += DIV_RU(nstruct - first, second); } @@ -255,7 +257,8 @@ 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), lbn, &new, &dbn, NULL); + error = gfs2_block_map(get_v2ip(sdp->sd_jdesc->jd_inode), + lbn, &new, &dbn, NULL); gfs2_assert_withdraw(sdp, !error && dbn); return dbn; @@ -554,7 +557,8 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 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; + 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)); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 3d792f81e48..4bd89c0781e 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -137,7 +137,8 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) 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) { + 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; @@ -147,7 +148,8 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) ll_rw_block(WRITE, 1, &bh); n = 0; - list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, bd_le.le_list) { + 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); @@ -239,7 +241,8 @@ 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; if (error) { - gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, + DIO_START | DIO_WAIT); return; } if (pass != 1) @@ -283,7 +286,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) 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_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)); @@ -515,19 +519,24 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) * into the log along with a header */ gfs2_log_lock(sdp); - bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, bd_le.le_list); + 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) { + list_for_each_entry_safe_continue(bd1, bdt, + &sdp->sd_log_le_databuf, + bd_le.le_list) { /* 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); + bd2 = list_prepare_entry(bd2, + &sdp->sd_log_le_databuf, + bd_le.le_list); } total_dbuf--; if (bd1->bd_bh) { @@ -535,7 +544,8 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) if (buffer_dirty(bd1->bd_bh)) { gfs2_log_unlock(sdp); wait_on_buffer(bd1->bd_bh); - ll_rw_block(WRITE, 1, &bd1->bd_bh); + ll_rw_block(WRITE, 1, + &bd1->bd_bh); gfs2_log_lock(sdp); } brelse(bd1->bd_bh); @@ -547,12 +557,17 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) gfs2_log_unlock(sdp); if (!bh) { bh = gfs2_log_get_buf(sdp); - ld = (struct gfs2_log_descriptor *)bh->b_data; + 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_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); @@ -577,7 +592,8 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } n = 0; gfs2_log_lock(sdp); - list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf, bd_le.le_list) { + 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 */ @@ -587,7 +603,9 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) 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); + 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 { @@ -608,7 +626,8 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) /* Wait on all ordered buffers */ while (!list_empty(&started)) { gfs2_log_lock(sdp); - bd1 = list_entry(started.next, struct gfs2_bufdata, 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--; @@ -685,7 +704,8 @@ 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; if (error) { - gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, + DIO_START | DIO_WAIT); return; } if (pass != 1) diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c index 8af62568a3f..ca959ebb80c 100644 --- a/fs/gfs2/lvb.c +++ b/fs/gfs2/lvb.c @@ -16,7 +16,8 @@ #include "gfs2.h" -#define pv(struct, member, fmt) printk(" "#member" = "fmt"\n", struct->member); +#define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", \ + struct->member); void gfs2_quota_lvb_in(struct gfs2_quota_lvb *qb, char *lvb) { diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index f4c4dfbf698..53f33fa899f 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -542,7 +542,8 @@ int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) * @meta: Flag to indicate whether its metadata or not */ -void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta) +void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, + int meta) { struct gfs2_bufdata *bd; @@ -818,7 +819,8 @@ 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; + uint32_t max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> + sdp->sd_sb.sb_bsize_shift; int error; if (!extlen || !max_ra) diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 887cac302c1..d72144d5d72 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -64,7 +64,8 @@ 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_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); +void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, + int meta); 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); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 964abd2760f..5a0bdc22a1f 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -17,7 +17,8 @@ #include "gfs2.h" #include -#define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", struct->member); +#define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", \ + struct->member); #define pa(struct, member, count) print_array(#member, struct->member, count); /** diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 8f839120a47..89a8b8fad2e 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -357,7 +357,8 @@ static int gfs2_prepare_write(struct file *file, struct page *page, 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); + error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, + page); if (error == 0) goto prepare_write; } else if (!PageUptodate(page)) @@ -432,7 +433,8 @@ static int gfs2_commit_write(struct file *file, struct page *page, if (inode->i_size < file_size) i_size_write(inode, file_size); } else { - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + 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) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 989f0f70fc2..e6ae2551b0c 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -531,7 +531,8 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) 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; + unsigned int lmode = (cmd == GFS2_IOCTL_SETFLAGS) ? + LM_ST_EXCLUSIVE : LM_ST_SHARED; struct buffer_head *dibh; struct gfs2_holder i_gh; int error; @@ -559,7 +560,8 @@ static int gfs2_ioctl_flags(struct gfs2_inode *ip, unsigned int cmd, if (!S_ISREG(ip->i_di.di_mode)) goto out; } - if (flags & (GFS2_DIF_INHERIT_JDATA|GFS2_DIF_INHERIT_DIRECTIO)) { + if (flags & + (GFS2_DIF_INHERIT_JDATA|GFS2_DIF_INHERIT_DIRECTIO)) { if (!S_ISDIR(ip->i_di.di_mode)) goto out; } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index a85f1a2676f..535f020f1e0 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -128,7 +128,8 @@ static void init_vfs(struct gfs2_sbd *sdp) 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_shift = sdp->sd_sb.sb_bsize_shift - + GFS2_BASIC_BLOCK_SHIFT; sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; } @@ -435,7 +436,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, + error = gfs2_glock_nq_init( + get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, &sdp->sd_jinode_gh); diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 808110e3ec5..bfeb920dcce 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -68,7 +68,8 @@ 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); + 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; @@ -143,7 +144,8 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, 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; + unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + + area->vm_pgoff; int alloc_required; int error; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c0352cf330a..40c7cf87eb4 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -395,7 +395,8 @@ static int qd_trylock(struct gfs2_quota_data *qd) static void qd_unlock(struct gfs2_quota_data *qd) { - gfs2_assert_warn(qd->qd_gl->gl_sbd, test_bit(QDF_LOCKED, &qd->qd_flags)); + 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); @@ -715,7 +716,8 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) qd = qda[x]; offset = qd2offset(qd); error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, - (struct gfs2_quota_data *)qd->qd_gl->gl_lvb); + (struct gfs2_quota_data *) + qd->qd_gl->gl_lvb); if (error) goto out_end_trans; @@ -932,7 +934,8 @@ static int print_message(struct gfs2_quota_data *qd, char *type) if (!line) return -ENOMEM; - len = snprintf(line, MAX_LINE-1, "GFS2: fsid=%s: quota %s for %s %u\r\n", + 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); @@ -981,7 +984,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) } 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)) { + gfs2_tune_get(sdp, + gt_quota_warn_period) * HZ)) { error = print_message(qd, "warning"); qd->qd_last_warn = jiffies; } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index bcb81c768c8..e5f2b284fa5 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -33,7 +33,8 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, uint32_t extlen; int error; - error = gfs2_block_map(get_v2ip(jd->jd_inode), blk, &new, &dblock, &extlen); + error = gfs2_block_map(get_v2ip(jd->jd_inode), blk, &new, &dblock, + &extlen); if (error) return error; if (!dblock) { diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 2e69e5cda96..9525b176f50 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -233,7 +233,8 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) bi->bi_len = bytes; /* other blocks */ } else { - bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header); + 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; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 60e26661872..2c1c6aa1c07 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -110,36 +110,43 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) break; if (!gfs2_old_fs_formats[x]) { - printk(KERN_WARNING "GFS2: code version (%u, %u) is incompatible " + printk(KERN_WARNING + "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(KERN_WARNING "GFS2: I don't know how to upgrade this FS\n"); + printk(KERN_WARNING + "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) + if (gfs2_old_multihost_formats[x] == + sb->sb_multihost_format) break; if (!gfs2_old_multihost_formats[x]) { - printk(KERN_WARNING "GFS2: code version (%u, %u) is incompatible " + printk(KERN_WARNING + "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(KERN_WARNING "GFS2: I don't know how to upgrade this FS\n"); + printk(KERN_WARNING + "GFS2: I don't know how to upgrade this FS\n"); return -EINVAL; } } if (!sdp->sd_args.ar_upgrade) { - printk(KERN_WARNING "GFS2: code version (%u, %u) is incompatible " + printk(KERN_WARNING + "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(KERN_INFO "GFS2: Use the \"upgrade\" mount option to upgrade " + printk(KERN_INFO + "GFS2: Use the \"upgrade\" mount option to upgrade " "the FS\n"); printk(KERN_INFO "GFS2: See the manual for more details\n"); return -EINVAL; @@ -289,7 +296,8 @@ 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), &name, NULL, NULL); + error = gfs2_dir_search(get_v2ip(sdp->sd_jindex), + &name, NULL, NULL); if (error == -ENOENT) { error = 0; break; @@ -445,7 +453,8 @@ int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) sdp->sd_sb.sb_master_dir.no_addr, &gfs2_inode_glops, CREATE, &gl); if (!error) { - error = gfs2_lookup_simple(sdp->sd_root_dir, ".gfs2_admin", &inode); + error = gfs2_lookup_simple(sdp->sd_root_dir, ".gfs2_admin", + &inode); sdp->sd_master_dir = inode; gfs2_glock_put(gl); } @@ -854,7 +863,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, LM_ST_SHARED, 0, + error = gfs2_glock_nq_init(get_v2ip(jd->jd_inode)->i_gl, + LM_ST_SHARED, 0, &lfcc->gh); if (error) { kfree(lfcc); -- GitLab From f382894e8889a64f8daf747db477a16da2d54eb0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 12:07:05 -0500 Subject: [PATCH 0053/1619] [GFS2] 80 Column audit of locking modules Requested by: Prarit Bhargava Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/main.c | 6 ++++-- fs/gfs2/locking/nolock/main.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 1c0943de940..3c9adf18fd9 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -22,7 +22,8 @@ int __init init_lock_dlm(void) error = gfs_register_lockproto(&gdlm_ops); if (error) { - printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n", error); + printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n", + error); return error; } @@ -42,7 +43,8 @@ int __init init_lock_dlm(void) gdlm_drop_count = GDLM_DROP_COUNT; gdlm_drop_period = GDLM_DROP_PERIOD; - printk(KERN_INFO "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); + printk(KERN_INFO + "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); return 0; } diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 7ede0906b2c..57f9e50832f 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -243,11 +243,13 @@ int __init init_nolock(void) error = gfs_register_lockproto(&nolock_ops); if (error) { - printk(KERN_WARNING "lock_nolock: can't register protocol: %d\n", error); + printk(KERN_WARNING + "lock_nolock: can't register protocol: %d\n", error); return error; } - printk(KERN_INFO "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__); + printk(KERN_INFO + "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__); return 0; } -- GitLab From 116ad29d9839610d2811a1962cac7f3f2a9f9295 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 12:11:18 -0500 Subject: [PATCH 0054/1619] [GFS2] Remove pointless comment from nolock/main.c As requested by: Pavel Machek Pavel's other comments will be dealt with in later patches. Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/nolock/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 57f9e50832f..9398309f281 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -33,9 +33,6 @@ static int nolock_mount(char *table_name, char *host_data, unsigned int jid; struct nolock_lockspace *nl; - /* If there is a "jid=" in the hostdata, return that jid. - Otherwise, return zero. */ - c = strstr(host_data, "jid="); if (!c) jid = 0; -- GitLab From 5c676f6d359b0404d53f542f02e1359583cb2895 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 17:23:27 -0500 Subject: [PATCH 0055/1619] [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(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 9482a677ea4..e9d05fe9435 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 57d420a86ad..49585e3de09 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 e132d8a4100..cd5e4d863ce 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 cff8d5368d2..94317dc7e42 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 56683788a6c..37f70ca558c 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 2914731250c..4b9f6cff7a3 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 146995d9cd6..8219d471f06 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 e5a42abf68a..2b4152b1fcb 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 6c53d080675..57175f70e2b 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 f30fde91d14..81b06812b32 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 27374306ecd..d9334eb72df 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 0e550e8e5be..2443e9aad59 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 51ecdb8503b..ea9e996f367 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 3df8fa00442..5b3c56d2df2 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 0e31d46edd4..32a41a274bf 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 4bd89c0781e..430161a05a2 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 ca959ebb80c..63b815dad8e 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 ca9732b2d9f..1b9eb69b953 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 0c60f2b10fd..c5417779031 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 53f33fa899f..b85fa246466 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 3e42697aafc..e90ea7d32f9 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 89a8b8fad2e..01aa4a9b48c 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 b020ad8f180..7f613928851 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 60d00640255..d149584cff3 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 e6ae2551b0c..d30c6db4624 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 535f020f1e0..4c4115f9d96 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 9971a30eb78..7633a8584b0 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 48a94522406..10f70ee1216 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 bfeb920dcce..dbc57071e7b 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 3542aa6b01c..a2c9e93c7c3 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 40c7cf87eb4..c57b5cf1d58 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 e5f2b284fa5..2df450e2f43 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 9525b176f50..4ae55969439 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 2c1c6aa1c07..9ccf0b9c598 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 f87df8ec041..f05ba8f6913 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 0a0ea70eac4..2cce68aec13 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 e92a3a11815..24b91c23bc2 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 4fb1704aac1..8b22fa91bd1 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 ec432e0c208..8d4f0445df4 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 3b507bf05d0..f789278a625 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 */ -- GitLab From b3f58d8f2b1200f1b9abbcfb9dec6c25bc787469 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 28 Feb 2006 11:16:37 -0500 Subject: [PATCH 0056/1619] [DLM] Pass in lockspace to lkb put function In some cases a lockspace isn't attached to the lkb, so that it needs to be passed directly to the lkb put function. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 54 +++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 80487703d58..85a0e73ba80 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -591,9 +591,11 @@ static void kill_lkb(struct kref *kref) DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb);); } -static int put_lkb(struct dlm_lkb *lkb) +/* __put_lkb() is used when an lkb may not have an rsb attached to + it so we need to provide the lockspace explicitly */ + +static int __put_lkb(struct dlm_ls *ls, 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); @@ -616,7 +618,13 @@ static int put_lkb(struct dlm_lkb *lkb) int dlm_put_lkb(struct dlm_lkb *lkb) { - return put_lkb(lkb); + struct dlm_ls *ls; + + DLM_ASSERT(lkb->lkb_resource, dlm_print_lkb(lkb);); + DLM_ASSERT(lkb->lkb_resource->res_ls, dlm_print_lkb(lkb);); + + ls = lkb->lkb_resource->res_ls; + return __put_lkb(ls, lkb); } /* This is only called to add a reference when the code already holds @@ -1949,7 +1957,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, error = 0; out_put: if (convert || error) - put_lkb(lkb); + __put_lkb(ls, lkb); if (error == -EAGAIN) error = 0; out: @@ -1991,7 +1999,7 @@ int dlm_unlock(dlm_lockspace_t *lockspace, if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL) error = 0; out_put: - put_lkb(lkb); + dlm_put_lkb(lkb); out: unlock_recovery(ls); dlm_put_lockspace(ls); @@ -2442,7 +2450,7 @@ static void receive_request(struct dlm_ls *ls, struct dlm_message *ms) lkb->lkb_flags |= DLM_IFL_MSTCPY; error = receive_request_args(ls, lkb, ms); if (error) { - put_lkb(lkb); + __put_lkb(ls, lkb); goto fail; } @@ -2450,7 +2458,7 @@ static void receive_request(struct dlm_ls *ls, struct dlm_message *ms) error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r); if (error) { - put_lkb(lkb); + __put_lkb(ls, lkb); goto fail; } @@ -2466,7 +2474,7 @@ static void receive_request(struct dlm_ls *ls, struct dlm_message *ms) if (error == -EINPROGRESS) error = 0; if (error) - put_lkb(lkb); + dlm_put_lkb(lkb); return; fail: @@ -2502,7 +2510,7 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); - put_lkb(lkb); + dlm_put_lkb(lkb); return; fail: @@ -2536,7 +2544,7 @@ static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); - put_lkb(lkb); + dlm_put_lkb(lkb); return; fail: @@ -2566,7 +2574,7 @@ static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); - put_lkb(lkb); + dlm_put_lkb(lkb); return; fail: @@ -2598,7 +2606,7 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); - put_lkb(lkb); + dlm_put_lkb(lkb); } static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms) @@ -2623,7 +2631,7 @@ static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); - put_lkb(lkb); + dlm_put_lkb(lkb); } static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms) @@ -2746,7 +2754,7 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); out: - put_lkb(lkb); + dlm_put_lkb(lkb); } static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, @@ -2813,7 +2821,7 @@ static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms) _receive_convert_reply(lkb, ms); out: - put_lkb(lkb); + dlm_put_lkb(lkb); } static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms) @@ -2860,7 +2868,7 @@ static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms) _receive_unlock_reply(lkb, ms); out: - put_lkb(lkb); + dlm_put_lkb(lkb); } static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms) @@ -2907,7 +2915,7 @@ static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms) _receive_cancel_reply(lkb, ms); out: - put_lkb(lkb); + dlm_put_lkb(lkb); } static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms) @@ -2954,7 +2962,7 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms) unlock_rsb(r); put_rsb(r); out: - put_lkb(lkb); + dlm_put_lkb(lkb); } int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) @@ -3159,7 +3167,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) ls->ls_stub_ms.m_result = -DLM_EUNLOCK; _remove_from_waiters(lkb); _receive_unlock_reply(lkb, &ls->ls_stub_ms); - put_lkb(lkb); + dlm_put_lkb(lkb); break; case DLM_MSG_CANCEL: @@ -3167,7 +3175,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) ls->ls_stub_ms.m_result = -DLM_ECANCEL; _remove_from_waiters(lkb); _receive_cancel_reply(lkb, &ls->ls_stub_ms); - put_lkb(lkb); + dlm_put_lkb(lkb); break; default: @@ -3272,7 +3280,7 @@ static void purge_queue(struct dlm_rsb *r, struct list_head *queue, if (test(ls, lkb)) { del_lkb(r, lkb); /* this put should free the lkb */ - if (!put_lkb(lkb)) + if (!dlm_put_lkb(lkb)) log_error(ls, "purged lkb not released"); } } @@ -3456,7 +3464,7 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc) error = receive_rcom_lock_args(ls, lkb, r, rc); if (error) { - put_lkb(lkb); + __put_lkb(ls, lkb); goto out_unlock; } @@ -3518,7 +3526,7 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc) unlock_rsb(r); put_rsb(r); - put_lkb(lkb); + dlm_put_lkb(lkb); return 0; } -- GitLab From e317ffcb7cc26c5e80cab97160a5e2761a4436ec Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Mar 2006 11:39:37 -0500 Subject: [PATCH 0057/1619] [GFS2] Remove uneeded memory allocation For every filesystem operation where we need a transaction, we now make one less memory allocation. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- fs/gfs2/trans.c | 30 ++++++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 2443e9aad59..c741016d07d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -360,7 +360,7 @@ struct gfs2_trans { unsigned int tr_revokes; unsigned int tr_reserved; - struct gfs2_holder *tr_t_gh; + struct gfs2_holder tr_t_gh; int tr_touched; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 2cce68aec13..5d1f4a1e407 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -53,18 +53,15 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, 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_NOFS); - if (!tr->tr_t_gh) - goto fail; + gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, + GL_NEVER_RECURSE, &tr->tr_t_gh); - error = gfs2_glock_nq(tr->tr_t_gh); + error = gfs2_glock_nq(&tr->tr_t_gh); if (error) - goto fail_holder_put; + goto fail_holder_uninit; if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { - tr->tr_t_gh->gh_flags |= GL_NOCACHE; + tr->tr_t_gh.gh_flags |= GL_NOCACHE; error = -EROFS; goto fail_gunlock; } @@ -78,12 +75,10 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, return 0; fail_gunlock: - gfs2_glock_dq(tr->tr_t_gh); + gfs2_glock_dq(&tr->tr_t_gh); - fail_holder_put: - gfs2_holder_put(tr->tr_t_gh); - - fail: + fail_holder_uninit: + gfs2_holder_uninit(&tr->tr_t_gh); kfree(tr); return error; @@ -100,16 +95,15 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) if (gfs2_assert_warn(sdp, tr)) return; - t_gh = tr->tr_t_gh; - tr->tr_t_gh = NULL; + t_gh = &tr->tr_t_gh; if (!tr->tr_touched) { gfs2_log_release(sdp, tr->tr_reserved); - kfree(tr); gfs2_glock_dq(t_gh); - gfs2_holder_put(t_gh); + gfs2_holder_uninit(t_gh); + kfree(tr); return; } @@ -127,7 +121,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) gfs2_log_commit(sdp, tr); gfs2_glock_dq(t_gh); - gfs2_holder_put(t_gh); + gfs2_holder_uninit(t_gh); if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) gfs2_log_flush(sdp); -- GitLab From c9fd43078f5007c6ca6b3a9cd04c51a8f0e44a20 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Mar 2006 15:31:02 -0500 Subject: [PATCH 0058/1619] [GFS2] Tidy up mount code. We no longer lookup ".gfs2_admin" in the root directory in order to find it, but instead use the inode number given in the superblock. Both the root directory and the admin directory are now looked up using the same routine, so the redundant code is removed. Also, there is no longer a reference to the root inode in the GFS2 super block. When required this can be retreived via sb->s_root->d_inode instead. Assuming that we introduce a metadata filesystem type for GFS, then this is a first step towards that goal. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 1 - fs/gfs2/inode.c | 13 +++++++------ fs/gfs2/inode.h | 2 +- fs/gfs2/ops_export.c | 4 ++-- fs/gfs2/ops_fstype.c | 40 +++++++++++++++++----------------------- fs/gfs2/ops_super.c | 1 - fs/gfs2/super.c | 19 ------------------- fs/gfs2/super.h | 1 - 8 files changed, 27 insertions(+), 54 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index c741016d07d..62f109e553c 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -532,7 +532,6 @@ struct gfs2_sbd { struct inode *sd_qc_inode; struct inode *sd_rindex; struct inode *sd_quota_inode; - struct inode *sd_root_dir; /* Inum stuff */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index ea9e996f367..cd1de61bff2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -288,7 +288,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) * Returns: errno */ -static int inode_create(struct gfs2_glock *i_gl, struct gfs2_inum *inum, +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) { @@ -354,8 +354,8 @@ static int inode_create(struct gfs2_glock *i_gl, struct gfs2_inum *inum, * Returns: errno */ -int gfs2_inode_get(struct gfs2_glock *i_gl, struct gfs2_inum *inum, int create, - struct gfs2_inode **ipp) +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; @@ -718,6 +718,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, struct inode **inodep) { + 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; @@ -733,7 +734,7 @@ int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, return -ENAMETOOLONG; if (gfs2_filecmp(name, ".", 1) || - (gfs2_filecmp(name, "..", 2) && dir == sdp->sd_root_dir)) { + (gfs2_filecmp(name, "..", 2) && dir == sb->s_root->d_inode)) { gfs2_inode_hold(dip); ipp = dip; goto done; @@ -1466,8 +1467,8 @@ 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 gfs2_sbd *sdp = this->i_sbd; struct inode *dir = to->i_vnode; + struct super_block *sb = dir->i_sb; struct inode *tmp; struct qstr dotdot; int error = 0; @@ -1483,7 +1484,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) error = -EINVAL; break; } - if (dir == sdp->sd_root_dir) { + if (dir == sb->s_root->d_inode) { error = 0; break; } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 069f0e21db6..c3fa6cfce16 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -35,7 +35,7 @@ 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, + 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); diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index d149584cff3..a346943363c 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -64,8 +64,8 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, int connectable) { struct inode *inode = dentry->d_inode; + struct super_block *sb = inode->i_sb; struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; if (*len < 4 || (connectable && *len < 8)) return 255; @@ -80,7 +80,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[3] = cpu_to_be32(fh[3]); *len = 4; - if (!connectable || ip == sdp->sd_root_dir->u.generic_ip) + if (!connectable || inode == sb->s_root->d_inode) return *len; spin_lock(&dentry->d_lock); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 4c4115f9d96..c3b830bd838 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -280,27 +280,30 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, return error; } -int gfs2_lookup_root(struct gfs2_sbd *sdp) +static struct inode *gfs2_lookup_root(struct gfs2_sbd *sdp, + const struct gfs2_inum *inum) { int error; struct gfs2_glock *gl; struct gfs2_inode *ip; + struct inode *inode; - error = gfs2_glock_get(sdp, sdp->sd_sb.sb_root_dir.no_addr, + error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, CREATE, &gl); if (!error) { - error = gfs2_inode_get(gl, &sdp->sd_sb.sb_root_dir, + error = gfs2_inode_get(gl, inum, CREATE, &ip); if (!error) { if (!error) gfs2_inode_min_init(ip, DT_DIR); - sdp->sd_root_dir = gfs2_ip2v(ip); + inode = gfs2_ip2v(ip); gfs2_inode_put(ip); + return inode; } gfs2_glock_put(gl); } - return error; + return ERR_PTR(error); } static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) @@ -311,7 +314,6 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) int error = 0; if (undo) { - iput(sdp->sd_master_dir); return 0; } @@ -351,35 +353,24 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) sb_set_blocksize(sb, sdp->sd_sb.sb_bsize); /* Get the root inode */ - error = gfs2_lookup_root(sdp); - if (error) { + inode = gfs2_lookup_root(sdp, &sdp->sd_sb.sb_root_dir); + if (IS_ERR(inode)) { + error = PTR_ERR(inode); fs_err(sdp, "can't read in root inode: %d\n", error); goto out; } - /* Get the root inode/dentry */ - inode = sdp->sd_root_dir; - if (!inode) { - fs_err(sdp, "can't get root inode\n"); - error = -ENOMEM; - goto out_rooti; - } - - igrab(inode); sb->s_root = d_alloc_root(inode); if (!sb->s_root) { fs_err(sdp, "can't get root dentry\n"); error = -ENOMEM; - goto out_rooti; + iput(inode); } out: gfs2_glock_dq_uninit(&sb_gh); return error; -out_rooti: - iput(sdp->sd_root_dir); - goto out; } static int init_journal(struct gfs2_sbd *sdp, int undo) @@ -529,15 +520,18 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) { int error = 0; struct gfs2_inode *ip; + struct inode *inode; if (undo) goto fail_qinode; - error = gfs2_lookup_master_dir(sdp); - if (error) { + inode = gfs2_lookup_root(sdp, &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); goto fail; } + sdp->sd_master_dir = inode; error = init_journal(sdp, undo); if (error) diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 10f70ee1216..f7349c0989a 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -103,7 +103,6 @@ static void gfs2_put_super(struct super_block *sb) iput(sdp->sd_statfs_inode); iput(sdp->sd_rindex); iput(sdp->sd_quota_inode); - iput(sdp->sd_root_dir); gfs2_glock_put(sdp->sd_rename_gl); gfs2_glock_put(sdp->sd_trans_gl); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 9ccf0b9c598..fff5a96f415 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -447,25 +447,6 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd) return error; } -int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) -{ - struct inode *inode = NULL; - 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_lookup_simple(sdp->sd_root_dir, ".gfs2_admin", - &inode); - sdp->sd_master_dir = inode; - gfs2_glock_put(gl); - } - - return error; -} - /** * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one * @sdp: the filesystem diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index cc1a3df1949..6abb7b5c882 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -33,7 +33,6 @@ 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); -- GitLab From b4dc72911d149d7d6b7ffb512bd68906f1cbd33a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Mar 2006 17:41:58 -0500 Subject: [PATCH 0059/1619] [GFS2] Fix some bugs Fix a bug I introduced earlier with a kfree() and usage of a structure in the wrong order. Also try and get the counts of the journaled data buffers "more correct". Still some work to do in this area though. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 2 -- fs/gfs2/lops.c | 1 + fs/gfs2/trans.c | 13 ++++++------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 32a41a274bf..e6a84f7a9b7 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -597,8 +597,6 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *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); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 430161a05a2..9d40e21f6ea 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -474,6 +474,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_trans_add_gl(bd->bd_gl); list_add(&bd->bd_list_tr, &tr->tr_list_buf); gfs2_pin(sdp, bd->bd_bh); + tr->tr_num_buf_new++; } gfs2_log_lock(sdp); if (!list_empty(&le->le_list)) { diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 5d1f4a1e407..63e7fed2bd4 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -87,7 +87,6 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, void gfs2_trans_end(struct gfs2_sbd *sdp) { struct gfs2_trans *tr; - struct gfs2_holder *t_gh; tr = current->journal_info; current->journal_info = NULL; @@ -95,13 +94,11 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) if (gfs2_assert_warn(sdp, tr)) return; - t_gh = &tr->tr_t_gh; - if (!tr->tr_touched) { gfs2_log_release(sdp, tr->tr_reserved); - gfs2_glock_dq(t_gh); - gfs2_holder_uninit(t_gh); + gfs2_glock_dq(&tr->tr_t_gh); + gfs2_holder_uninit(&tr->tr_t_gh); kfree(tr); return; @@ -120,8 +117,10 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) gfs2_log_commit(sdp, tr); - gfs2_glock_dq(t_gh); - gfs2_holder_uninit(t_gh); + gfs2_glock_dq(&tr->tr_t_gh); + gfs2_holder_uninit(&tr->tr_t_gh); + + kfree(tr); if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) gfs2_log_flush(sdp); -- GitLab From 419c93e0b6b9eef0bf26b8ad415f2a5bf4300119 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 2 Mar 2006 16:33:41 -0500 Subject: [PATCH 0060/1619] [GFS2] Add gfs2meta filesystem In order to separate out the filesystem's metadata from "normal" files and directories, a new filesystem type has been created. It is called gfs2meta and mounting it gives access to the files that were previously under .gfs2_admin (well still are until mkfs is altered, which is next on the adgenda). Its not currently possible to mount both gfs2 and gfs2meta on the same block device at the same time. A future patch will allow that to happen. Signed-off-by: Steven Whitehouse --- fs/gfs2/main.c | 9 ++++++- fs/gfs2/ops_fstype.c | 58 +++++++++++++++++++++++++++----------------- fs/gfs2/ops_fstype.h | 1 + 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c5417779031..c8d17b7ba60 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -64,11 +64,17 @@ static int __init init_gfs2_fs(void) if (error) goto fail; + error = register_filesystem(&gfs2meta_fs_type); + if (error) + goto fail_unregister; + printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__); return 0; - fail: +fail_unregister: + unregister_filesystem(&gfs2_fs_type); +fail: if (gfs2_bufdata_cachep) kmem_cache_destroy(gfs2_bufdata_cachep); @@ -90,6 +96,7 @@ static int __init init_gfs2_fs(void) static void __exit exit_gfs2_fs(void) { unregister_filesystem(&gfs2_fs_type); + unregister_filesystem(&gfs2meta_fs_type); kmem_cache_destroy(gfs2_bufdata_cachep); kmem_cache_destroy(gfs2_inode_cachep); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c3b830bd838..8d6d9414356 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -113,9 +113,9 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) return sdp; } -static void init_vfs(struct gfs2_sbd *sdp) +static void init_vfs(struct super_block *sb, unsigned noatime) { - struct super_block *sb = sdp->sd_vfs; + struct gfs2_sbd *sdp = sb->s_fs_info; sb->s_magic = GFS2_MAGIC; sb->s_op = &gfs2_super_ops; @@ -123,18 +123,10 @@ static void init_vfs(struct gfs2_sbd *sdp) sb->s_maxbytes = MAX_LFS_FILESIZE; if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME)) - set_bit(SDF_NOATIME, &sdp->sd_flags); + set_bit(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) @@ -291,18 +283,16 @@ static struct inode *gfs2_lookup_root(struct gfs2_sbd *sdp, error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, CREATE, &gl); if (!error) { - error = gfs2_inode_get(gl, inum, - CREATE, &ip); + error = gfs2_inode_get(gl, inum, CREATE, &ip); if (!error) { - if (!error) - gfs2_inode_min_init(ip, DT_DIR); + 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); } @@ -310,6 +300,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 inode *inode; int error = 0; @@ -332,14 +323,15 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) } /* Set up the buffer cache and SB for real */ - error = -EINVAL; if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) { + error = -EINVAL; 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) { + error = -EINVAL; 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); @@ -353,7 +345,10 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) sb_set_blocksize(sb, sdp->sd_sb.sb_bsize); /* Get the root inode */ - inode = gfs2_lookup_root(sdp, &sdp->sd_sb.sb_root_dir); + 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); if (IS_ERR(inode)) { error = PTR_ERR(inode); fs_err(sdp, "can't read in root inode: %d\n", error); @@ -366,10 +361,8 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) error = -ENOMEM; iput(inode); } - out: gfs2_glock_dq_uninit(&sb_gh); - return error; } @@ -791,7 +784,15 @@ static int fill_super(struct super_block *sb, void *data, int silent) goto fail; } - init_vfs(sdp); + init_vfs(sb, SDF_NOATIME); + + /* 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; error = init_names(sdp, silent); if (error) @@ -881,11 +882,24 @@ static struct super_block *gfs2_get_sb(struct file_system_type *fs_type, return get_sb_bdev(fs_type, flags, dev_name, data, fill_super); } +static void gfs2_kill_sb(struct super_block *sb) +{ + kill_block_super(sb); +} + struct file_system_type gfs2_fs_type = { .name = "gfs2", .fs_flags = FS_REQUIRES_DEV, .get_sb = gfs2_get_sb, - .kill_sb = kill_block_super, + .kill_sb = gfs2_kill_sb, + .owner = THIS_MODULE, +}; + +struct file_system_type gfs2meta_fs_type = { + .name = "gfs2meta", + .fs_flags = FS_REQUIRES_DEV, + .get_sb = gfs2_get_sb, + .kill_sb = gfs2_kill_sb, .owner = THIS_MODULE, }; diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h index 7008364e76e..c6452874483 100644 --- a/fs/gfs2/ops_fstype.h +++ b/fs/gfs2/ops_fstype.h @@ -11,5 +11,6 @@ #define __OPS_FSTYPE_DOT_H__ extern struct file_system_type gfs2_fs_type; +extern struct file_system_type gfs2meta_fs_type; #endif /* __OPS_FSTYPE_DOT_H__ */ -- GitLab From c752666c17f870fa8ae9f16804dd457e9e6daaec Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 20 Mar 2006 12:30:04 -0500 Subject: [PATCH 0061/1619] [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(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 37f70ca558c..f31f163da1a 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 5b01497b3ab..8fd4dc0f700 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 cd1de61bff2..d403d51d5b0 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 c3fa6cfce16..0dd2a26626e 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 5a0bdc22a1f..3be060f1cbe 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 7f613928851..b54608f9df5 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 a346943363c..b27bce74a79 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 8d6d9414356..8d2c557b3ff 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 7633a8584b0..e8ab9d254b7 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 fff5a96f415..71cca762940 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 8d4f0445df4..a5fb4f99aa4 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); -- GitLab From 94aabbd99370f738da4f6cb4ea0b94cd9024002f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 21 Mar 2006 11:29:00 -0500 Subject: [PATCH 0062/1619] [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 diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index d30c6db4624..6333a14cf77 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 fb7c0cf72c5..00000000000 --- 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__ */ - -- GitLab From 71b86f562b5eb6f94ea00bba060caa64d0137969 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 28 Mar 2006 14:14:04 -0500 Subject: [PATCH 0063/1619] [GFS2] Further updates to dir and logging code This reduces the size of the directory code by about 3k and gets readdir() to use the functions which were introduced in the previous directory code update. Two memory allocations are merged into one. Eliminates zeroing of some buffers which were never used before they were initialised by other data. There is still scope for further improvement in the directory code. On the logging side, a hand created mutex has been replaced by a standard Linux mutex in the log allocation code. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 1 + fs/gfs2/dir.c | 412 +++++++++++++++++-------------------------- fs/gfs2/dir.h | 15 +- fs/gfs2/incore.h | 3 +- fs/gfs2/inode.c | 14 +- fs/gfs2/log.c | 34 +--- fs/gfs2/ops_dentry.c | 1 + fs/gfs2/ops_export.c | 8 +- fs/gfs2/ops_file.c | 219 ++++++++++++++++++++++- fs/gfs2/ops_fstype.c | 4 +- fs/gfs2/ops_inode.c | 13 +- fs/gfs2/recovery.c | 2 + fs/gfs2/super.c | 1 + fs/gfs2/util.c | 5 - fs/gfs2/util.h | 2 - 15 files changed, 416 insertions(+), 318 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cd5e4d863ce..c7723119acb 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f31f163da1a..ba3438553f3 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -344,7 +345,8 @@ fail: } typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, - const struct qstr *name); + const struct qstr *name, + void *opaque); static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, const struct qstr *name, int ret) @@ -358,13 +360,15 @@ static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, } static int gfs2_dirent_find(const struct gfs2_dirent *dent, - const struct qstr *name) + const struct qstr *name, + void *opaque) { return __gfs2_dirent_find(dent, name, 1); } static int gfs2_dirent_prev(const struct gfs2_dirent *dent, - const struct qstr *name) + const struct qstr *name, + void *opaque) { return __gfs2_dirent_find(dent, name, 2); } @@ -374,7 +378,8 @@ static int gfs2_dirent_prev(const struct gfs2_dirent *dent, * name->len holds size of block. */ static int gfs2_dirent_last(const struct gfs2_dirent *dent, - const struct qstr *name) + const struct qstr *name, + void *opaque) { const char *start = name->name; const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len); @@ -384,17 +389,36 @@ static int gfs2_dirent_last(const struct gfs2_dirent *dent, } static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, - const struct qstr *name) + const struct qstr *name, + void *opaque) { 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 (!dent->de_inum.no_addr) + actual = GFS2_DIRENT_SIZE(0); if ((totlen - actual) >= required) return 1; return 0; } +struct dirent_gather { + const struct gfs2_dirent **pdent; + unsigned offset; +}; + +static int gfs2_dirent_gather(const struct gfs2_dirent *dent, + const struct qstr *name, + void *opaque) +{ + struct dirent_gather *g = opaque; + if (dent->de_inum.no_addr) { + g->pdent[g->offset++] = dent; + } + return 0; +} + /* * Other possible things to check: * - Inode located within filesystem size (and on valid block) @@ -431,19 +455,12 @@ error: 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) +static int gfs2_dirent_offset(const void *buf) { - struct gfs2_meta_header *h = buf; - struct gfs2_dirent *dent, *prev; - unsigned offset; - unsigned size; - int ret = 0; + const struct gfs2_meta_header *h = buf; + int offset; BUG_ON(buf == NULL); - BUG_ON(name == NULL); switch(be16_to_cpu(h->mh_type)) { case GFS2_METATYPE_LF: @@ -455,14 +472,36 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, default: goto wrong_type; } + return offset; +wrong_type: + printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n", + be16_to_cpu(h->mh_type)); + return -1; +} +static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, + void *buf, + unsigned int len, gfs2_dscan_t scan, + const struct qstr *name, + void *opaque) +{ + struct gfs2_dirent *dent, *prev; + unsigned offset; + unsigned size; + int ret = 0; + + ret = gfs2_dirent_offset(buf); + if (ret < 0) + goto consist_inode; + + offset = ret; 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); + ret = scan(dent, name, opaque); if (ret) break; offset += size; @@ -487,9 +526,6 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, 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); @@ -651,7 +687,8 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, const struct qstr *name) { struct gfs2_dirent *dent; - dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_find_space, name); + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, + gfs2_dirent_find_space, name, NULL); if (!dent || IS_ERR(dent)) return dent; return gfs2_init_dirent(inode, dent, name, bh); @@ -734,7 +771,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, return ERR_PTR(error); do { dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, - scan, name); + scan, name, NULL); if (dent) goto got_dent; leaf = (struct gfs2_leaf *)bh->b_data; @@ -751,7 +788,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, 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); + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); got_dent: *pbh = bh; return dent; @@ -764,6 +801,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct gfs2_leaf *leaf; struct gfs2_dirent *dent; + struct qstr name = { .name = "", .len = 0, .hash = 0 }; if (!bh) return NULL; gfs2_trans_add_bh(ip->i_gl, bh, 1); @@ -775,12 +813,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, 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); + gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); *pbh = bh; return leaf; } @@ -831,7 +864,7 @@ static int dir_make_exhash(struct inode *inode) 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); + gfs2_dirent_last, &args, NULL); if (!dent) { brelse(bh); brelse(dibh); @@ -939,7 +972,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) lp[x] = cpu_to_be64(bn); error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), - half_len * sizeof(uint64_t)); + half_len * sizeof(uint64_t)); if (error != half_len * sizeof(uint64_t)) { if (error >= 0) error = -EIO; @@ -965,7 +998,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) 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); + new = gfs2_dirent_alloc(inode, nbh, &str); if (IS_ERR(new)) { error = PTR_ERR(new); break; @@ -1154,10 +1187,10 @@ static int compare_dents(const void *a, const void *b) 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, + const struct gfs2_dirent **darr, uint32_t entries, int *copied) { - struct gfs2_dirent *dent, *dent_next; + const struct gfs2_dirent *dent, *dent_next; struct gfs2_inum inum; uint64_t off, off_next; unsigned int x, y; @@ -1216,189 +1249,74 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *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) +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_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; + struct gfs2_inode *ip = inode->u.generic_ip; + struct buffer_head *bh; + struct gfs2_leaf *lf; + unsigned entries = 0; + unsigned leaves = 0; + const struct gfs2_dirent **darr, *dent; + struct dirent_gather g; + struct buffer_head **larr; + int leaf = 0; + int error, i; + u64 lfn = leaf_no; - 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 = be64_to_cpu(leaf->lf_next); - - while (ln) { - error = get_leaf(dip, ln, &tmp_bh); + error = get_leaf(ip, lfn, &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 = be64_to_cpu(leaf->lf_next); - - brelse(tmp_bh); - } + goto out; + lf = (struct gfs2_leaf *)bh->b_data; + if (leaves == 0) + *depth = be16_to_cpu(lf->lf_depth); + entries += be16_to_cpu(lf->lf_entries); + leaves++; + lfn = be64_to_cpu(lf->lf_next); + brelse(bh); + } while(lfn); 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 = be64_to_cpu(leaf->lf_next); + error = -ENOMEM; + larr = kmalloc((leaves + entries) * sizeof(void*), GFP_KERNEL); + if (!larr) + goto out; + darr = (const struct gfs2_dirent **)(larr + leaves); + g.pdent = darr; + g.offset = 0; + lfn = leaf_no; - while (ln) { - error = get_leaf(dip, ln, &tmp_bh); + do { + error = get_leaf(ip, lfn, &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 = be64_to_cpu(leaf->lf_next); + goto out_kfree; + lf = (struct gfs2_leaf *)bh->b_data; + lfn = be64_to_cpu(lf->lf_next); + if (lf->lf_entries) { + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, + gfs2_dirent_gather, NULL, &g); + error = PTR_ERR(dent); + if (IS_ERR(dent)) { + goto out_kfree; + } + error = 0; + larr[leaf++] = bh; } else { - ln = be64_to_cpu(leaf->lf_next); - brelse(tmp_bh); + brelse(bh); } - } + } while(lfn); - 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, + error = do_filldir_main(ip, offset, opaque, filldir, darr, entries, copied); - - out: - kfree(darr); - for (x = 0; x < l; x++) - brelse(larr[x]); +out_kfree: + for(i = 0; i < leaf; i++) + brelse(larr[i]); kfree(larr); - +out: return error; } @@ -1412,18 +1330,18 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, * Returns: errno */ -static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, +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 buffer_head *bh; - struct gfs2_leaf *leaf; - uint32_t hsize, len; + uint32_t hsize, len = 0; uint32_t ht_offset, lp_offset, ht_offset_cur = -1; uint32_t hash, index; uint64_t *lp; int copied = 0; int error = 0; + unsigned depth; hsize = 1 << dip->i_di.di_depth; if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { @@ -1454,61 +1372,66 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, ht_offset_cur = ht_offset; } - error = get_leaf(dip, be64_to_cpu(lp[lp_offset]), &bh); + error = gfs2_dir_read_leaf(inode, offset, opaque, filldir, + &copied, &depth, + be64_to_cpu(lp[lp_offset])); if (error) - goto out; - - 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, - be16_to_cpu(leaf->lf_entries), - &copied); - - brelse(bh); - - if (error) { - if (error > 0) - error = 0; - goto out; - } + break; - len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); + len = 1 << (dip->i_di.di_depth - depth); index = (index & ~(len - 1)) + len; } - out: +out: kfree(lp); - + if (error > 0) + error = 0; return error; } -static int dir_l_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, - gfs2_filldir_t filldir) +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 dirent_gather g; + const struct gfs2_dirent **darr, *dent; struct buffer_head *dibh; int copied = 0; int error; + if (!dip->i_di.di_entries) + return 0; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + return dir_e_read(inode, offset, opaque, filldir); + 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); + error = -ENOMEM; + darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *), + GFP_KERNEL); + if (darr) { + g.pdent = darr; + g.offset = 0; + dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size, + gfs2_dirent_gather, NULL, &g); + if (IS_ERR(dent)) { + error = PTR_ERR(dent); + goto out; + } + error = do_filldir_main(dip, offset, opaque, filldir, darr, + dip->i_di.di_entries, &copied); +out: + kfree(darr); + } + if (error > 0) error = 0; @@ -1694,7 +1617,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) return PTR_ERR(dent); } /* If not first in block, adjust pointers accordingly */ - if (gfs2_dirent_find(dent, name) == 0) { + if (gfs2_dirent_find(dent, name, NULL) == 0) { prev = dent; dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); } @@ -1724,19 +1647,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) 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 diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 8fd4dc0f700..42b3a1f34de 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -32,7 +32,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *filename, 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, +int gfs2_dir_read(struct inode *inode, uint64_t * 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); @@ -44,6 +44,19 @@ int gfs2_diradd_alloc_required(struct inode *dir, int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, struct buffer_head **bhp); +static inline uint32_t gfs2_disk_hash(const char *data, int len) +{ + return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF; +} + + +static inline void gfs2_str2qstr(struct qstr *name, const char *fname) +{ + name->name = fname; + name->len = strlen(fname); + name->hash = gfs2_disk_hash(name->name, name->len); +} + /* 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) { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 62f109e553c..be307185f49 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -634,8 +634,7 @@ struct gfs2_sbd { 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; + struct mutex sd_log_reserve_mutex; uint64_t sd_log_sequence; unsigned int sd_log_head; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index d403d51d5b0..6140c2434e8 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -701,9 +702,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) 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); + gfs2_str2qstr(&qstr, name); return gfs2_lookupi(dip, &qstr, 1, NULL); } @@ -1389,9 +1388,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, if (error) return error; - dotname.len = 1; - dotname.name = "."; - dotname.hash = gfs2_disk_hash(dotname.name, dotname.len); + gfs2_str2qstr(&dotname, "."); error = gfs2_dir_del(ip, &dotname); if (error) return error; @@ -1487,10 +1484,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) struct qstr dotdot; int error = 0; - memset(&dotdot, 0, sizeof(struct qstr)); - dotdot.name = ".."; - dotdot.len = 2; - dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len); + gfs2_str2qstr(&dotdot, ".."); igrab(dir); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index e6a84f7a9b7..16c14441a37 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -24,18 +25,13 @@ #include "lops.h" #include "meta_io.h" #include "util.h" +#include "dir.h" #define PULL 1 -static void do_lock_wait(struct gfs2_sbd *sdp, wait_queue_head_t *wq, - atomic_t *a) -{ - wait_event(*wq, atomic_read(a) ? 0 : 1); -} - static void lock_for_trans(struct gfs2_sbd *sdp) { - do_lock_wait(sdp, &sdp->sd_log_trans_wq, &sdp->sd_log_flush_count); + wait_event(sdp->sd_log_trans_wq, atomic_read(&sdp->sd_log_flush_count) ? 0 : 1); atomic_inc(&sdp->sd_log_trans_count); } @@ -49,7 +45,7 @@ static void unlock_from_trans(struct gfs2_sbd *sdp) static void gfs2_lock_for_flush(struct gfs2_sbd *sdp) { atomic_inc(&sdp->sd_log_flush_count); - do_lock_wait(sdp, &sdp->sd_log_flush_wq, &sdp->sd_log_trans_count); + wait_event(sdp->sd_log_flush_wq, atomic_read(&sdp->sd_log_trans_count) ? 0 : 1); } static void gfs2_unlock_from_flush(struct gfs2_sbd *sdp) @@ -191,37 +187,19 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) 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; + mutex_lock(&sdp->sd_log_reserve_mutex); 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); + mutex_unlock(&sdp->sd_log_reserve_mutex); break; } diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index b54608f9df5..95837107609 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "gfs2.h" diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index b27bce74a79..be16c68263d 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -153,7 +154,7 @@ static int gfs2_get_name(struct dentry *parent, char *name, if (error) return error; - error = gfs2_dir_read(dip, &offset, &gnfd, get_name_filldir); + error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir); gfs2_glock_dq_uninit(&gh); @@ -165,12 +166,11 @@ static int gfs2_get_name(struct dentry *parent, char *name, static struct dentry *gfs2_get_parent(struct dentry *child) { - struct qstr dotdot = { .name = "..", .len = 2 }; + struct qstr dotdot; struct inode *inode; struct dentry *dentry; - dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len); - + gfs2_str2qstr(&dotdot, ".."); inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL); if (!inode) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 6333a14cf77..ac8e1238cb6 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -39,6 +41,7 @@ #include "rgrp.h" #include "trans.h" #include "util.h" +#include "eaops.h" /* "bad" is for NFS support */ struct filldir_bad_entry { @@ -357,7 +360,8 @@ 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 = file->f_mapping->host->u.generic_ip; + struct inode *dir = file->f_mapping->host; + struct gfs2_inode *dip = dir->u.generic_ip; struct filldir_reg fdr; struct gfs2_holder d_gh; uint64_t offset = file->f_pos; @@ -375,7 +379,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) return error; } - error = gfs2_dir_read(dip, &offset, &fdr, filldir_reg_func); + error = gfs2_dir_read(dir, &offset, &fdr, filldir_reg_func); gfs2_glock_dq_uninit(&d_gh); @@ -446,7 +450,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 gfs2_inode *dip = file->f_mapping->host->u.generic_ip; + struct inode *dir = file->f_mapping->host; + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct filldir_reg fdr; unsigned int entries, size; @@ -479,7 +484,7 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) goto out; } - error = gfs2_dir_read(dip, &offset, fdb, filldir_bad_func); + error = gfs2_dir_read(dir, &offset, fdb, filldir_bad_func); gfs2_glock_dq_uninit(&d_gh); @@ -531,6 +536,210 @@ 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 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 int get_ext2_flags(struct inode *inode, u32 __user *ptr) +{ + struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_holder gh; + int error; + u32 ext2; + + 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)) + error = -EFAULT; + + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); + return error; +} + +/* Flags that can be set by user space */ +#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \ + GFS2_DIF_DIRECTIO| \ + GFS2_DIF_IMMUTABLE| \ + GFS2_DIF_APPENDONLY| \ + GFS2_DIF_NOATIME| \ + GFS2_DIF_SYNC| \ + GFS2_DIF_SYSTEM| \ + GFS2_DIF_INHERIT_DIRECTIO| \ + GFS2_DIF_INHERIT_JDATA) + +/** + * gfs2_set_flags - set flags on an inode + * @inode: The inode + * @flags: The flags to set + * @mask: Indicates which flags are valid + * + */ +static int gfs2_set_flags(struct inode *inode, u32 flags, u32 mask) +{ + struct gfs2_inode *ip = inode->u.generic_ip; + struct buffer_head *bh; + struct gfs2_holder gh; + int error; + u32 new_flags; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (error) + return error; + + new_flags = (ip->i_di.di_flags & ~mask) | (flags & mask); + if ((new_flags ^ flags) == 0) + goto out; + + 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; + if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY)) + goto out; + error = gfs2_repermission(inode, MAY_WRITE, NULL); + if (error) + goto out; + + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out; + 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); + brelse(bh); +out: + gfs2_glock_dq_uninit(&gh); + return error; +} + +static int set_ext2_flags(struct inode *inode, u32 __user *ptr) +{ + u32 ext2, gfs2; + if (get_user(ext2, ptr)) + return -EFAULT; + if (gfs2_flags_from_ext2(&gfs2, ext2)) + return -EINVAL; + return gfs2_set_flags(inode, gfs2, ~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); + } + return -ENOTTY; +} + + /** * gfs2_mmap - * @file: The file to map @@ -832,6 +1041,7 @@ 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, @@ -843,6 +1053,7 @@ 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/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 8d2c557b3ff..2628bf32633 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -97,9 +97,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) 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); - + mutex_init(&sdp->sd_log_reserve_mutex); INIT_LIST_HEAD(&sdp->sd_ail1_list); INIT_LIST_HEAD(&sdp->sd_ail2_list); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index e8ab9d254b7..1e2b709711a 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -417,18 +418,16 @@ 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 = (struct gfs2_dirent *)(di+1); - struct qstr str = { .name = ".", .len = 1 }; - str.hash = gfs2_disk_hash(str.name, str.len); + struct qstr str; + gfs2_str2qstr(&str, "."); 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_type = DT_DIR; di->di_entries = cpu_to_be32(1); - str.name = ".."; - str.len = 2; - str.hash = gfs2_disk_hash(str.name, str.len); + gfs2_str2qstr(&str, ".."); 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); @@ -772,9 +771,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (dir_rename) { struct qstr name; - name.len = 2; - name.name = ".."; - name.hash = gfs2_disk_hash(name.name, name.len); + gfs2_str2qstr(&name, ".."); error = gfs2_change_nlink(ndip, +1); if (error) diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 2df450e2f43..6c7e2e880e3 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -27,6 +28,7 @@ #include "recovery.h" #include "super.h" #include "util.h" +#include "dir.h" int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, struct buffer_head **bh) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 71cca762940..a4da649d086 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 8b22fa91bd1..7cd9e25639c 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -28,11 +28,6 @@ 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", diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 8d6eba3bdf0..addbe304993 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -10,8 +10,6 @@ #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) -- GitLab From 7aabffcab47a0f881c7640f5c108e8d3f2e35ebf Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 28 Mar 2006 14:20:58 -0500 Subject: [PATCH 0064/1619] [DLM] Look for "nodir" in the lockspace mount options Look for "nodir" in the hostdata mount option which is used to set the NODIR flag in dlm_new_lockspace(). Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/mount.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 042f3a75c44..026f05ce168 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -60,7 +60,7 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata, return ls; } -static int make_args(struct gdlm_ls *ls, char *data_arg) +static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) { char data[256]; char *options, *x, *y; @@ -101,6 +101,14 @@ static int make_args(struct gdlm_ls *ls, char *data_arg) } sscanf(y, "%u", &ls->id); + } else if (!strcmp(x, "nodir")) { + if (!y) { + log_error("need argument to nodir"); + error = -EINVAL; + break; + } + sscanf(y, "%u", nodir); + } else { log_error("unkonwn option: %s", x); error = -EINVAL; @@ -118,7 +126,7 @@ static int gdlm_mount(char *table_name, char *host_data, struct kobject *fskobj) { struct gdlm_ls *ls; - int error = -ENOMEM; + int error = -ENOMEM, nodir = 0; if (min_lvb_size > GDLM_LVB_SIZE) goto out; @@ -127,12 +135,18 @@ static int gdlm_mount(char *table_name, char *host_data, if (!ls) goto out; + error = make_args(ls, host_data, &nodir); + if (error) + goto out; + error = gdlm_init_threads(ls); if (error) goto out_free; error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), - &ls->dlm_lockspace, 0, GDLM_LVB_SIZE); + &ls->dlm_lockspace, + nodir ? DLM_LSFL_NODIR : 0, + GDLM_LVB_SIZE); if (error) { log_error("dlm_new_lockspace error %d", error); goto out_thread; @@ -142,10 +156,6 @@ static int gdlm_mount(char *table_name, char *host_data, if (error) goto out_dlm; - error = make_args(ls, host_data); - if (error) - goto out_sysfs; - lockstruct->ls_jid = ls->jid; lockstruct->ls_first = ls->first; lockstruct->ls_lockspace = ls; @@ -154,8 +164,6 @@ static int gdlm_mount(char *table_name, char *host_data, lockstruct->ls_lvb_size = GDLM_LVB_SIZE; return 0; - out_sysfs: - gdlm_kobject_release(ls); out_dlm: dlm_release_lockspace(ls->dlm_lockspace, 2); out_thread: -- GitLab From 484adff8a06cb5d952832f5487ae863f54c0fb69 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 29 Mar 2006 09:12:12 -0500 Subject: [PATCH 0065/1619] [GFS2] Update locking in log.c Replace the lock_for_trans()/lock_for_flush() functions with an rwsem. In fact the sd_log_flush_lock becomes an rwsem (the write part of it) and is extended slightly to cover everything that the lock_for_flush() used to cover. The read part of the lock is instead of lock_for_trans(). This corrects the races in the original code and reduces the code size. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 6 +--- fs/gfs2/log.c | 67 ++++++++++++-------------------------------- fs/gfs2/ops_fstype.c | 4 +-- fs/gfs2/trans.c | 4 +-- 4 files changed, 22 insertions(+), 59 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index be307185f49..35163b56246 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -611,10 +611,6 @@ struct gfs2_sbd { /* 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; @@ -643,7 +639,7 @@ struct gfs2_sbd { int sd_log_idle; unsigned long sd_log_flush_time; - struct mutex sd_log_flush_lock; + struct rw_semaphore sd_log_flush_lock; struct list_head sd_log_flush_list; unsigned int sd_log_flush_head; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 16c14441a37..b103d9acf40 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -29,32 +29,6 @@ #define PULL 1 -static void lock_for_trans(struct gfs2_sbd *sdp) -{ - wait_event(sdp->sd_log_trans_wq, atomic_read(&sdp->sd_log_flush_count) ? 0 : 1); - atomic_inc(&sdp->sd_log_trans_count); -} - -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); -} - -static void gfs2_lock_for_flush(struct gfs2_sbd *sdp) -{ - atomic_inc(&sdp->sd_log_flush_count); - wait_event(sdp->sd_log_flush_wq, atomic_read(&sdp->sd_log_trans_count) ? 0 : 1); -} - -static 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 @@ -109,9 +83,8 @@ void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) first = NULL; for (;;) { - if (first && - (head->prev != first || - gfs2_ail1_empty_one(sdp, first_ai, 0))) + if (first && (head->prev != first || + gfs2_ail1_empty_one(sdp, first_ai, 0))) break; for (tmp = head->prev; tmp != head; tmp = tmp->prev) { @@ -194,23 +167,21 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) return -EINVAL; mutex_lock(&sdp->sd_log_reserve_mutex); - for (;;) { - gfs2_log_lock(sdp); - if (sdp->sd_log_blks_free > blks) { - sdp->sd_log_blks_free -= blks; - gfs2_log_unlock(sdp); - mutex_unlock(&sdp->sd_log_reserve_mutex); - break; - } - + gfs2_log_lock(sdp); + while(sdp->sd_log_blks_free <= blks) { gfs2_log_unlock(sdp); gfs2_ail1_empty(sdp, 0); gfs2_log_flush(sdp); if (try++) gfs2_ail1_start(sdp, 0); + gfs2_log_lock(sdp); } - lock_for_trans(sdp); + sdp->sd_log_blks_free -= blks; + gfs2_log_unlock(sdp); + mutex_unlock(&sdp->sd_log_reserve_mutex); + + down_read(&sdp->sd_log_flush_lock); return 0; } @@ -224,7 +195,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) { - unlock_from_trans(sdp); + up_read(&sdp->sd_log_flush_lock); gfs2_log_lock(sdp); sdp->sd_log_blks_free += blks; @@ -474,20 +445,20 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); INIT_LIST_HEAD(&ai->ai_ail1_list); INIT_LIST_HEAD(&ai->ai_ail2_list); - gfs2_lock_for_flush(sdp); + + down_write(&sdp->sd_log_flush_lock); if (gl) { gfs2_log_lock(sdp); if (list_empty(&gl->gl_le.le_list)) { gfs2_log_unlock(sdp); - gfs2_unlock_from_flush(sdp); + up_write(&sdp->sd_log_flush_lock); kfree(ai); return; } gfs2_log_unlock(sdp); } - mutex_lock(&sdp->sd_log_flush_lock); gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf == sdp->sd_log_commited_buf); @@ -519,9 +490,8 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) } gfs2_log_unlock(sdp); - mutex_unlock(&sdp->sd_log_flush_lock); sdp->sd_vfs->s_dirt = 0; - gfs2_unlock_from_flush(sdp); + up_write(&sdp->sd_log_flush_lock); kfree(ai); } @@ -573,7 +543,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) lops_incore_commit(sdp, tr); sdp->sd_vfs->s_dirt = 1; - unlock_from_trans(sdp); + up_read(&sdp->sd_log_flush_lock); gfs2_log_lock(sdp); if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) { @@ -591,9 +561,8 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) void gfs2_log_shutdown(struct gfs2_sbd *sdp) { - mutex_lock(&sdp->sd_log_flush_lock); + down_write(&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); @@ -618,6 +587,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) sdp->sd_log_wraps++; sdp->sd_log_tail = sdp->sd_log_head; - mutex_unlock(&sdp->sd_log_flush_lock); + up_write(&sdp->sd_log_flush_lock); } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 2628bf32633..5166455b9fd 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -88,8 +88,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) mutex_init(&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); @@ -101,7 +99,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_ail1_list); INIT_LIST_HEAD(&sdp->sd_ail2_list); - mutex_init(&sdp->sd_log_flush_lock); + init_rwsem(&sdp->sd_log_flush_lock); INIT_LIST_HEAD(&sdp->sd_log_flush_list); INIT_LIST_HEAD(&sdp->sd_revoke_list); diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 63e7fed2bd4..aa1a619f085 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -74,10 +74,10 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, return 0; - fail_gunlock: +fail_gunlock: gfs2_glock_dq(&tr->tr_t_gh); - fail_holder_uninit: +fail_holder_uninit: gfs2_holder_uninit(&tr->tr_t_gh); kfree(tr); -- GitLab From d0dc80dbafb5c10ad2084831a61bbf945484a139 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 29 Mar 2006 14:36:49 -0500 Subject: [PATCH 0066/1619] [GFS2] Update debugging code Update the debugging code in trans.c and at the same time improve the debugging code for gfs2_holders. The new code should be pretty fast during the normal case and provide just as much information in case of errors (or more). One small function from glock.c has moved to glock.h as a static inline so that its return address won't get in the way of the debugging. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 34 +++++++++------------------------- fs/gfs2/glock.h | 27 +++++++++++++++++++++++++-- fs/gfs2/incore.h | 4 ++-- fs/gfs2/trans.c | 32 ++++++++++++++------------------ fs/gfs2/trans.h | 8 ++------ 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 81b06812b32..6a1b42cf4df 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -357,6 +358,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags, { INIT_LIST_HEAD(&gh->gh_list); gh->gh_gl = gl; + gh->gh_ip = (unsigned long)__builtin_return_address(0); gh->gh_owner = (flags & GL_NEVER_RECURSE) ? NULL : current; gh->gh_state = state; gh->gh_flags = flags; @@ -388,6 +390,7 @@ void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh) gh->gh_flags |= GL_LOCAL_EXCL; gh->gh_iflags &= 1 << HIF_ALLOCED; + gh->gh_ip = (unsigned long)__builtin_return_address(0); } /** @@ -400,6 +403,7 @@ void gfs2_holder_uninit(struct gfs2_holder *gh) { gfs2_glock_put(gh->gh_gl); gh->gh_gl = NULL; + gh->gh_ip = 0; } /** @@ -427,7 +431,7 @@ struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state, gfs2_holder_init(gl, state, flags, gh); set_bit(HIF_ALLOCED, &gh->gh_iflags); - + gh->gh_ip = (unsigned long)__builtin_return_address(0); return gh; } @@ -1238,6 +1242,9 @@ static int recurse_check(struct gfs2_holder *existing, struct gfs2_holder *new, return 0; fail: + print_symbol(KERN_WARNING "GFS2: Existing holder from %s\n", + existing->gh_ip); + print_symbol(KERN_WARNING "GFS2: New holder from %s\n", new->gh_ip); set_bit(HIF_ABORTED, &new->gh_iflags); return -EINVAL; } @@ -1543,30 +1550,6 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int 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 @@ -2334,6 +2317,7 @@ static int dump_holder(char *str, struct gfs2_holder *gh) if (test_bit(x, &gh->gh_iflags)) printk(" %u", x); printk(" \n"); + print_symbol(KERN_INFO " initialized at: %s\n", gh->gh_ip); error = 0; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 06847ebebde..560029de8d0 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -106,8 +106,6 @@ 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, @@ -121,6 +119,31 @@ void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, uint64_t number, struct gfs2_glock_operations *glops, unsigned int state, int flags); +/** + * 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 + */ + +static inline 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; +} + /* Lock Value Block functions */ int gfs2_lvb_hold(struct gfs2_glock *gl); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 35163b56246..b5a994d1b5f 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -161,6 +161,7 @@ struct gfs2_holder { int gh_error; unsigned long gh_iflags; struct completion gh_wait; + unsigned long gh_ip; }; enum { @@ -353,8 +354,7 @@ struct gfs2_log_buf { }; struct gfs2_trans { - char *tr_file; - unsigned int tr_line; + unsigned long tr_ip; unsigned int tr_blocks; unsigned int tr_revokes; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index aa1a619f085..3fae3d4e9ae 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -25,24 +26,20 @@ #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) +int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, + unsigned int revokes) { struct gfs2_trans *tr; int error; - if (gfs2_assert_warn(sdp, !current->journal_info) || - gfs2_assert_warn(sdp, blocks || revokes)) { - fs_warn(sdp, "(%s, %u)\n", file, line); - return -EINVAL; - } + BUG_ON(current->journal_info); + BUG_ON(blocks == 0 && revokes == 0); tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS); if (!tr) return -ENOMEM; - tr->tr_file = file; - tr->tr_line = line; + tr->tr_ip = (unsigned long)__builtin_return_address(0); tr->tr_blocks = blocks; tr->tr_revokes = revokes; tr->tr_reserved = 1; @@ -104,16 +101,15 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) 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_buf <= tr->tr_blocks)) { + fs_err(sdp, "tr_num_buf = %u, tr_blocks = %u ", + tr->tr_num_buf, tr->tr_blocks); + print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip); + } 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); + fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u ", + tr->tr_num_revoke, tr->tr_revokes); + print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip); gfs2_log_commit(sdp, tr); diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index f7f3e2a3d59..6b5e9e8bf56 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -21,12 +21,8 @@ #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); +int gfs2_trans_begin(struct gfs2_sbd *sdp, + unsigned int blocks, unsigned int revokes); void gfs2_trans_end(struct gfs2_sbd *sdp); -- GitLab From e90deff5336ac500c65f873484c326cfa8a9d379 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 29 Mar 2006 19:02:15 -0500 Subject: [PATCH 0067/1619] [GFS2] Fix bug in directory expansion code We didn't properly check that leaf splitting was allowed. We do now. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ba3438553f3..9f17e7d05af 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -940,10 +940,15 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) /* Get the old leaf block */ error = get_leaf(dip, leaf_no, &obh); if (error) - goto fail; + return error; - gfs2_trans_add_bh(dip->i_gl, obh, 1); oleaf = (struct gfs2_leaf *)obh->b_data; + if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) { + brelse(obh); + return 1; /* can't split */ + } + + gfs2_trans_add_bh(dip->i_gl, obh, 1); nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1); if (!nleaf) { @@ -956,6 +961,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { + printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index); gfs2_consist_inode(dip); error = -EIO; goto fail_brelse; @@ -1038,13 +1044,11 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) return error; - fail_lpfree: +fail_lpfree: kfree(lp); - fail_brelse: +fail_brelse: brelse(obh); - - fail: brelse(nbh); return error; } @@ -1570,16 +1574,17 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, error = dir_split_leaf(inode, name); if (error == 0) continue; - if (error != -ENOSPC) + if (error < 0) 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) + if (error < 0) break; - continue; + if (error == 0) + continue; } error = dir_new_leaf(inode, name); if (!error) -- GitLab From cd45697f0ddbb58f3f83c29fe164713ee7765e21 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 30 Mar 2006 11:10:12 -0500 Subject: [PATCH 0068/1619] [GFS2] Add missing {} in trans.c A conditional had missing {} around the two following statements. Now added. Signed-off-by: Steven Whitehouse --- fs/gfs2/trans.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 3fae3d4e9ae..d72f79e67c9 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -106,10 +106,11 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) tr->tr_num_buf, tr->tr_blocks); print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip); } - if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) + if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) { fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u ", tr->tr_num_revoke, tr->tr_revokes); print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip); + } gfs2_log_commit(sdp, tr); -- GitLab From e3167ded1f1b16424bc14d5673cdc5414f179970 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 30 Mar 2006 15:46:23 -0500 Subject: [PATCH 0069/1619] [GFS] Fix bug in endian conversion for metadata header In some cases 16 bit functions were being used rather than 32 bit functions. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 6 +++--- fs/gfs2/log.c | 4 ++-- fs/gfs2/lops.c | 16 ++++++++-------- fs/gfs2/ondisk.c | 8 ++++---- fs/gfs2/recovery.c | 4 ++-- fs/gfs2/util.h | 7 +++---- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 9f17e7d05af..66917f2c64a 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -462,7 +462,7 @@ static int gfs2_dirent_offset(const void *buf) BUG_ON(buf == NULL); - switch(be16_to_cpu(h->mh_type)) { + switch(be32_to_cpu(h->mh_type)) { case GFS2_METATYPE_LF: offset = sizeof(struct gfs2_leaf); break; @@ -475,7 +475,7 @@ static int gfs2_dirent_offset(const void *buf) return offset; wrong_type: printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n", - be16_to_cpu(h->mh_type)); + be32_to_cpu(h->mh_type)); return -1; } @@ -548,7 +548,7 @@ 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 (be16_to_cpu(h->mh_type) == GFS2_METATYPE_LF) { + if (be32_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 + diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index b103d9acf40..ea69376c00d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -377,8 +377,8 @@ static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) 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_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); + lh->lh_header.mh_format = cpu_to_be32(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); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 9d40e21f6ea..689c9101c0f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -133,8 +133,8 @@ static void buf_lo_before_commit(struct gfs2_sbd *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_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be32(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); @@ -291,8 +291,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) 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_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be32(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))); @@ -313,8 +313,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) 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); + mh->mh_type = cpu_to_be32(GFS2_METATYPE_LB); + mh->mh_format = cpu_to_be32(GFS2_FORMAT_LB); offset = sizeof(struct gfs2_meta_header); } @@ -576,9 +576,9 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); ld->ld_header.mh_type = - cpu_to_be16(GFS2_METATYPE_LD); + cpu_to_be32(GFS2_METATYPE_LD); ld->ld_header.mh_format = - cpu_to_be16(GFS2_FORMAT_LD); + cpu_to_be32(GFS2_FORMAT_LD); ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_JDATA); ld->ld_length = cpu_to_be32(num + 1); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 3be060f1cbe..acfc944ce13 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -83,8 +83,8 @@ static 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); + 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) @@ -92,8 +92,8 @@ static 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); + str->mh_type = cpu_to_be32(mh->mh_type); + str->mh_format = cpu_to_be32(mh->mh_format); } void gfs2_meta_header_print(struct gfs2_meta_header *mh) diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 6c7e2e880e3..68c85610fb5 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -324,7 +324,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, 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) { + if (be32_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) { struct gfs2_log_header lh; error = get_log_header(jd, start, &lh); if (!error) { @@ -400,7 +400,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) 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_header.mh_format = cpu_to_be32(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); diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index addbe304993..4532dbab0a2 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -107,12 +107,11 @@ static inline int gfs2_metatype_check_i(struct gfs2_sbd *sdp, { struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; uint32_t magic = mh->mh_magic; - uint16_t t = mh->mh_type; + uint16_t t = be32_to_cpu(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); @@ -127,8 +126,8 @@ static inline void gfs2_metatype_set(struct buffer_head *bh, uint16_t type, { 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); + mh->mh_type = cpu_to_be32(type); + mh->mh_format = cpu_to_be32(format); } -- GitLab From 7ea9ea832212c4a755650f7c7cc1ff0b63292a41 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 31 Mar 2006 15:01:28 -0500 Subject: [PATCH 0070/1619] [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 diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index ac8e1238cb6..db4484a3efc 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 a5fb4f99aa4..3ab40917383 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 00000000000..1b4d9ef5d62 --- /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 */ -- GitLab From 8628de0583504138551a05ad44ca388467f0f552 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 31 Mar 2006 16:48:41 -0500 Subject: [PATCH 0071/1619] [GFS2] Update GFS2 for the recent pull from Linus Some interfaces have changed. In particular one of the posix locking functions has changed prototype, along with the address space operation invalidatepage and the block getting callback to the direct IO function. In addition add the splice file operations. These will need to be updated to support AOP_TRUNCATED_PAGE before they will be of much use to us. Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/nolock/main.c | 15 +++----- fs/gfs2/ops_address.c | 66 ++++------------------------------- fs/gfs2/ops_file.c | 19 +++++----- 3 files changed, 19 insertions(+), 81 deletions(-) diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 9398309f281..ecd37371eba 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -176,14 +176,13 @@ static void nolock_sync_lvb(lm_lock_t *lock, char *lvb) static int nolock_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { - struct file_lock *tmp; + struct file_lock tmp; + int ret; - lock_kernel(); - tmp = posix_test_lock(file, fl); + ret = posix_test_lock(file, fl, &tmp); fl->fl_type = F_UNLCK; - if (tmp) - memcpy(fl, tmp, sizeof(struct file_lock)); - unlock_kernel(); + if (ret) + memcpy(fl, &tmp, sizeof(struct file_lock)); return 0; } @@ -192,9 +191,7 @@ static int nolock_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, int cmd, struct file_lock *fl) { int error; - lock_kernel(); error = posix_lock_file_wait(file, fl); - unlock_kernel(); return error; } @@ -202,9 +199,7 @@ static int nolock_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { int error; - lock_kernel(); error = posix_lock_file_wait(file, fl); - unlock_kernel(); return error; } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 01aa4a9b48c..3fd8c6ec256 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -96,59 +96,6 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, 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 = inode->u.generic_ip; - 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 = inode->u.generic_ip; - 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 @@ -527,16 +474,15 @@ static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) unlock_buffer(bh); } -static int gfs2_invalidatepage(struct page *page, unsigned long offset) +static void gfs2_invalidatepage(struct page *page, unsigned long offset) { 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; BUG_ON(!PageLocked(page)); if (!page_has_buffers(page)) - return 1; + return; bh = head = page_buffers(page); do { @@ -551,9 +497,9 @@ static int gfs2_invalidatepage(struct page *page, unsigned long offset) } while (bh != head); if (!offset) - ret = try_to_release_page(page, 0); + try_to_release_page(page, 0); - return ret; + return; } static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, @@ -587,7 +533,7 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, goto out; rv = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, - iov, offset, nr_segs, get_blocks_noalloc, + iov, offset, nr_segs, gfs2_get_block, NULL, DIO_OWN_LOCKING); out: gfs2_glock_dq_m(1, &gh); @@ -619,7 +565,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, return -EINVAL; return __blockdev_direct_IO(READ, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, get_blocks, NULL, + offset, nr_segs, gfs2_get_block, NULL, DIO_OWN_LOCKING); } diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index db4484a3efc..c44225fa758 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -833,20 +833,15 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (sdp->sd_args.ar_localflocks) { if (IS_GETLK(cmd)) { - struct file_lock *tmp; - lock_kernel(); - tmp = posix_test_lock(file, fl); + struct file_lock tmp; + int ret; + ret = posix_test_lock(file, fl, &tmp); fl->fl_type = F_UNLCK; - if (tmp) - memcpy(fl, tmp, sizeof(struct file_lock)); - unlock_kernel(); + if (ret) + memcpy(fl, &tmp, sizeof(struct file_lock)); return 0; } else { - int error; - lock_kernel(); - error = posix_lock_file_wait(file, fl); - unlock_kernel(); - return error; + return posix_lock_file_wait(file, fl); } } @@ -983,6 +978,8 @@ struct file_operations gfs2_file_fops = { .lock = gfs2_lock, .sendfile = gfs2_sendfile, .flock = gfs2_flock, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, }; struct file_operations gfs2_dir_fops = { -- GitLab From 55eccc6d00cea224bf634d44e9871cfe83200ff2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 4 Apr 2006 14:29:30 -0400 Subject: [PATCH 0072/1619] [GFS2] Finish off ioctl support This puts the finishing touches to the ioctl support and also removes a couple of unused fields from GFS2's private per file structure. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 4 ---- fs/gfs2/ops_file.c | 22 +++++++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index b5a994d1b5f..423cfa72b4c 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -277,12 +277,8 @@ enum { struct gfs2_file { unsigned long f_flags; /* GFF_... */ - struct mutex f_fl_mutex; struct gfs2_holder f_fl_gh; - - struct gfs2_inode *f_inode; - struct file *f_vfile; }; struct gfs2_revoke { diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index c44225fa758..9bb29671708 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -572,7 +572,7 @@ static int gfs2_get_flags(struct inode *inode, u32 __user *ptr) 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)) error = -EFAULT; @@ -600,20 +600,22 @@ static int gfs2_get_flags(struct inode *inode, u32 __user *ptr) * @mask: Indicates which flags are valid * */ -static int do_gfs2_set_flags(struct inode *inode, u32 flags, u32 mask) +static int do_gfs2_set_flags(struct inode *inode, u32 reqflags, u32 mask) { struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head *bh; struct gfs2_holder gh; int error; - u32 new_flags; + u32 new_flags, flags; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); if (error) return error; - new_flags = (ip->i_di.di_flags & ~mask) | (flags & mask); + flags = ip->i_di.di_flags; + new_flags = (flags & ~mask) | (reqflags & mask); if ((new_flags ^ flags) == 0) goto out; @@ -640,13 +642,18 @@ static int do_gfs2_set_flags(struct inode *inode, u32 flags, u32 mask) if (error) goto out; - error = gfs2_meta_inode_buffer(ip, &bh); + error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) goto out; + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + 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); brelse(bh); +out_trans_end: + gfs2_trans_end(sdp); out: gfs2_glock_dq_uninit(&gh); return error; @@ -730,9 +737,6 @@ static int gfs2_open(struct inode *inode, struct file *file) mutex_init(&fp->f_fl_mutex); - fp->f_inode = ip; - fp->f_vfile = file; - gfs2_assert_warn(ip->i_sbd, !file->private_data); file->private_data = fp; @@ -875,7 +879,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 = fp->f_inode; + struct gfs2_inode *ip = file->f_dentry->d_inode->u.generic_ip; struct gfs2_glock *gl; unsigned int state; int flags; -- GitLab From b09e593d799560f1a0782c20ac5900058390a26f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 7 Apr 2006 11:17:32 -0400 Subject: [PATCH 0073/1619] [GFS2] Fix a ref count bug and other clean ups This fixes a ref count bug that sometimes showed up a umount time (causing it to hang) but it otherwise mostly harmless. At the same time there are some clean ups including making the log operations structures const, moving a memory allocation so that its not done in the fast path of checking to see if there is an outstanding transaction related to a particular glock. Removes the sd_log_wrap varaible which was updated, but never actually used anywhere. Updates the gfs2 ioctl() to run without the kernel lock (which it never needed anyway). Removes the "invalidate inodes" loop from GFS2's put_super routine. This is done in kill super anyway so we don't need to do it here. The loop was also bogus in that if there are any inodes "stuck" at this point its a bug and we need to know about it rather than hide it by hanging forever. Signed-off-by: Steven Whitehouse --- fs/gfs2/daemon.c | 2 +- fs/gfs2/dir.c | 2 ++ fs/gfs2/glops.c | 6 +++--- fs/gfs2/incore.h | 6 +++--- fs/gfs2/log.c | 33 ++++++++++++++++++--------------- fs/gfs2/log.h | 6 +----- fs/gfs2/lops.c | 14 ++++++++------ fs/gfs2/lops.h | 14 +++++++------- fs/gfs2/meta_io.c | 10 +++++----- fs/gfs2/ops_file.c | 23 ++++++++++++----------- fs/gfs2/ops_fstype.c | 4 ++-- fs/gfs2/ops_super.c | 12 +++--------- fs/gfs2/quota.c | 2 +- fs/gfs2/trans.c | 2 +- 14 files changed, 67 insertions(+), 69 deletions(-) diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index 94317dc7e42..b3830b92d78 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -129,7 +129,7 @@ int gfs2_logd(void *data) gfs2_ail1_empty(sdp, DIO_ALL); if (time_after_eq(jiffies, t)) { - gfs2_log_flush(sdp); + gfs2_log_flush(sdp, NULL); sdp->sd_log_flush_time = jiffies; } diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 66917f2c64a..316eed688f8 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -789,6 +789,8 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, if (error) return ERR_PTR(error); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); + brelse(bh); + got_dent: *pbh = bh; return dent; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d9334eb72df..d180c89dd56 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -45,7 +45,7 @@ static void meta_go_sync(struct gfs2_glock *gl, int flags) return; if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { - gfs2_log_flush_glock(gl); + gfs2_log_flush(gl->gl_sbd, gl); gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); if (flags & DIO_RELEASE) gfs2_ail_empty_gl(gl); @@ -149,12 +149,12 @@ static void inode_go_sync(struct gfs2_glock *gl, int flags) if (test_bit(GLF_DIRTY, &gl->gl_flags)) { if (meta && data) { gfs2_page_sync(gl, flags | DIO_START); - gfs2_log_flush_glock(gl); + gfs2_log_flush(gl->gl_sbd, 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_log_flush(gl->gl_sbd, gl); gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); } else if (data) gfs2_page_sync(gl, flags | DIO_START | DIO_WAIT); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 423cfa72b4c..dfed83b37ab 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -62,12 +62,12 @@ struct gfs2_log_operations { struct gfs2_log_descriptor *ld, __be64 *ptr, int pass); void (*lo_after_scan) (struct gfs2_jdesc *jd, int error, int pass); - char *lo_name; + const char *lo_name; }; struct gfs2_log_element { struct list_head le_list; - struct gfs2_log_operations *le_ops; + const struct gfs2_log_operations *le_ops; }; struct gfs2_bitmap { @@ -618,6 +618,7 @@ struct gfs2_sbd { unsigned int sd_log_num_rg; unsigned int sd_log_num_databuf; unsigned int sd_log_num_jdata; + unsigned int sd_log_num_hdrs; struct list_head sd_log_le_gl; struct list_head sd_log_le_buf; @@ -631,7 +632,6 @@ struct gfs2_sbd { 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; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index ea69376c00d..cadfef193e5 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -171,13 +171,14 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) while(sdp->sd_log_blks_free <= blks) { gfs2_log_unlock(sdp); gfs2_ail1_empty(sdp, 0); - gfs2_log_flush(sdp); + gfs2_log_flush(sdp, NULL); if (try++) gfs2_ail1_start(sdp, 0); gfs2_log_lock(sdp); } sdp->sd_log_blks_free -= blks; + /* printk(KERN_INFO "reserved %u blocks (%u left)\n", blks, sdp->sd_log_blks_free); */ gfs2_log_unlock(sdp); mutex_unlock(&sdp->sd_log_reserve_mutex); @@ -199,6 +200,7 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) gfs2_log_lock(sdp); sdp->sd_log_blks_free += blks; + /* printk(KERN_INFO "released %u blocks (%u left)\n", blks, sdp->sd_log_blks_free); */ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); @@ -342,6 +344,7 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) gfs2_log_lock(sdp); sdp->sd_log_blks_free += dist - ((pull) ? 1 : 0); + /* printk(KERN_INFO "pull tail refunding %u blocks (%u left) pull=%d\n", dist - ((pull) ? 1 : 0), sdp->sd_log_blks_free, pull); */ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); @@ -364,6 +367,8 @@ static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) unsigned int tail; uint32_t hash; + /* printk(KERN_INFO "log write header start (flags=%08x, pull=%d)\n", flags, pull); */ + bh = sb_getblk(sdp->sd_vfs, blkno); lock_buffer(bh); memset(bh->b_data, 0, bh->b_size); @@ -398,6 +403,8 @@ static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); log_incr_head(sdp); + + /* printk(KERN_INFO "log write header out\n"); */ } static void log_flush_commit(struct gfs2_sbd *sdp) @@ -432,20 +439,16 @@ static void log_flush_commit(struct gfs2_sbd *sdp) } /** - * gfs2_log_flush_i - flush incore transaction(s) + * gfs2_log_flush - 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) +void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) { struct gfs2_ail *ai; - ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); - INIT_LIST_HEAD(&ai->ai_ail1_list); - INIT_LIST_HEAD(&ai->ai_ail2_list); - down_write(&sdp->sd_log_flush_lock); if (gl) { @@ -453,12 +456,14 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) if (list_empty(&gl->gl_le.le_list)) { gfs2_log_unlock(sdp); up_write(&sdp->sd_log_flush_lock); - kfree(ai); return; } gfs2_log_unlock(sdp); } + ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); + INIT_LIST_HEAD(&ai->ai_ail1_list); + INIT_LIST_HEAD(&ai->ai_ail2_list); gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf == sdp->sd_log_commited_buf); @@ -476,11 +481,12 @@ void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) 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++; + + /* printk(KERN_INFO "sd_log_num_hdrs %u\n", sdp->sd_log_num_hdrs); */ sdp->sd_log_blks_reserved = sdp->sd_log_commited_buf = + sdp->sd_log_num_hdrs = sdp->sd_log_commited_revoke = 0; gfs2_log_lock(sdp); @@ -519,8 +525,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 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 >= old); gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); @@ -548,7 +553,7 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *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); + gfs2_log_flush(sdp, NULL); } else gfs2_log_unlock(sdp); } @@ -583,8 +588,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) 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_write(&sdp->sd_log_flush_lock); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index e7a6a65c530..84a3e902e84 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -37,7 +37,6 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp, { if (++value == sdp->sd_jdesc->jd_blocks) { value = 0; - sdp->sd_log_wraps++; } sdp->sd_log_head = sdp->sd_log_tail = value; } @@ -54,10 +53,7 @@ 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_flush(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); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 689c9101c0f..4d90eb31149 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -130,6 +130,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) if (total > limit) num = limit; bh = gfs2_log_get_buf(sdp); + sdp->sd_log_num_hdrs++; ld = (struct gfs2_log_descriptor *)bh->b_data; ptr = (__be64 *)(bh->b_data + offset); ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); @@ -570,6 +571,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) gfs2_log_unlock(sdp); if (!bh) { bh = gfs2_log_get_buf(sdp); + sdp->sd_log_num_hdrs++; ld = (struct gfs2_log_descriptor *) bh->b_data; ptr = (__be64 *)(bh->b_data + offset); @@ -750,13 +752,13 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) } -struct gfs2_log_operations gfs2_glock_lops = { +const 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 = { +const 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, @@ -767,7 +769,7 @@ struct gfs2_log_operations gfs2_buf_lops = { .lo_name = "buf" }; -struct gfs2_log_operations gfs2_revoke_lops = { +const 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, @@ -776,13 +778,13 @@ struct gfs2_log_operations gfs2_revoke_lops = { .lo_name = "revoke" }; -struct gfs2_log_operations gfs2_rg_lops = { +const 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 = { +const 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, @@ -792,7 +794,7 @@ struct gfs2_log_operations gfs2_databuf_lops = { .lo_name = "databuf" }; -struct gfs2_log_operations *gfs2_log_ops[] = { +const struct gfs2_log_operations *gfs2_log_ops[] = { &gfs2_glock_lops, &gfs2_buf_lops, &gfs2_revoke_lops, diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 417f5aade4b..0c78d222d6f 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -10,16 +10,16 @@ #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 const struct gfs2_log_operations gfs2_glock_lops; +extern const struct gfs2_log_operations gfs2_buf_lops; +extern const struct gfs2_log_operations gfs2_revoke_lops; +extern const struct gfs2_log_operations gfs2_rg_lops; +extern const struct gfs2_log_operations gfs2_databuf_lops; -extern struct gfs2_log_operations *gfs2_log_ops[]; +extern const struct gfs2_log_operations *gfs2_log_ops[]; static inline void lops_init_le(struct gfs2_log_element *le, - struct gfs2_log_operations *lops) + const struct gfs2_log_operations *lops) { INIT_LIST_HEAD(&le->le_list); le->le_ops = lops; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index b85fa246466..4a6aacf294d 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -59,11 +59,12 @@ static int gfs2_aspace_writepage(struct page *page, static void stuck_releasepage(struct buffer_head *bh) { - struct gfs2_sbd *sdp = bh->b_page->mapping->host->i_sb->s_fs_info; + 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()\n"); + fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); 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)); @@ -191,7 +192,6 @@ struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) aspace->u.generic_ip = NULL; insert_inode_hash(aspace); } - return aspace; } @@ -353,7 +353,7 @@ void gfs2_ail_empty_gl(struct gfs2_glock *gl) gfs2_log_unlock(sdp); gfs2_trans_end(sdp); - gfs2_log_flush(sdp); + gfs2_log_flush(sdp, NULL); } /** @@ -876,7 +876,7 @@ void gfs2_meta_ra(struct gfs2_glock *gl, uint64_t dblock, uint32_t extlen) void gfs2_meta_syncfs(struct gfs2_sbd *sdp) { - gfs2_log_flush(sdp); + gfs2_log_flush(sdp, NULL); for (;;) { gfs2_ail1_start(sdp, DIO_ALL); if (gfs2_ail1_empty(sdp, DIO_ALL)) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 9bb29671708..3fb1a29f88a 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -561,8 +561,9 @@ static const u32 gfs2_to_iflags[32] = { [gfs2fl_InheritJdata] = IFLAG_INHERITJDATA, }; -static int gfs2_get_flags(struct inode *inode, u32 __user *ptr) +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_holder gh; int error; @@ -600,8 +601,9 @@ static int gfs2_get_flags(struct inode *inode, u32 __user *ptr) * @mask: Indicates which flags are valid * */ -static int do_gfs2_set_flags(struct inode *inode, u32 reqflags, u32 mask) +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 buffer_head *bh; @@ -659,23 +661,22 @@ out: return error; } -static int gfs2_set_flags(struct inode *inode, u32 __user *ptr) +static int gfs2_set_flags(struct file *filp, u32 __user *ptr) { u32 iflags, gfsflags; if (get_user(iflags, ptr)) return -EFAULT; gfsflags = iflags_cvt(iflags_to_gfs2, iflags); - return do_gfs2_set_flags(inode, gfsflags, ~0); + return do_gfs2_set_flags(filp, gfsflags, ~0); } -int gfs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { case IFLAGS_GET_IOC: - return gfs2_get_flags(inode, (u32 __user *)arg); + return gfs2_get_flags(filp, (u32 __user *)arg); case IFLAGS_SET_IOC: - return gfs2_set_flags(inode, (u32 __user *)arg); + return gfs2_set_flags(filp, (u32 __user *)arg); } return -ENOTTY; } @@ -808,7 +809,7 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) { struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; - gfs2_log_flush_glock(ip->i_gl); + gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); return 0; } @@ -974,7 +975,7 @@ struct file_operations gfs2_file_fops = { .write = generic_file_write, .writev = generic_file_writev, .aio_write = generic_file_aio_write, - .ioctl = gfs2_ioctl, + .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, .open = gfs2_open, .release = gfs2_close, @@ -988,7 +989,7 @@ struct file_operations gfs2_file_fops = { struct file_operations gfs2_dir_fops = { .readdir = gfs2_readdir, - .ioctl = gfs2_ioctl, + .unlocked_ioctl = gfs2_ioctl, .open = gfs2_open, .release = gfs2_close, .fsync = gfs2_fsync, diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 5166455b9fd..4538a1e621e 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -276,8 +276,8 @@ static struct inode *gfs2_lookup_root(struct gfs2_sbd *sdp, struct gfs2_inode *ip; struct inode *inode; - error = gfs2_glock_get(sdp, inum->no_addr, - &gfs2_inode_glops, CREATE, &gl); + 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) { diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index f7349c0989a..80ce40c1dfb 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -53,7 +53,7 @@ static int gfs2_write_inode(struct inode *inode, int sync) if (current->flags & PF_MEMALLOC) return 0; if (ip && sync) - gfs2_log_flush_glock(ip->i_gl); + gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); return 0; } @@ -121,10 +121,8 @@ static void gfs2_put_super(struct super_block *sb) } 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); @@ -135,10 +133,6 @@ static void gfs2_put_super(struct super_block *sb) gfs2_sys_fs_del(sdp); - /* Get rid of any extra inodes */ - while (invalidate_inodes(sb)) - yield(); - vfree(sdp); sb->s_fs_info = NULL; @@ -149,13 +143,13 @@ static void gfs2_put_super(struct super_block *sb) * @sb: the filesystem * * This function is called every time sync(2) is called. - * After this exits, all dirty buffers and synced. + * After this exits, all dirty buffers are synced. */ static void gfs2_write_super(struct super_block *sb) { struct gfs2_sbd *sdp = sb->s_fs_info; - gfs2_log_flush(sdp); + gfs2_log_flush(sdp, NULL); } /** diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c57b5cf1d58..90e32a3dc50 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -749,7 +749,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) while (qx--) gfs2_glock_dq_uninit(&ghs[qx]); kfree(ghs); - gfs2_log_flush_glock(ip->i_gl); + gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); return error; } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index d72f79e67c9..061f4a9a1db 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -120,7 +120,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) kfree(tr); if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) - gfs2_log_flush(sdp); + gfs2_log_flush(sdp, NULL); } void gfs2_trans_add_gl(struct gfs2_glock *gl) -- GitLab From ed3865079b573ef55dc13ab0bfb242ed5ebab4c1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 7 Apr 2006 16:28:07 -0400 Subject: [PATCH 0074/1619] [GFS2] Finally get ref counting correct The last patch missed some other instances of incorrect ref counting, this fixes all of those too. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 17 ++++++++++++----- fs/gfs2/log.c | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 316eed688f8..100672d2c6c 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -776,9 +776,9 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, goto got_dent; leaf = (struct gfs2_leaf *)bh->b_data; ln = be64_to_cpu(leaf->lf_next); - brelse(bh); if (!ln) break; + brelse(bh); error = get_leaf(ip, ln, &bh); } while(!error); @@ -789,9 +789,11 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, if (error) return ERR_PTR(error); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); - brelse(bh); - got_dent: + if (unlikely(IS_ERR(dent))) { + brelse(bh); + bh = NULL; + } *pbh = bh; return dent; } @@ -1475,6 +1477,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *name, brelse(bh); return 0; } + brelse(bh); return -ENOENT; } @@ -1616,6 +1619,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) previous entry otherwise */ dent = gfs2_dirent_search(dip->i_vnode, name, gfs2_dirent_prev, &bh); if (!dent) { + brelse(bh); gfs2_consist_inode(dip); return -EIO; } @@ -1636,8 +1640,8 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) if (!entries) gfs2_consist_inode(dip); leaf->lf_entries = cpu_to_be16(--entries); - brelse(bh); } + brelse(bh); error = gfs2_meta_inode_buffer(dip, &bh); if (error) @@ -1676,6 +1680,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, dent = gfs2_dirent_search(dip->i_vnode, filename, gfs2_dirent_find, &bh); if (!dent) { + brelse(bh); gfs2_consist_inode(dip); return -EIO; } @@ -1955,8 +1960,10 @@ int gfs2_diradd_alloc_required(struct inode *inode, struct buffer_head *bh; dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); - if (!dent) + if (!dent) { + brelse(bh); return 1; + } if (IS_ERR(dent)) return PTR_ERR(dent); brelse(bh); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index cadfef193e5..0b26d6a7411 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -196,7 +196,6 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) { - up_read(&sdp->sd_log_flush_lock); gfs2_log_lock(sdp); sdp->sd_log_blks_free += blks; @@ -204,6 +203,7 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); + up_read(&sdp->sd_log_flush_lock); } static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) -- GitLab From f4154ea039bbf45c52840b30c68143a2dc28d4b4 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 11 Apr 2006 14:49:06 -0400 Subject: [PATCH 0075/1619] [GFS2] Update journal accounting code. A small update to the journaling code to change the way that the "extra" blocks are accounted for in the journal. These are used at a rate of one per 503 metadata blocks or one per 251 journaled data blocks (or just one if the total number of journaled blocks in the transaction is smaller). Since we are using them at two different rates the old method of accounting for them no longer works and we count them up as required. Since the "per transaction" accounting can't handle this (there is no fixed number of header blocks per transaction) we have to account for it in the general journal code. We now require that each transaction reserves more blocks than it actually needs to take account of the possible extra blocks. Also a final fix to dir.c to ensure that all ref counts are handled correctly. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 8 ++------ fs/gfs2/log.c | 10 +++++++--- fs/gfs2/trans.c | 13 +++---------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 100672d2c6c..01f89c727cc 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -776,9 +776,9 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, goto got_dent; leaf = (struct gfs2_leaf *)bh->b_data; ln = be64_to_cpu(leaf->lf_next); + brelse(bh); if (!ln) break; - brelse(bh); error = get_leaf(ip, ln, &bh); } while(!error); @@ -790,7 +790,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, return ERR_PTR(error); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); got_dent: - if (unlikely(IS_ERR(dent))) { + if (unlikely(dent == NULL || IS_ERR(dent))) { brelse(bh); bh = NULL; } @@ -1477,7 +1477,6 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *name, brelse(bh); return 0; } - brelse(bh); return -ENOENT; } @@ -1619,7 +1618,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) previous entry otherwise */ dent = gfs2_dirent_search(dip->i_vnode, name, gfs2_dirent_prev, &bh); if (!dent) { - brelse(bh); gfs2_consist_inode(dip); return -EIO; } @@ -1680,7 +1678,6 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, dent = gfs2_dirent_search(dip->i_vnode, filename, gfs2_dirent_find, &bh); if (!dent) { - brelse(bh); gfs2_consist_inode(dip); return -EIO; } @@ -1961,7 +1958,6 @@ int gfs2_diradd_alloc_required(struct inode *inode, dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); if (!dent) { - brelse(bh); return 1; } if (IS_ERR(dent)) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 0b26d6a7411..b0dd0b9ad79 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -412,11 +412,13 @@ 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; +#if 0 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); +#endif while (!list_empty(head)) { lb = list_entry(head->next, struct gfs2_log_buf, lb_list); @@ -483,6 +485,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) sdp->sd_log_head = sdp->sd_log_flush_head; /* printk(KERN_INFO "sd_log_num_hdrs %u\n", sdp->sd_log_num_hdrs); */ + sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs; sdp->sd_log_blks_reserved = sdp->sd_log_commited_buf = @@ -515,8 +518,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 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; + reserved += sdp->sd_log_commited_buf; if (sdp->sd_log_commited_revoke) reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, sizeof(uint64_t)); @@ -527,7 +529,8 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 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_free <= sdp->sd_jdesc->jd_blocks + + sdp->sd_log_num_hdrs); sdp->sd_log_blks_reserved = reserved; @@ -582,6 +585,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0); + /* printk(KERN_INFO "sd_log_blks_free %u, sd_jdesc->jd_blocks %u\n", sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); */ 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); diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 061f4a9a1db..6b02d8c38f0 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -44,7 +44,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, tr->tr_revokes = revokes; tr->tr_reserved = 1; if (blocks) - tr->tr_reserved += 1 + blocks; + tr->tr_reserved += 6 + blocks; if (revokes) tr->tr_reserved += gfs2_struct2blk(sdp, revokes, sizeof(uint64_t)); @@ -83,20 +83,15 @@ fail_holder_uninit: void gfs2_trans_end(struct gfs2_sbd *sdp) { - struct gfs2_trans *tr; + struct gfs2_trans *tr = current->journal_info; - tr = current->journal_info; + BUG_ON(!tr); current->journal_info = NULL; - if (gfs2_assert_warn(sdp, tr)) - return; - if (!tr->tr_touched) { gfs2_log_release(sdp, tr->tr_reserved); - gfs2_glock_dq(&tr->tr_t_gh); gfs2_holder_uninit(&tr->tr_t_gh); - kfree(tr); return; } @@ -113,10 +108,8 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) } gfs2_log_commit(sdp, tr); - gfs2_glock_dq(&tr->tr_t_gh); gfs2_holder_uninit(&tr->tr_t_gh); - kfree(tr); if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) -- GitLab From 4d8012b60e0f0e0217e65f67da7d97276d1824e9 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 12 Apr 2006 17:39:45 -0400 Subject: [PATCH 0076/1619] [GFS2] Fix bug which was causing postmark to fail A typo in the directory code was causing postmark to fail somewhere in the allocation code, since it was unable to find newly allocated directory leaf blocks under certain circumstances. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 01f89c727cc..fe6c5adc5df 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1511,7 +1511,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) brelse(obh); return -ENOSPC; } - oleaf->lf_next = cpu_to_be64(bn); + oleaf->lf_next = cpu_to_be64(bh->b_blocknr); brelse(bh); brelse(obh); @@ -1950,8 +1950,7 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) * Returns: 1 if alloc required, 0 if not, -ve on error */ -int gfs2_diradd_alloc_required(struct inode *inode, - const struct qstr *name) +int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name) { struct gfs2_dirent *dent; struct buffer_head *bh; -- GitLab From fe1bdedc6c16adedc6fd3636185ea91596b1d6eb Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 18 Apr 2006 10:09:15 -0400 Subject: [PATCH 0077/1619] [GFS2] Use vmalloc() in dir code When allocating memory to sort directory entries, use vmalloc() rather than kmalloc() since for larger directories, the required size can easily be graeter than the 128k maximum of kmalloc(). Also adding the first steps towards getting the AOP_TRUNCATED_PAGE return code get in the glock code by flagging all places where we request a glock and we are holding a page lock. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 5 +++-- fs/gfs2/glock.c | 3 +++ fs/gfs2/glock.h | 1 + fs/gfs2/incore.h | 2 +- fs/gfs2/meta_io.c | 2 +- fs/gfs2/ops_address.c | 4 ++-- fs/gfs2/ops_inode.c | 3 +-- fs/gfs2/ops_super.c | 2 -- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index fe6c5adc5df..eb68cdd41d4 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -1290,7 +1291,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, return 0; error = -ENOMEM; - larr = kmalloc((leaves + entries) * sizeof(void*), GFP_KERNEL); + larr = vmalloc((leaves + entries) * sizeof(void*)); if (!larr) goto out; darr = (const struct gfs2_dirent **)(larr + leaves); @@ -1323,7 +1324,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, out_kfree: for(i = 0; i < leaf; i++) brelse(larr[i]); - kfree(larr); + vfree(larr); out: return error; } diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 6a1b42cf4df..4ed13787b7e 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -461,6 +461,9 @@ static void handle_recurse(struct gfs2_holder *gh) struct gfs2_holder *tmp_gh, *safe; int found = 0; + printk(KERN_INFO "recursion %016llx, %u\n", gl->gl_name.ln_number, + gl->gl_name.ln_type); + if (gfs2_assert_warn(sdp, gh->gh_owner)) return; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 560029de8d0..b6646e7fed1 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -27,6 +27,7 @@ #define GL_SYNC 0x00000800 #define GL_NOCANCEL 0x00001000 #define GL_NEVER_RECURSE 0x00002000 +#define GL_AOP 0x00004000 #define GLR_TRYFAILED 13 #define GLR_CANCELED 14 diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index dfed83b37ab..761f00153d4 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -156,7 +156,7 @@ struct gfs2_holder { struct gfs2_glock *gh_gl; struct task_struct *gh_owner; unsigned int gh_state; - int gh_flags; + unsigned gh_flags; int gh_error; unsigned long gh_iflags; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 4a6aacf294d..74cf28e77b4 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -881,7 +881,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) gfs2_ail1_start(sdp, DIO_ALL); if (gfs2_ail1_empty(sdp, DIO_ALL)) break; - msleep(100); + msleep(10); } } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 3fd8c6ec256..005c2522a87 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -216,7 +216,7 @@ static int gfs2_readpage(struct file *file, struct page *page) int error; if (file != &gfs2_internal_file_sentinal) { - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); error = gfs2_glock_nq_m_atime(1, &gh); if (error) goto out_unlock; @@ -267,7 +267,7 @@ static int gfs2_prepare_write(struct file *file, struct page *page, loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; struct gfs2_alloc *al; - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|GL_AOP, &ip->i_gh); error = gfs2_glock_nq_m_atime(1, &ip->i_gh); if (error) goto out_uninit; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 1e2b709711a..62a12a59d91 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -742,8 +742,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_gunlock_q; - error = gfs2_trans_begin(sdp, - sdp->sd_max_dirres + + 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 + diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 80ce40c1dfb..60bf2563c7b 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -132,9 +132,7 @@ static void gfs2_put_super(struct super_block *sb) /* At this point, we're through participating in the lockspace */ gfs2_sys_fs_del(sdp); - vfree(sdp); - sb->s_fs_info = NULL; } -- GitLab From 190562bd84a484bf6590425aa2bb4d6d611c112b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 20 Apr 2006 16:57:23 -0400 Subject: [PATCH 0078/1619] [GFS2] Fix a bug: scheduling under a spinlock At some stage, a mutex was added to gfs2_glock_put() without checking all its call sites. Two of them were called from under a spinlock causing random delays at various points and crashes. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 30 ++++++++++++++++++++---------- fs/gfs2/glock.h | 6 +++--- fs/gfs2/inode.c | 2 +- fs/gfs2/log.c | 1 + fs/gfs2/meta_io.c | 2 ++ 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 4ed13787b7e..32cc4005307 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -158,6 +158,7 @@ int gfs2_glock_put(struct gfs2_glock *gl) if (kref_put(&gl->gl_ref, kill_glock)) { list_del_init(&gl->gl_list); write_unlock(&bucket->hb_lock); + BUG_ON(spin_is_locked(&gl->gl_spin)); glock_free(gl); rv = 1; goto out; @@ -353,13 +354,14 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, * */ -void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags, +void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, struct gfs2_holder *gh) { + flags |= GL_NEVER_RECURSE; INIT_LIST_HEAD(&gh->gh_list); gh->gh_gl = gl; gh->gh_ip = (unsigned long)__builtin_return_address(0); - gh->gh_owner = (flags & GL_NEVER_RECURSE) ? NULL : current; + gh->gh_owner = current; gh->gh_state = state; gh->gh_flags = flags; gh->gh_error = 0; @@ -382,10 +384,10 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags, * */ -void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh) +void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh) { gh->gh_state = state; - gh->gh_flags = flags; + gh->gh_flags = flags | GL_NEVER_RECURSE; if (gh->gh_state == LM_ST_EXCLUSIVE) gh->gh_flags |= GL_LOCAL_EXCL; @@ -461,6 +463,8 @@ static void handle_recurse(struct gfs2_holder *gh) struct gfs2_holder *tmp_gh, *safe; int found = 0; + BUG_ON(!spin_is_locked(&gl->gl_spin)); + printk(KERN_INFO "recursion %016llx, %u\n", gl->gl_name.ln_number, gl->gl_name.ln_type); @@ -502,6 +506,8 @@ static void do_unrecurse(struct gfs2_holder *gh) struct gfs2_holder *tmp_gh, *last_gh = NULL; int found = 0; + BUG_ON(!spin_is_locked(&gl->gl_spin)); + if (gfs2_assert_warn(sdp, gh->gh_owner)) return; @@ -676,7 +682,6 @@ static int rq_greedy(struct gfs2_holder *gh) * @gl: the glock * */ - static void run_queue(struct gfs2_glock *gl) { struct gfs2_holder *gh; @@ -779,6 +784,7 @@ void gfs2_glmutex_unlock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); clear_bit(GLF_LOCK, &gl->gl_flags); run_queue(gl); + BUG_ON(!spin_is_locked(&gl->gl_spin)); spin_unlock(&gl->gl_spin); } @@ -1244,7 +1250,7 @@ static int recurse_check(struct gfs2_holder *existing, struct gfs2_holder *new, return 0; - fail: +fail: print_symbol(KERN_WARNING "GFS2: Existing holder from %s\n", existing->gh_ip); print_symbol(KERN_WARNING "GFS2: New holder from %s\n", new->gh_ip); @@ -1263,6 +1269,8 @@ static void add_to_queue(struct gfs2_holder *gh) struct gfs2_glock *gl = gh->gh_gl; struct gfs2_holder *existing; + BUG_ON(!gh->gh_owner); + if (!gh->gh_owner) goto out; @@ -1331,7 +1339,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh) if (!(gh->gh_flags & GL_ASYNC)) { error = glock_wait_internal(gh); if (error == GLR_CANCELED) { - msleep(1000); + msleep(100); goto restart; } } @@ -1360,7 +1368,7 @@ int gfs2_glock_poll(struct gfs2_holder *gh) else if (list_empty(&gh->gh_list)) { if (gh->gh_error == GLR_CANCELED) { spin_unlock(&gl->gl_spin); - msleep(1000); + msleep(100); if (gfs2_glock_nq(gh)) return 1; return 0; @@ -1386,7 +1394,7 @@ int gfs2_glock_wait(struct gfs2_holder *gh) error = glock_wait_internal(gh); if (error == GLR_CANCELED) { - msleep(1000); + msleep(100); gh->gh_flags &= ~GL_ASYNC; error = gfs2_glock_nq(gh); } @@ -2217,10 +2225,12 @@ static void clear_glock(struct gfs2_glock *gl) if (!list_empty(&gl->gl_reclaim)) { list_del_init(&gl->gl_reclaim); atomic_dec(&sdp->sd_reclaim_count); + spin_unlock(&sdp->sd_reclaim_lock); released = gfs2_glock_put(gl); gfs2_assert(sdp, !released); + } else { + spin_unlock(&sdp->sd_reclaim_lock); } - spin_unlock(&sdp->sd_reclaim_lock); if (gfs2_glmutex_trylock(gl)) { if (gl->gl_ops == &gfs2_inode_glops) { diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index b6646e7fed1..ed5bc3e6539 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -81,10 +81,10 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, 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, +void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, struct gfs2_holder *gh); -void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh); +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); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6140c2434e8..fb5a4d06e92 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -409,8 +409,8 @@ void gfs2_inode_destroy(struct gfs2_inode *ip) spin_lock(&io_gl->gl_spin); io_gl->gl_object = NULL; - gfs2_glock_put(i_gl); spin_unlock(&io_gl->gl_spin); + gfs2_glock_put(i_gl); gfs2_glock_dq_uninit(&ip->i_iopen_gh); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index b0dd0b9ad79..9e32e0faaf2 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -578,6 +578,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) 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, !sdp->sd_log_num_hdrs); gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); sdp->sd_log_flush_head = sdp->sd_log_head; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 74cf28e77b4..da49973a90d 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -214,6 +214,8 @@ void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) struct buffer_head *bh; int retry; + BUG_ON(!spin_is_locked(&sdp->sd_log_lock)); + do { retry = 0; -- GitLab From c63e31c2cc1ec67372920b5e1aff8204d04dd172 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 20 Apr 2006 17:03:48 -0400 Subject: [PATCH 0079/1619] [GFS2] journal recovery patch This is one of the changes related to journal recovery I mentioned a couple weeks ago. We can get into a situation where there are only readonly nodes currently mounting the fs, but there are journals that need to be recovered. Since the readonly nodes can't recover journals, the next rw mounter needs to go through and check all journals and recover any that are dirty (i.e. what the first node to mount the fs does). This rw mounter needs to skip the journals held by the existing readonly nodes. Skipping those journals amounts to using the TRY flag on the journal locks so acquiring the lock of a journal held by a readonly node will fail instead of blocking indefinately. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 5 ++--- fs/gfs2/recovery.c | 13 +++++-------- fs/gfs2/recovery.h | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 4538a1e621e..70745f3561a 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -444,8 +444,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) 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); + error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x)); if (error) { fs_err(sdp, "error recovering journal %u: %d\n", x, error); @@ -455,7 +454,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) gfs2_lm_others_may_mount(sdp); } else if (!sdp->sd_args.ar_spectator) { - error = gfs2_recover_journal(sdp->sd_jdesc, WAIT); + error = gfs2_recover_journal(sdp->sd_jdesc); if (error) { fs_err(sdp, "error recovering my journal: %d\n", error); goto fail_jinode_gh; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 68c85610fb5..e91c2bda6c3 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -418,7 +418,6 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) /** * 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. @@ -426,7 +425,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) * Returns: errno */ -int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) +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; @@ -441,12 +440,10 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) /* Aquire the journal lock so we can do recovery */ - error = gfs2_glock_nq_num(sdp, - jd->jd_jid, &gfs2_journal_glops, + 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); + LM_FLAG_NOEXP | LM_FLAG_TRY | GL_NOCACHE, + &j_gh); switch (error) { case 0: break; @@ -574,7 +571,7 @@ void gfs2_check_journals(struct gfs2_sbd *sdp) break; if (jd != sdp->sd_jdesc) - gfs2_recover_journal(jd, NO_WAIT); + gfs2_recover_journal(jd); } } diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 50d7eb57881..24848118930 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -25,7 +25,7 @@ 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); +int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); void gfs2_check_journals(struct gfs2_sbd *sdp); #endif /* __RECOVERY_DOT_H__ */ -- GitLab From a74604bee27da7c9506114e5710f91f388e98296 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 21 Apr 2006 15:10:46 -0400 Subject: [PATCH 0080/1619] [GFS2] sem -> mutex conversion in locking.c Convert a semaphore to a mutex in locking.c and also tidy up one or two loose ends. Signed-off-by: Steven Whitehouse --- fs/gfs2/locking.c | 34 +++++++++++++++++----------------- fs/gfs2/log.c | 7 +++---- fs/gfs2/util.h | 1 - 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 0f4c50ebcba..6a78aacb26a 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -28,7 +28,7 @@ struct lmh_wrapper { of them by name at mount time, e.g. lock_nolock, lock_dlm. */ static struct list_head lmh_list; -static struct semaphore lmh_lock; +static struct mutex lmh_lock; /** * gfs_register_lockproto - Register a low-level locking protocol @@ -41,11 +41,11 @@ int gfs_register_lockproto(struct lm_lockops *proto) { struct lmh_wrapper *lw; - down(&lmh_lock); + mutex_lock(&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); + mutex_unlock(&lmh_lock); printk(KERN_INFO "GFS2: protocol %s already exists\n", proto->lm_proto_name); return -EEXIST; @@ -54,14 +54,14 @@ int gfs_register_lockproto(struct lm_lockops *proto) lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL); if (!lw) { - up(&lmh_lock); + mutex_unlock(&lmh_lock); return -ENOMEM; } lw->lw_ops = proto; list_add(&lw->lw_list, &lmh_list); - up(&lmh_lock); + mutex_unlock(&lmh_lock); return 0; } @@ -76,18 +76,18 @@ void gfs_unregister_lockproto(struct lm_lockops *proto) { struct lmh_wrapper *lw; - down(&lmh_lock); + mutex_lock(&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); + mutex_unlock(&lmh_lock); kfree(lw); return; } } - up(&lmh_lock); + mutex_unlock(&lmh_lock); printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n", proto->lm_proto_name); @@ -118,7 +118,7 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, int error, found; retry: - down(&lmh_lock); + mutex_lock(&lmh_lock); found = 0; list_for_each_entry(lw, &lmh_list, lw_list) { @@ -131,7 +131,7 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, if (!found) { if (!try && capable(CAP_SYS_MODULE)) { try = 1; - up(&lmh_lock); + mutex_unlock(&lmh_lock); request_module(proto_name); goto retry; } @@ -142,7 +142,7 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, if (!try_module_get(lw->lw_ops->lm_owner)) { try = 0; - up(&lmh_lock); + mutex_unlock(&lmh_lock); msleep(1000); goto retry; } @@ -152,17 +152,17 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, if (error) module_put(lw->lw_ops->lm_owner); out: - up(&lmh_lock); + mutex_unlock(&lmh_lock); return error; } void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct) { - down(&lmh_lock); + mutex_lock(&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); + mutex_unlock(&lmh_lock); } /** @@ -173,16 +173,16 @@ void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct) void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct) { - down(&lmh_lock); + mutex_lock(&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); + mutex_unlock(&lmh_lock); } void __init gfs2_init_lmh(void) { - init_MUTEX(&lmh_lock); + mutex_init(&lmh_lock); INIT_LIST_HEAD(&lmh_list); } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 9e32e0faaf2..134fc57e21d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -587,10 +587,9 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0); /* printk(KERN_INFO "sd_log_blks_free %u, sd_jdesc->jd_blocks %u\n", sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); */ - 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)); + gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); + gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); + gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); sdp->sd_log_head = sdp->sd_log_flush_head; sdp->sd_log_tail = sdp->sd_log_head; diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 4532dbab0a2..c9624c30cad 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -30,7 +30,6 @@ void gfs2_assert_i(struct gfs2_sbd *sdp); do { \ if (unlikely(!(assertion))) { \ gfs2_assert_i(sdp); \ - BUG(); \ } \ } while (0) -- GitLab From 1dde2dbfc70001e2f86b6581baac2f48900b80ed Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 21 Apr 2006 15:39:02 -0400 Subject: [PATCH 0081/1619] [GFS2] Add back missing BUG() Signed-off-by: Steven Whitehouse --- fs/gfs2/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 7cd9e25639c..2fc110208d0 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -32,6 +32,7 @@ void gfs2_assert_i(struct gfs2_sbd *sdp) { printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n", sdp->sd_fsname); + BUG(); } /** -- GitLab From 1e09ae544eb1a2d11b04c6924f738a310c7a7a2b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 21 Apr 2006 15:52:46 -0400 Subject: [PATCH 0082/1619] [GFS2] Move BUG() back into the header file In order to make the file and line number reporting work correctly, this has been moved back into the header file. Signed-off-by: Steven Whitehouse --- fs/gfs2/util.c | 1 - fs/gfs2/util.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 2fc110208d0..7cd9e25639c 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -32,7 +32,6 @@ void gfs2_assert_i(struct gfs2_sbd *sdp) { printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n", sdp->sd_fsname); - BUG(); } /** diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index c9624c30cad..4532dbab0a2 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -30,6 +30,7 @@ void gfs2_assert_i(struct gfs2_sbd *sdp); do { \ if (unlikely(!(assertion))) { \ gfs2_assert_i(sdp); \ + BUG(); \ } \ } while (0) -- GitLab From 61e085a88cb59232eb8ff5b446d70491c7bf2c68 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 24 Apr 2006 10:07:13 -0400 Subject: [PATCH 0083/1619] [GFS2] Tidy up dir code as per Christoph Hellwig's comments 1. Comment whitespace fix 2. Removed unused header files from dir.c 3. Split the gfs2_dir_get_buffer() function into two functions Cc: Christoph Hellwig Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 2 +- fs/gfs2/dir.c | 144 +++++++++++++++++++++++++------------------------ fs/gfs2/dir.h | 4 +- 3 files changed, 78 insertions(+), 72 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index c7723119acb..68bc3be09c9 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -111,7 +111,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, if (isdir) { block = gfs2_alloc_meta(ip); - error = gfs2_dir_get_buffer(ip, block, 1, &bh); + error = gfs2_dir_get_new_buffer(ip, block, &bh); if (error) goto out_brelse; gfs2_buffer_copy_tail(bh, diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index eb68cdd41d4..ffc1beff670 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -8,61 +8,59 @@ */ /* -* 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. -*/ + * 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 #include -#include #include "gfs2.h" #include "lm_interface.h" @@ -92,33 +90,36 @@ typedef int (*leaf_call_t) (struct gfs2_inode *dip, uint32_t index, uint32_t len, uint64_t leaf_no, void *data); -int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, - struct buffer_head **bhp) + +int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, + 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; - } - } + 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)); *bhp = bh; return 0; } +static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, uint64_t block, + struct buffer_head **bhp) +{ + struct buffer_head *bh; + int error; + 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; +} static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, unsigned int offset, unsigned int size) @@ -205,9 +206,11 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, goto fail; } - error = gfs2_dir_get_buffer(ip, dblock, - (amount == sdp->sd_jbsize) ? - 1 : new, &bh); + if (amount == sdp->sd_jbsize || new) + error = gfs2_dir_get_new_buffer(ip, dblock, &bh); + else + error = gfs2_dir_get_existing_buffer(ip, dblock, &bh); + if (error) goto fail; @@ -321,7 +324,10 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, gfs2_meta_ra(ip->i_gl, dblock, extlen); if (dblock) { - error = gfs2_dir_get_buffer(ip, dblock, new, &bh); + if (new) + error = gfs2_dir_get_new_buffer(ip, dblock, &bh); + else + error = gfs2_dir_get_existing_buffer(ip, dblock, &bh); if (error) goto fail; dblock++; diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 42b3a1f34de..d209f1fcb8a 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -41,8 +41,8 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); 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); +int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, + struct buffer_head **bhp); static inline uint32_t gfs2_disk_hash(const char *data, int len) { -- GitLab From b800a1cb3940f216c4e5c963007a1f72fca0f15f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 24 Apr 2006 13:13:56 -0400 Subject: [PATCH 0084/1619] [GFS2] Tidy up daemon.c As per Andrew Morton's comments, remove uneeded casts and use wait_event_interruptible() rather than open code the wait. Cc: Andrew Morton Signed-off-by: Steven Whitehouse --- fs/gfs2/daemon.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index b3830b92d78..c2b5d69044c 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -45,7 +45,7 @@ int gfs2_scand(void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + struct gfs2_sbd *sdp = data; unsigned long t; while (!kthread_should_stop()) { @@ -67,20 +67,15 @@ int gfs2_scand(void *data) int gfs2_glockd(void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; - DECLARE_WAITQUEUE(wait_chan, current); + struct gfs2_sbd *sdp = data; 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); + wait_event_interruptible(sdp->sd_reclaim_wq, + (atomic_read(&sdp->sd_reclaim_count) || + kthread_should_stop())); } return 0; @@ -94,7 +89,7 @@ int gfs2_glockd(void *data) int gfs2_recoverd(void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + struct gfs2_sbd *sdp = data; unsigned long t; while (!kthread_should_stop()) { @@ -116,7 +111,7 @@ int gfs2_recoverd(void *data) int gfs2_logd(void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + struct gfs2_sbd *sdp = data; struct gfs2_holder ji_gh; unsigned long t; @@ -159,7 +154,7 @@ int gfs2_logd(void *data) int gfs2_quotad(void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + struct gfs2_sbd *sdp = data; unsigned long t; int error; @@ -209,7 +204,7 @@ int gfs2_quotad(void *data) int gfs2_inoded(void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + struct gfs2_sbd *sdp = data; unsigned long t; int error; -- GitLab From b5ea3e1ef307548bdd40fff6aba5fc96b002f284 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 24 Apr 2006 14:14:42 -0400 Subject: [PATCH 0085/1619] [GFS2] Tidy up Makefile & Kconfig Remove select of SYSFS as requested by Greg KH. Change whitespace to tabs rather than spaces in places where it was incorrect and removed 'default m' as suggested by Adrian Bunk. Reorganised Makefile as suggested by Sam Ravnborg. Cc: Sam Ravnborg Cc: Adrian Bunk Cc: Greg KH Signed-off-by: Steven Whitehouse --- fs/gfs2/Kconfig | 26 ++++++++++++-------------- fs/gfs2/Makefile | 42 +++++------------------------------------- 2 files changed, 17 insertions(+), 51 deletions(-) diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 17cb44bea1c..115f30d8c22 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -1,19 +1,17 @@ config GFS2_FS - tristate "GFS2 file system support" - default m + tristate "GFS2 file system support" 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. + select FS_POSIX_ACL + 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 diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 88f92794811..66de2cc7bb5 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -1,41 +1,9 @@ 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 \ - 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 +gfs2-y := acl.o bits.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 obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/ -- GitLab From 4bcf7091f9da595016f9d1175aa1bea8e736566f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 25 Apr 2006 13:20:27 -0400 Subject: [PATCH 0086/1619] [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(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 3fb1a29f88a..c2dbc300a50 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 1b4d9ef5d62..5b27102dfea 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__ -- GitLab From 96c2c0083d76ca80d546a53089c86e74fbfbe791 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 25 Apr 2006 13:23:09 -0400 Subject: [PATCH 0087/1619] [DLM] Update Kconfig in the light of comments on lkml We now depend on user selectable options rather than select them. There is no dependancy on SYSFS since this selection is independant of the DLM (even though it wouldn't be sensible to build the DLM without it) Signed-off-by: Steven Whitehouse --- fs/dlm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig index d01f735e6e0..09e78bf6e7a 100644 --- a/fs/dlm/Kconfig +++ b/fs/dlm/Kconfig @@ -3,9 +3,8 @@ menu "Distributed Lock Manager" config DLM tristate "Distributed Lock Manager (DLM)" - depends on SYSFS depends on IPV6 || IPV6=n - select IP_SCTP + depends on IP_SCTP select CONFIGFS_FS help A general purpose distributed lock manager for kernel or userspace -- GitLab From 714dc65c34385afbc21342f5bee8d0d25027ac9a Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Tue, 25 Apr 2006 14:49:01 -0400 Subject: [PATCH 0088/1619] [DLM] Convert a semaphore to a completion Convert a semaphore into a completion in device.c. Cc: David Teigland Cc: Andrew Morton Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/device.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 99d8b6b07fb..5da4b2ed988 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -79,7 +79,7 @@ struct lock_info { struct list_head li_ownerqueue; struct file_info *li_file; struct dlm_lksb __user *li_user_lksb; - struct semaphore li_firstlock; + struct completion li_firstcomp; }; /* A queued AST no less */ @@ -376,8 +376,7 @@ static void ast_routine(void *param) li->li_lksb.sb_status != 0) { /* Wait till dlm_lock() has finished */ - down(&li->li_firstlock); - up(&li->li_firstlock); + wait_for_completion(&li->li_firstcomp); spin_lock(&li->li_file->fi_li_lock); list_del(&li->li_ownerqueue); @@ -808,10 +807,10 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, li->li_castaddr = kparams->castaddr; li->li_castparam = kparams->castparam; - /* OK, this isn;t exactly a FIRSTLOCK but it is the + /* 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); + init_completion(&li->li_firstcomp); set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); add_lockinfo(li); @@ -839,10 +838,10 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, if (!li) return -ENOMEM; - /* semaphore to allow us to complete our work before + /* 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); + init_completion(&li->li_firstcomp); set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); } @@ -892,7 +891,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, if (add_lockinfo(li)) printk(KERN_WARNING "Add lockinfo failed\n"); - up(&li->li_firstlock); + complete(&li->li_firstcomp); } /* Return the lockid as the user needs it /now/ */ @@ -936,8 +935,7 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, /* Wait until dlm_lock() has completed */ if (!test_bit(LI_FLAG_ONLIST, &li->li_flags)) { - down(&li->li_firstlock); - up(&li->li_firstlock); + wait_for_completion(&li->li_firstcomp); } /* dlm_unlock() passes a 0 for castaddr which means don't overwrite -- GitLab From 373b5a453255b6a013b9d20116918f09a1ceeccc Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Apr 2006 15:44:04 -0400 Subject: [PATCH 0089/1619] [GFS2] Update documentation Updated information on the GFS2 tools Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- Documentation/filesystems/gfs2.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt index a20ba19e9fe..593004b6bba 100644 --- a/Documentation/filesystems/gfs2.txt +++ b/Documentation/filesystems/gfs2.txt @@ -34,11 +34,10 @@ needed, simply: GFS2 is not on-disk compatible with previous versions of GFS. The following man pages can be found at the URL above: - gfs2_mkfs to make a filesystem gfs2_fsck to repair a filesystem gfs2_grow to expand a filesystem online gfs2_jadd to add journals to a filesystem online gfs2_tool to manipulate, examine and tune a filesystem gfs2_quota to examine and change quota values in a filesystem - mount.gfs2 to find mount options - + mount.gfs2 to help mount(8) mount a filesystem + mkfs.gfs2 to make a filesystem -- GitLab From 3a2a9c96ac129d17aad1a5c46988ad28f72564b0 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Apr 2006 15:45:51 -0400 Subject: [PATCH 0090/1619] [GFS2] Update plock code in DLM locking module We should be using fl_pid not fl_owner. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/plock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index f7ac5821def..86312d96147 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -70,7 +70,7 @@ int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, return -ENOMEM; op->info.optype = GDLM_PLOCK_OP_LOCK; - op->info.pid = (uint32_t) fl->fl_owner; + op->info.pid = fl->fl_pid; op->info.ex = (fl->fl_type == F_WRLCK); op->info.wait = IS_SETLKW(cmd); op->info.fsid = ls->id; @@ -116,7 +116,7 @@ int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, name->ln_type, name->ln_number); op->info.optype = GDLM_PLOCK_OP_UNLOCK; - op->info.pid = (uint32_t) fl->fl_owner; + op->info.pid = fl->fl_pid; op->info.fsid = ls->id; op->info.number = name->ln_number; op->info.start = fl->fl_start; @@ -150,7 +150,7 @@ int gdlm_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, return -ENOMEM; op->info.optype = GDLM_PLOCK_OP_GET; - op->info.pid = (uint32_t) fl->fl_owner; + op->info.pid = fl->fl_pid; op->info.ex = (fl->fl_type == F_WRLCK); op->info.fsid = ls->id; op->info.number = name->ln_number; -- GitLab From 5965b1f4792a1a9364b4e1ed6be8778a50eb981b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 26 Apr 2006 13:21:55 -0400 Subject: [PATCH 0091/1619] [GFS2] Don't do recursive locking in glock layer This patch changes the last user of recursive locking so that it no longer needs this feature and removes it from the glock layer. This makes the glock code a lot simpler and easier to understand. Its also a prerequsite to adding support for the AOP_TRUNCATED_PAGE return code (or at least it is if you don't want your brain to melt in the process) I've left in a couple of checks just in case there is some place else in the code which is still using this feature that I didn't spot yet, but they can probably be removed long term. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 162 ++------------------------------------------- fs/gfs2/incore.h | 1 - fs/gfs2/recovery.c | 79 +++++++++++----------- 3 files changed, 46 insertions(+), 196 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 32cc4005307..0f317155915 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -449,86 +449,6 @@ void gfs2_holder_put(struct gfs2_holder *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; - - BUG_ON(!spin_is_locked(&gl->gl_spin)); - - printk(KERN_INFO "recursion %016llx, %u\n", gl->gl_name.ln_number, - gl->gl_name.ln_type); - - 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; - - BUG_ON(!spin_is_locked(&gl->gl_spin)); - - 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 @@ -562,7 +482,6 @@ 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)) { @@ -588,7 +507,6 @@ static int rq_promote(struct gfs2_holder *gh) 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) @@ -597,16 +515,12 @@ static int rq_promote(struct gfs2_holder *gh) 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; @@ -897,8 +811,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) 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)) { @@ -922,8 +834,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) 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)) { @@ -941,8 +851,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) 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 { @@ -1161,8 +1069,6 @@ static int glock_wait_internal(struct gfs2_holder *gh) !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; @@ -1191,9 +1097,6 @@ static int glock_wait_internal(struct gfs2_holder *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); } } @@ -1202,8 +1105,6 @@ static int glock_wait_internal(struct gfs2_holder *gh) 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); } @@ -1224,40 +1125,6 @@ find_holder_by_owner(struct list_head *head, struct task_struct *owner) 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: - print_symbol(KERN_WARNING "GFS2: Existing holder from %s\n", - existing->gh_ip); - print_symbol(KERN_WARNING "GFS2: New holder from %s\n", new->gh_ip); - 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 @@ -1271,37 +1138,20 @@ static void add_to_queue(struct gfs2_holder *gh) BUG_ON(!gh->gh_owner); - 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; + print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); + print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + BUG(); } 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; + print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); + print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + BUG(); } - out: if (gh->gh_flags & LM_FLAG_PRIORITY) list_add(&gh->gh_list, &gl->gl_waiters3); else diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 761f00153d4..84dd2f579e6 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -146,7 +146,6 @@ enum { HIF_DEALLOC = 5, HIF_HOLDER = 6, HIF_FIRST = 7, - HIF_RECURSE = 8, HIF_ABORTED = 9, }; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index e91c2bda6c3..7d467966f92 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -436,30 +436,35 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) 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 | LM_FLAG_TRY | GL_NOCACHE, - &j_gh); - switch (error) { - case 0: - break; + if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) { + fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n", + jd->jd_jid); - case GLR_TRYFAILED: - fs_info(sdp, "jid=%u: Busy\n", jd->jd_jid); - error = 0; + /* Aquire the journal lock so we can do recovery */ - default: - goto fail; - }; + error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops, + LM_ST_EXCLUSIVE, + LM_FLAG_NOEXP | 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(ip->i_gl, LM_ST_SHARED, - LM_FLAG_NOEXP, &ji_gh); - if (error) - goto fail_gunlock_j; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, + LM_FLAG_NOEXP, &ji_gh); + if (error) + goto fail_gunlock_j; + } else { + fs_info(sdp, "jid=%u, already locked for use\n", jd->jd_jid); + } fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid); @@ -481,10 +486,8 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, - LM_FLAG_NOEXP | - LM_FLAG_PRIORITY | - GL_NEVER_RECURSE | - GL_NOCANCEL | + LM_FLAG_NOEXP | LM_FLAG_PRIORITY | + GL_NEVER_RECURSE | GL_NOCANCEL | GL_NOCACHE, &t_gh); if (error) @@ -521,37 +524,35 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) goto fail_gunlock_tr; gfs2_glock_dq_uninit(&t_gh); - t = DIV_ROUND_UP(jiffies - t, HZ); - fs_info(sdp, "jid=%u: Journal replayed in %lus\n", jd->jd_jid, t); } - gfs2_glock_dq_uninit(&ji_gh); + if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) + gfs2_glock_dq_uninit(&ji_gh); gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS); - gfs2_glock_dq_uninit(&j_gh); + if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) + gfs2_glock_dq_uninit(&j_gh); fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); - return 0; - fail_gunlock_tr: +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); +fail_gunlock_ji: + if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) { + 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: +fail: gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); - return error; } -- GitLab From 579b78a43b366d51f9c888afaf1eab1f4ea599fa Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 26 Apr 2006 14:58:26 -0400 Subject: [PATCH 0092/1619] [GFS2] Remove GL_NEVER_RECURSE flag There is no point in keeping this flag since recursion is not now allowed for any glock. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 10 ++++------ fs/gfs2/glock.h | 1 - fs/gfs2/ops_fstype.c | 10 +++++----- fs/gfs2/recovery.c | 3 +-- fs/gfs2/super.c | 6 +++--- fs/gfs2/trans.c | 3 +-- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 0f317155915..67e3f2a4d10 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -357,7 +357,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, struct gfs2_holder *gh) { - flags |= GL_NEVER_RECURSE; INIT_LIST_HEAD(&gh->gh_list); gh->gh_gl = gl; gh->gh_ip = (unsigned long)__builtin_return_address(0); @@ -387,7 +386,7 @@ 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) { gh->gh_state = state; - gh->gh_flags = flags | GL_NEVER_RECURSE; + gh->gh_flags = flags; if (gh->gh_state == LM_ST_EXCLUSIVE) gh->gh_flags |= GL_LOCAL_EXCL; @@ -731,8 +730,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state) } else { spin_unlock(&gl->gl_spin); - new_gh = gfs2_holder_get(gl, state, - LM_FLAG_TRY | GL_NEVER_RECURSE, + new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_KERNEL | __GFP_NOFAIL), set_bit(HIF_DEMOTE, &new_gh->gh_iflags); set_bit(HIF_DEALLOC, &new_gh->gh_iflags); @@ -1336,7 +1334,7 @@ void gfs2_glock_force_drop(struct gfs2_glock *gl) { struct gfs2_holder gh; - gfs2_holder_init(gl, LM_ST_UNLOCKED, GL_NEVER_RECURSE, &gh); + gfs2_holder_init(gl, LM_ST_UNLOCKED, 0, &gh); set_bit(HIF_DEMOTE, &gh.gh_iflags); spin_lock(&gl->gl_spin); @@ -1401,7 +1399,7 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time) } gh = &gr->gr_gh; - gfs2_holder_init(gl, 0, GL_NEVER_RECURSE, gh); + gfs2_holder_init(gl, 0, 0, gh); set_bit(HIF_GREEDY, &gh->gh_iflags); INIT_WORK(&gr->gr_work, greedy_work, gr); diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index ed5bc3e6539..6f9c88ed538 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -26,7 +26,6 @@ #define GL_NOCACHE 0x00000400 #define GL_SYNC 0x00000800 #define GL_NOCANCEL 0x00001000 -#define GL_NEVER_RECURSE 0x00002000 #define GL_AOP 0x00004000 #define GLR_TRYFAILED 13 diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 70745f3561a..d19d98766aa 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -223,7 +223,7 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, error = gfs2_glock_nq_num(sdp, GFS2_LIVE_LOCK, &gfs2_nondisk_glops, LM_ST_SHARED, - LM_FLAG_NOEXP | GL_EXACT | GL_NEVER_RECURSE, + LM_FLAG_NOEXP | GL_EXACT, &sdp->sd_live_gh); if (error) { fs_err(sdp, "can't acquire live glock: %d\n", error); @@ -638,7 +638,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ip = sdp->sd_ir_inode->u.generic_ip; error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + LM_ST_EXCLUSIVE, 0, &sdp->sd_ir_gh); if (error) { fs_err(sdp, "can't lock local \"ir\" file: %d\n", error); @@ -647,7 +647,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ip = sdp->sd_sc_inode->u.generic_ip; error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + LM_ST_EXCLUSIVE, 0, &sdp->sd_sc_gh); if (error) { fs_err(sdp, "can't lock local \"sc\" file: %d\n", error); @@ -656,7 +656,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ip = sdp->sd_ut_inode->u.generic_ip; error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + LM_ST_EXCLUSIVE, 0, &sdp->sd_ut_gh); if (error) { fs_err(sdp, "can't lock local \"ut\" file: %d\n", error); @@ -665,7 +665,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ip = sdp->sd_qc_inode->u.generic_ip; error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + LM_ST_EXCLUSIVE, 0, &sdp->sd_qc_gh); if (error) { fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 7d467966f92..d916817fb6e 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -487,8 +487,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) 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, + GL_NOCANCEL | GL_NOCACHE, &t_gh); if (error) goto fail_gunlock_ji; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index a4da649d086..f0dbd2d7aad 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -469,7 +469,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) int error; error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, - GL_LOCAL_EXCL | GL_NEVER_RECURSE, &t_gh); + GL_LOCAL_EXCL, &t_gh); if (error) return error; @@ -530,7 +530,7 @@ int gfs2_make_fs_ro(struct gfs2_sbd *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, + GL_LOCAL_EXCL | GL_NOCACHE, &t_gh); if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) return error; @@ -869,7 +869,7 @@ int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) } error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED, - LM_FLAG_PRIORITY | GL_NEVER_RECURSE | GL_NOCACHE, + LM_FLAG_PRIORITY | GL_NOCACHE, t_gh); list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 6b02d8c38f0..18c606d0712 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -50,8 +50,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, sizeof(uint64_t)); INIT_LIST_HEAD(&tr->tr_list_buf); - gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, - GL_NEVER_RECURSE, &tr->tr_t_gh); + gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &tr->tr_t_gh); error = gfs2_glock_nq(&tr->tr_t_gh); if (error) -- GitLab From 6bd70aba5ab453459bb53b1e29f0e0650d6c311f Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 26 Apr 2006 15:56:35 -0400 Subject: [PATCH 0093/1619] [DLM] lock_dlm recover_status patch This saves the journal recovery result and makes it visible through sysfs. User space needs to know if the node actually recovered the journal or tried and gave up. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/lock_dlm.h | 1 + fs/gfs2/locking/dlm/mount.c | 1 + fs/gfs2/locking/dlm/sysfs.c | 25 ++++++++++++++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 6d76146953c..e6c1e4786fe 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -70,6 +70,7 @@ struct gdlm_ls { lm_fsdata_t *fsdata; int recover_jid; int recover_jid_done; + int recover_jid_status; spinlock_t async_lock; struct list_head complete; struct list_head blocking; diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 026f05ce168..aa79fbecaf6 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -203,6 +203,7 @@ static void gdlm_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, { struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; ls->recover_jid_done = jid; + ls->recover_jid_status = message; kobject_uevent(&ls->kobj, KOBJ_CHANGE); } diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index e1e5186c97c..0d8bd0806db 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -110,6 +110,11 @@ static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf) return sprintf(buf, "%d\n", ls->recover_jid_done); } +static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->recover_jid_status); +} + struct gdlm_attr { struct attribute attr; ssize_t (*show)(struct gdlm_ls *, char *); @@ -119,15 +124,16 @@ struct gdlm_attr { #define GDLM_ATTR(_name,_mode,_show,_store) \ static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) -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); +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); +GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); static struct attribute *gdlm_attrs[] = { &gdlm_attr_proto_name.attr, @@ -139,6 +145,7 @@ static struct attribute *gdlm_attrs[] = { &gdlm_attr_first_done.attr, &gdlm_attr_recover.attr, &gdlm_attr_recover_done.attr, + &gdlm_attr_recover_status.attr, NULL, }; -- GitLab From e7f5c01caddbad150dcf003f76cd5aac413f4c50 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 27 Apr 2006 11:25:45 -0400 Subject: [PATCH 0094/1619] [GFS2] Remove redundant casts to/from void Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 11 +++++------ fs/gfs2/locking/dlm/lock.c | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 67e3f2a4d10..17d474fab5a 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1348,7 +1348,7 @@ void gfs2_glock_force_drop(struct gfs2_glock *gl) static void greedy_work(void *data) { - struct greedy *gr = (struct greedy *)data; + struct greedy *gr = data; struct gfs2_holder *gh = &gr->gr_gh; struct gfs2_glock *gl = gh->gh_gl; struct gfs2_glock_operations *glops = gl->gl_ops; @@ -1745,19 +1745,19 @@ void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data) switch (type) { case LM_CB_NEED_E: - blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_UNLOCKED); + blocking_cb(sdp, data, LM_ST_UNLOCKED); return; case LM_CB_NEED_D: - blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_DEFERRED); + blocking_cb(sdp, data, LM_ST_DEFERRED); return; case LM_CB_NEED_S: - blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_SHARED); + blocking_cb(sdp, data, LM_ST_SHARED); return; case LM_CB_ASYNC: { - struct lm_async_cb *async = (struct lm_async_cb *)data; + struct lm_async_cb *async = data; struct gfs2_glock *gl; gl = gfs2_glock_find(sdp, &async->lc_name); @@ -1766,7 +1766,6 @@ void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data) if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) gl->gl_req_bh(gl, async->lc_ret); gfs2_glock_put(gl); - return; } diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 1799d2237e7..a309b799dff 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -25,7 +25,7 @@ static void queue_complete(struct gdlm_lock *lp) static inline void gdlm_ast(void *astarg) { - queue_complete((struct gdlm_lock *) astarg); + queue_complete(astarg); } static inline void gdlm_bast(void *astarg, int mode) @@ -257,7 +257,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp) lp->cur, lp->req, lp->lkf); error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf, - str.name, str.namelen, 0, gdlm_ast, (void *) lp, + str.name, str.namelen, 0, gdlm_ast, lp, bast ? gdlm_bast : NULL); if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) { -- GitLab From 363275216c1a1b0b82c8419310c194b8c26b9c27 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 28 Apr 2006 10:46:21 -0400 Subject: [PATCH 0095/1619] [GFS2] Reordering in deallocation to avoid recursive locking Despite my earlier careful search, there was a recursive lock left in the deallocation code. This removes it. It also should speed up deallocation be reducing the number of locking operations which take place by using two "try lock" operations on the two locks involved in inode deallocation which allows us to grab the locks out of order (compared with NFS which grabs the inode lock first and the iopen lock later). It is ok for us to fail while doing this since if it does fail it means that someone else is still using the inode and thus it wouldn't be possible to deallocate anyway. This fixes the bug reported to me by Rob Kenna. Cc: Rob Kenna Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 6 ++-- fs/gfs2/inode.c | 95 +++++++++++++++++++++++-------------------------- fs/gfs2/inode.h | 2 +- 3 files changed, 49 insertions(+), 54 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 17d474fab5a..f82ecc0cc8f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1814,7 +1814,7 @@ void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum) if (atomic_read(&ip->i_count)) goto out_unlock; - gfs2_inode_destroy(ip); + gfs2_inode_destroy(ip, 1); out_unlock: gfs2_glmutex_unlock(gl); @@ -1940,7 +1940,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) 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); + gfs2_inode_destroy(ip, 1); } if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && @@ -2083,7 +2083,7 @@ static void clear_glock(struct gfs2_glock *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); + gfs2_inode_destroy(ip, 1); } if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index fb5a4d06e92..9084d6037a0 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -287,7 +287,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) 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) + struct gfs2_inode **ipp, int need_lock) { struct gfs2_sbd *sdp = i_gl->gl_sbd; struct gfs2_inode *ip; @@ -312,11 +312,13 @@ static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, 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; + 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; + } ip->i_iopen_gh.gh_owner = NULL; spin_lock(&io_gl->gl_spin); @@ -376,7 +378,7 @@ int gfs2_inode_get(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, 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); + error = inode_create(i_gl, inum, io_gl, LM_ST_SHARED, ipp, 1); gfs2_glock_put(io_gl); } @@ -398,21 +400,23 @@ void gfs2_inode_put(struct gfs2_inode *ip) atomic_dec(&ip->i_count); } -void gfs2_inode_destroy(struct gfs2_inode *ip) +void gfs2_inode_destroy(struct gfs2_inode *ip, int unlock) { 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, 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); + 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); @@ -493,6 +497,13 @@ static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) * @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 */ @@ -503,33 +514,21 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, 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) { + error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr, + &gfs2_inode_glops, LM_ST_EXCLUSIVE, + LM_FLAG_TRY_1CB, &i_gh); + switch(error) { case 0: break; case GLR_TRYFAILED: - error = 1; + return 1; /* or back off and relock in different order? */ default: - goto out; + 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); - - gfs2_glock_dq(io_gh); + LM_ST_EXCLUSIVE, &ip, 0); if (error) goto out; @@ -568,13 +567,13 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, if (error) goto out_iput; - out_iput: +out_iput: gfs2_glmutex_lock(i_gh.gh_gl); gfs2_inode_put(ip); - gfs2_inode_destroy(ip); + gfs2_inode_destroy(ip, 0); gfs2_glmutex_unlock(i_gh.gh_gl); - out: +out: gfs2_glock_dq_uninit(&i_gh); return error; @@ -589,14 +588,13 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) { - struct gfs2_holder io_gh; 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, &io_gh); + 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; @@ -606,9 +604,8 @@ static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) return error; } - gfs2_glock_dq(&io_gh); - error = inode_dealloc(sdp, ul, &io_gh); - gfs2_holder_uninit(&io_gh); + error = inode_dealloc(sdp, ul, &iogh); + gfs2_glock_dq_uninit(&iogh); return error; } @@ -634,9 +631,7 @@ static int inode_dealloc_uninit(struct gfs2_sbd *sdp, 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_UNLINKED + RES_STATFS, 0); if (error) goto out_gunlock; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 0dd2a26626e..13bc4eacac6 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -39,7 +39,7 @@ int gfs2_inode_get(struct gfs2_glock *i_gl, 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); +void gfs2_inode_destroy(struct gfs2_inode *ip, int unlock); int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); -- GitLab From ae118962b9f8572b5ff00e85c053dbeede2314db Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 28 Apr 2006 10:48:59 -0400 Subject: [PATCH 0096/1619] [DLM] PATCH 1/3 dlm: force free user lockspace Lockspaces created from user space should be forcibly freed without requiring any further user space interaction. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 5da4b2ed988..49a20d54921 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -626,7 +626,7 @@ static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, } if (kparams->flags & DLM_USER_LSFLG_FORCEFREE) - force = 2; + force = 3; status = unregister_lockspace(lsinfo, force); mutex_unlock(&user_ls_lock); -- GitLab From 1c032c03117c014512195f2e33c3af999f132146 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 28 Apr 2006 10:50:41 -0400 Subject: [PATCH 0097/1619] [DLM] PATCH 2/3 dlm: lowcomms close When a node is removed from a lockspace configuration, close our connection to it, clearing any remaining messages for it. Signed-off-by: David Teigland Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/config.c | 2 ++ fs/dlm/lowcomms.c | 21 +++++++++++++++++++++ fs/dlm/lowcomms.h | 1 + fs/dlm/member.c | 1 - 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/fs/dlm/config.c b/fs/dlm/config.c index 87df9616415..88553054bbf 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -17,6 +17,7 @@ #include #include "config.h" +#include "lowcomms.h" /* * /config/dlm//spaces//nodes//nodeid @@ -429,6 +430,7 @@ 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; + dlm_lowcomms_close(cm->nodeid); while (cm->addr_count--) kfree(cm->addr[cm->addr_count]); config_item_put(i); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 09b0124f7fc..cdd168e4bf4 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1063,6 +1063,27 @@ static void dealloc_nodeinfo(void) } } +int dlm_lowcomms_close(int nodeid) +{ + struct nodeinfo *ni; + + ni = nodeid2nodeinfo(nodeid, 0); + if (!ni) + return -1; + + spin_lock(&ni->lock); + if (ni->assoc_id) { + ni->assoc_id = 0; + /* Don't send shutdown here, sctp will just queue it + till the node comes back up! */ + } + spin_unlock(&ni->lock); + + clean_one_writequeue(ni); + clear_bit(NI_INIT_PENDING, &ni->flags); + return 0; +} + static int write_list_empty(void) { int status; diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h index 3af8035ff12..6c04bb09cfa 100644 --- a/fs/dlm/lowcomms.h +++ b/fs/dlm/lowcomms.h @@ -18,6 +18,7 @@ int dlm_lowcomms_init(void); void dlm_lowcomms_exit(void); int dlm_lowcomms_start(void); void dlm_lowcomms_stop(void); +int dlm_lowcomms_close(int nodeid); void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc); void dlm_lowcomms_commit_buffer(void *mh); diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 926cd0cb6bf..cd0c51e724e 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -15,7 +15,6 @@ #include "member.h" #include "recoverd.h" #include "recover.h" -#include "lowcomms.h" #include "rcom.h" #include "config.h" -- GitLab From c56b39cd2c55d521597f04bbd872a08d1c4373ca Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 28 Apr 2006 10:51:53 -0400 Subject: [PATCH 0098/1619] [DLM] PATCH 3/3 dlm: show recover state Expose the current recovery state in sysfs to help in debugging. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lockspace.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index d2ff505d51c..9ed4b70348f 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -21,6 +21,7 @@ #include "config.h" #include "memory.h" #include "lock.h" +#include "recover.h" #ifdef CONFIG_DLM_DEBUG int dlm_create_debug_file(struct dlm_ls *ls); @@ -74,6 +75,12 @@ static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len) return len; } +static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf) +{ + uint32_t status = dlm_recover_status(ls); + return sprintf(buf, "%x\n", status); +} + struct dlm_attr { struct attribute attr; ssize_t (*show)(struct dlm_ls *, char *); @@ -96,10 +103,16 @@ static struct dlm_attr dlm_attr_id = { .store = dlm_id_store }; +static struct dlm_attr dlm_attr_recover_status = { + .attr = {.name = "recover_status", .mode = S_IRUGO}, + .show = dlm_recover_status_show +}; + static struct attribute *dlm_attrs[] = { &dlm_attr_control.attr, &dlm_attr_event.attr, &dlm_attr_id.attr, + &dlm_attr_recover_status.attr, NULL, }; -- GitLab From 08bc2dbc7327e89b9d5b9c8ef9401d1df2622fca Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 28 Apr 2006 10:59:12 -0400 Subject: [PATCH 0099/1619] [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(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 68bc3be09c9..f570d8caef6 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 ee9ec8d7515..23fb6589d5e 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 ffc1beff670..0404783f39b 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 4b9f6cff7a3..1b376eceb6a 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 f83c497eddc..30ec6a09bfd 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 8219d471f06..d3316cab2be 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 2b4152b1fcb..ffd56686225 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 f82ecc0cc8f..0a5a0e87b0a 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 6f9c88ed538..a36b26585fb 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 5b3c56d2df2..06a785e9b58 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 ec812424fde..4ee5c34434b 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 a309b799dff..3b0dfd7ae26 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 e6c1e4786fe..530c2f54258 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 3c9adf18fd9..89728c91665 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 ecd37371eba..97ffac5cdef 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 63b815dad8e..9d72872c6f7 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 1b9eb69b953..3c4c17405e9 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 acfc944ce13..b11e659bdd9 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 90e32a3dc50..942c4c8b9f5 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 005529f6895..1baeeb23d23 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 f0dbd2d7aad..75a8def8d0b 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 6abb7b5c882..175afdde43b 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 3ab40917383..4356e386464 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__ */ -- GitLab From 5be7b50f3227577d651eb6788ffea8272d215b63 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 28 Apr 2006 11:27:32 -0400 Subject: [PATCH 0100/1619] [GFS2] Add suitable Maintainers entries As suggested by Adrian Bunk Signed-off-by: Steven Whithouse --- MAINTAINERS | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d6a8e5b434e..f4bd145c007 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -819,6 +819,16 @@ M: jack@suse.cz L: linux-kernel@vger.kernel.org S: Maintained +DISTRIBUTED LOCK MANAGER +P: Patrick Caulfield +M: pcaulfie@redhat.com +P: David Teigland +M: teigland@redhat.com +L: linux-cluster@redhat.com +W: http://sources.redhat.com/cluster/ +T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git +S: Supported + DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER P: Tobias Ringstrom M: tori@unhappy.mine.nu @@ -1069,6 +1079,14 @@ M: khc@pm.waw.pl W: http://www.kernel.org/pub/linux/utils/net/hdlc/ S: Maintained +GFS2 FILE SYSTEM +P: Steven Whitehouse +M: swhiteho@redhat.com +L: linux-cluster@redhat.com +W: http://sources.redhat.com/cluster/ +T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git +S: Supported + GIGASET ISDN DRIVERS P: Hansjoerg Lipp M: hjlipp@web.de -- GitLab From bac1e07926ae514739e6a12218c8b6ce8ce04514 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 28 Apr 2006 11:29:48 -0400 Subject: [PATCH 0101/1619] [GFS2] Update my Credits file entry Signed-off-by: Steven Whitehouse --- CREDITS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CREDITS b/CREDITS index 787564bc248..529534b61fe 100644 --- a/CREDITS +++ b/CREDITS @@ -3551,11 +3551,11 @@ S: Fargo, North Dakota 58122 S: USA N: Steven Whitehouse -E: SteveW@ACM.org +E: steve@chygwyn.com W: http://www.chygwyn.com/~steve -D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html +D: Linux DECnet project D: Minor debugging of other networking protocols. -D: Misc bug fixes and filesystem development +D: Misc bug fixes and GFS2 filesystem development N: Hans-Joachim Widmaier E: hjw@zvw.de -- GitLab From 56409abbf8a9e3754d752d0189f9b9a609ec78de Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 28 Apr 2006 11:48:45 -0400 Subject: [PATCH 0102/1619] [GFS2] Remove some unused code Remove some of the unused code flagged up by Adrian Bunk. Cc: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 31 ------- fs/gfs2/eattr.c | 27 ------ fs/gfs2/glock.c | 23 ----- fs/gfs2/lvb.c | 9 -- fs/gfs2/ondisk.c | 225 ----------------------------------------------- 5 files changed, 315 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index f570d8caef6..cfe1a428c66 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -48,37 +48,6 @@ struct strip_mine { 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 - */ -#if 0 -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; -} -#endif /* 0 */ - /** * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big * @ip: The GFS2 inode to unstuff diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index d3316cab2be..af4f1c3f592 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -358,33 +358,6 @@ 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) -{ - 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; -} - -#endif /* 0 */ - struct ea_list { struct gfs2_ea_request *ei_er; unsigned int ei_size; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 0a5a0e87b0a..4fb8066dc74 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1328,29 +1328,6 @@ static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, glops->go_xmote_th(gl, state, flags); } -/** - * gfs2_glock_force_drop - Force a glock to be uncached - * @gl: the glock - * - */ -#if 0 -void gfs2_glock_force_drop(struct gfs2_glock *gl) -{ - struct gfs2_holder gh; - - gfs2_holder_init(gl, LM_ST_UNLOCKED, 0, &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); -} -#endif /* 0 */ - static void greedy_work(void *data) { struct greedy *gr = data; diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c index 9d72872c6f7..47867db92ea 100644 --- a/fs/gfs2/lvb.c +++ b/fs/gfs2/lvb.c @@ -43,13 +43,4 @@ 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"); - pv(qb, qb_limit, "%llu"); - pv(qb, qb_warn, "%llu"); - pv(qb, qb_value, "%lld"); -} -#endif /* 0 */ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index b11e659bdd9..f6aba3b156c 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -19,30 +19,6 @@ #define pv(struct, member, fmt) printk(KERN_INFO " "#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 - * - */ -#if 0 -static void print_array(char *title, char *buf, int count) -{ - int x; - - printk(KERN_INFO " %s =\n" KERN_INFO, title); - for (x = 0; x < count; x++) { - printk("%.2X ", (unsigned char)buf[x]); - if (x % 16 == 15) - printk("\n" KERN_INFO); - } - if (x % 16) - printk("\n"); -} -#endif /* 0 */ /* * gfs2_xxx_in - read in an xxx struct @@ -122,24 +98,6 @@ 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); - - 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"); -} -#endif /* 0 */ - void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) { struct gfs2_rindex *str = (struct gfs2_rindex *)buf; @@ -152,23 +110,6 @@ 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; - - 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)); -} - -#endif /* 0 */ - void gfs2_rindex_print(struct gfs2_rindex *ri) { pv(ri, ri_addr, "%llu"); @@ -202,18 +143,6 @@ 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); - pv(rg, rg_flags, "%u"); - pv(rg, rg_free, "%u"); - pv(rg, rg_dinodes, "%u"); - - pa(rg, rg_reserved, 36); -} -#endif /* 0 */ - void gfs2_quota_in(struct gfs2_quota *qu, char *buf) { struct gfs2_quota *str = (struct gfs2_quota *)buf; @@ -223,26 +152,6 @@ 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; - - 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"); -} - -#endif /* 0 */ - void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) { struct gfs2_dinode *str = (struct gfs2_dinode *)buf; @@ -339,77 +248,6 @@ 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]; - - 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(KERN_INFO " name = %s\n", buf); -} - -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(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; @@ -422,31 +260,6 @@ 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); - 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); -} - -#endif /* 0 */ - void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf) { struct gfs2_inum_range *str = (struct gfs2_inum_range *)buf; @@ -463,14 +276,6 @@ 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) { struct gfs2_statfs_change *str = (struct gfs2_statfs_change *)buf; @@ -489,15 +294,6 @@ 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) { struct gfs2_unlinked_tag *str = (struct gfs2_unlinked_tag *)buf; @@ -515,16 +311,6 @@ 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; @@ -534,14 +320,3 @@ 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"); - pv(qc, qc_flags, "0x%.8X"); - pv(qc, qc_id, "%u"); -} - -#endif /* 0 */ - -- GitLab From d2d7b8a2a756fb520792ca3db3abdeed9214ae5b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 2 May 2006 12:09:42 -0400 Subject: [PATCH 0103/1619] [GFS2] Fix bug in writepage() As pointed out by Wendy Cheng, the logic in GFS2's writepage() function wasn't quite right with respect to invalidating pages when a file has been truncated. This patch fixes that. CC: Wendy Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 005c2522a87..afcc12a00a3 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -126,7 +126,7 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) /* Is the page fully outside i_size? (truncate in progress) */ offset = i_size & (PAGE_CACHE_SIZE-1); - if (page->index >= end_index+1 || !offset) { + if (page->index > end_index || (page->index == end_index && !offset)) { page->mapping->a_ops->invalidatepage(page, 0); unlock_page(page); return 0; /* don't care */ -- GitLab From 97a35d1e5fab9ff8de27814082b78b2fc9ad94f0 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 2 May 2006 13:34:03 -0400 Subject: [PATCH 0104/1619] [DLM] fix grant_after_purge softlockup In dlm_grant_after_purge() we were holding a hash table read_lock while calling put_rsb() which potentially removes the rsb from the hash table, taking the same lock in write. Fix this by flagging rsb's ahead of time that have been purged. Then iteratively read_lock the hash table, find a flagged rsb, unlock, process rsb. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/lock.c | 42 ++++++++++++++++++++++++++++-------------- fs/dlm/lock.h | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index c3299020c8f..149106f2b80 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -280,6 +280,7 @@ enum rsb_flags { RSB_NEW_MASTER, RSB_NEW_MASTER2, RSB_RECOVER_CONVERT, + RSB_LOCKS_PURGED, }; static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 85a0e73ba80..5f696390410 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3278,6 +3278,7 @@ static void purge_queue(struct dlm_rsb *r, struct list_head *queue, list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) { if (test(ls, lkb)) { + rsb_set_flag(r, RSB_LOCKS_PURGED); del_lkb(r, lkb); /* this put should free the lkb */ if (!dlm_put_lkb(lkb)) @@ -3334,27 +3335,40 @@ int dlm_purge_locks(struct dlm_ls *ls) return 0; } -int dlm_grant_after_purge(struct dlm_ls *ls) +static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket) +{ + struct dlm_rsb *r, *r_ret = NULL; + + read_lock(&ls->ls_rsbtbl[bucket].lock); + list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) { + if (!rsb_flag(r, RSB_LOCKS_PURGED)) + continue; + hold_rsb(r); + rsb_clear_flag(r, RSB_LOCKS_PURGED); + r_ret = r; + break; + } + read_unlock(&ls->ls_rsbtbl[bucket].lock); + return r_ret; +} + +void 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); + r = find_purged_rsb(ls, i); + if (!r) + continue; + lock_rsb(r); + if (is_master(r)) { + grant_pending_locks(r); + confirm_master(r, 0); } - read_unlock(&ls->ls_rsbtbl[i].lock); + unlock_rsb(r); + put_rsb(r); } - - return 0; } static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid, diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index bffab9c88b1..56cdc073b1f 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -25,7 +25,7 @@ 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); +void 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); -- GitLab From 5bb76af1e089ac186c15c6aa792340d22b63d4b4 Mon Sep 17 00:00:00 2001 From: Robert S Peterson Date: Fri, 5 May 2006 16:29:50 -0400 Subject: [PATCH 0105/1619] [GFS2] Set d_ops for root inode Well, I managed to track down the bug in gfs2 that was causing my grief. Below is a patch for the problem. Please incorporate as you see fit. Or should I say: as you see git. The problem was basically that you never set d_ops for the root inode, so the wrong hash algorithm was being used. But only for the root directory. Turns out that if I used subdirectories, it used the proper hash and my files were found just fine. Signed-off-by: Robert S Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index d19d98766aa..f252723b37d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -40,6 +40,8 @@ #define DO 0 #define UNDO 1 +extern struct dentry_operations gfs2_dops; + static struct gfs2_sbd *init_sbd(struct super_block *sb) { struct gfs2_sbd *sdp; @@ -357,6 +359,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) error = -ENOMEM; iput(inode); } + sb->s_root->d_op = &gfs2_dops; out: gfs2_glock_dq_uninit(&sb_gh); return error; -- GitLab From fd88de569b802c4a04aaa6ee74667775f4aed8c6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 5 May 2006 16:59:11 -0400 Subject: [PATCH 0106/1619] [GFS2] Readpages support This adds readpages support (and also corrects a small bug in the readpage error path at the same time). Hopefully this will improve performance by allowing GFS to submit larger lumps of I/O at a time. In order to simplify the setting of BH_Boundary, it currently gets set when we hit the end of a indirect pointer block. There is always a boundary at this point with the current allocation code. It doesn't get all the boundaries right though, so there is still room for improvement in this. See comments in fs/gfs2/ops_address.c for further information about readpages with GFS2. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 170 +++++++++++++++++++++++++++--------------- fs/gfs2/bmap.h | 5 +- fs/gfs2/dir.c | 8 +- fs/gfs2/glock.c | 2 +- fs/gfs2/inode.c | 5 +- fs/gfs2/log.c | 4 +- fs/gfs2/ops_address.c | 145 ++++++++++++++++++++++++++++------- fs/gfs2/ops_super.c | 3 - fs/gfs2/ops_vm.c | 8 +- fs/gfs2/quota.c | 5 +- fs/gfs2/recovery.c | 8 +- fs/gfs2/rgrp.c | 15 ++-- fs/gfs2/unlinked.c | 5 +- 13 files changed, 254 insertions(+), 129 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cfe1a428c66..474b9a16f0f 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -314,13 +314,17 @@ static void find_metapath(struct gfs2_inode *ip, uint64_t block, * metadata tree. */ -static inline uint64_t *metapointer(struct buffer_head *bh, - unsigned int height, struct metapath *mp) +static inline u64 *metapointer(struct buffer_head *bh, int *boundary, + unsigned int height, const 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]; + u64 *ptr; + *boundary = 0; + ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height]; + if (ptr + 1 == (u64*)(bh->b_data + bh->b_size)) + *boundary = 1; + return ptr; } /** @@ -339,24 +343,24 @@ static inline uint64_t *metapointer(struct buffer_head *bh, * */ -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) +static int 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); + int boundary; + uint64_t *ptr = metapointer(bh, &boundary, height, mp); if (*ptr) { *block = be64_to_cpu(*ptr); - return; + return boundary; } *block = 0; if (!create) - return; + return 0; - if (height == ip->i_di.di_height - 1 && - !gfs2_is_dir(ip)) + if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) *block = gfs2_alloc_data(ip); else *block = gfs2_alloc_meta(ip); @@ -367,15 +371,16 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, ip->i_di.di_blocks++; *new = 1; + return 0; } /** - * gfs2_block_map - Map a block from an inode to a disk block - * @ip: The GFS2 inode + * gfs2_block_pointers - Map a block from an inode to a disk block + * @inode: The 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 + * @boundary: gets set if we've hit a block boundary + * @mp: metapath to use * * 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. @@ -383,12 +388,14 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, * Returns: errno */ -int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, - uint64_t *dblock, uint32_t *extlen) +static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, + int *new, u64 *dblock, + int *boundary, + struct metapath *mp) { + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head *bh; - struct metapath mp; int create = *new; unsigned int bsize; unsigned int height; @@ -398,13 +405,6 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, *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; @@ -421,7 +421,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, goto out; } - find_metapath(ip, lblock, &mp); + find_metapath(ip, lblock, mp); end_of_metadata = ip->i_di.di_height - 1; error = gfs2_meta_inode_buffer(ip, &bh); @@ -429,7 +429,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, goto out; for (x = 0; x < end_of_metadata; x++) { - lookup_block(ip, bh, x, &mp, create, new, dblock); + lookup_block(ip, bh, x, mp, create, new, dblock); brelse(bh); if (!*dblock) goto out; @@ -439,49 +439,95 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, 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); - + *boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock); if (*new) { - error = gfs2_meta_inode_buffer(ip, &bh); + struct buffer_head *dibh; + error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - gfs2_trans_add_bh(ip->i_gl, bh, 1); - gfs2_dinode_out(&ip->i_di, bh->b_data); - brelse(bh); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); } } + return bh; +out: + return ERR_PTR(error); +} - out: + +static inline void bmap_lock(struct inode *inode, int create) +{ + struct gfs2_inode *ip = inode->u.generic_ip; + if (create) + down_write(&ip->i_rw_mutex); + else + down_read(&ip->i_rw_mutex); +} + +static inline void bmap_unlock(struct inode *inode, int create) +{ + struct gfs2_inode *ip = inode->u.generic_ip; if (create) up_write(&ip->i_rw_mutex); else up_read(&ip->i_rw_mutex); +} - return error; +int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary) +{ + struct metapath mp; + struct buffer_head *bh; + int create = *new; + + bmap_lock(inode, create); + bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp); + bmap_unlock(inode, create); + if (!bh) + return 0; + if (IS_ERR(bh)) + return PTR_ERR(bh); + brelse(bh); + return 0; +} + +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 metapath mp; + struct buffer_head *bh; + int boundary; + int create = *new; + + BUG_ON(!extlen); + BUG_ON(!dblock); + BUG_ON(!new); + + bmap_lock(inode, create); + bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp); + *extlen = 1; + + if (bh && !IS_ERR(bh) && *dblock && !*new) { + u64 tmp_dblock; + int tmp_new; + unsigned int nptrs; + unsigned end_of_metadata = ip->i_di.di_height - 1; + + 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)++; + } + } + bmap_unlock(inode, create); + if (!bh) + return 0; + if (IS_ERR(bh)) + return PTR_ERR(bh); + brelse(bh); + return 0; } /** @@ -1053,7 +1099,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, } for (; lblock < lblock_stop; lblock += extlen) { - error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); if (error) return error; diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 23fb6589d5e..bc46c114912 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -16,9 +16,8 @@ typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip, 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); +int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); +int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size); int gfs2_truncatei_resume(struct gfs2_inode *ip); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 0404783f39b..7f8b27e4091 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -197,8 +197,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, if (!extlen) { new = 1; - error = gfs2_block_map(ip, lblock, &new, &dblock, - &extlen); + error = gfs2_extent_map(ip->i_vnode, lblock, &new, + &dblock, &extlen); if (error) goto fail; error = -EIO; @@ -314,8 +314,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, if (!extlen) { new = 0; - error = gfs2_block_map(ip, lblock, &new, &dblock, - &extlen); + error = gfs2_extent_map(ip->i_vnode, lblock, &new, + &dblock, &extlen); if (error) goto fail; } diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 4fb8066dc74..9d4ae094fa2 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2125,7 +2125,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) mutex_lock(&sdp->sd_invalidate_inodes_mutex); invalidate_inodes(sdp->sd_vfs); mutex_unlock(&sdp->sd_invalidate_inodes_mutex); - yield(); + msleep(10); } } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9084d6037a0..0817f6ede18 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1606,9 +1606,8 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) 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); + gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY, + gh); error = gfs2_glock_nq(gh); if (error) return error; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 134fc57e21d..02d31e35f0c 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -211,9 +211,9 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) int new = 0; uint64_t dbn; int error; + int bdy; - error = gfs2_block_map(sdp->sd_jdesc->jd_inode->u.generic_ip, - lbn, &new, &dbn, NULL); + error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, &bdy); gfs2_assert_withdraw(sdp, !error && dbn); return dbn; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index afcc12a00a3..d89179b316f 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -47,12 +48,12 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - struct gfs2_inode *ip = inode->u.generic_ip; int new = create; uint64_t dblock; int error; + int boundary; - error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); + error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); if (error) return error; @@ -62,6 +63,8 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, map_bh(bh_result, inode->i_sb, dblock); if (new) set_buffer_new(bh_result); + if (boundary) + set_buffer_boundary(bh_result); return 0; } @@ -83,8 +86,9 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, int new = 0; uint64_t dblock; int error; + int boundary; - error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); + error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); if (error) return error; @@ -92,6 +96,8 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, map_bh(bh_result, inode->i_sb, dblock); else if (gfs2_assert_withdraw(ip->i_sbd, !create)) error = -EIO; + if (boundary) + set_buffer_boundary(bh_result); return error; } @@ -151,6 +157,19 @@ out_ignore: return 0; } +static int zero_readpage(struct page *page) +{ + void *kaddr; + + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr, 0, PAGE_CACHE_SIZE); + kunmap_atomic(page, KM_USER0); + + SetPageUptodate(page); + + return 0; +} + /** * stuffed_readpage - Fill in a Linux page with stuffed file data * @ip: the inode @@ -165,17 +184,18 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) void *kaddr; int error; + /* Only the first page of a stuffed file might contain data */ + if (unlikely(page->index)) + return zero_readpage(page); + error = gfs2_meta_inode_buffer(ip, &dibh); if (error) return error; kaddr = kmap_atomic(page, KM_USER0); - memcpy((char *)kaddr, - dibh->b_data + sizeof(struct gfs2_dinode), + memcpy(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); + memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size); kunmap_atomic(page, KM_USER0); brelse(dibh); @@ -185,19 +205,6 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) return 0; } -static int zero_readpage(struct page *page) -{ - void *kaddr; - - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr, 0, PAGE_CACHE_SIZE); - kunmap_atomic(page, KM_USER0); - - SetPageUptodate(page); - unlock_page(page); - - return 0; -} /** * gfs2_readpage - readpage with locking @@ -215,19 +222,16 @@ static int gfs2_readpage(struct file *file, struct page *page) struct gfs2_holder gh; int error; - if (file != &gfs2_internal_file_sentinal) { + if (likely(file != &gfs2_internal_file_sentinal)) { gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); error = gfs2_glock_nq_m_atime(1, &gh); - if (error) + if (unlikely(error)) goto out_unlock; } if (gfs2_is_stuffed(ip)) { - if (!page->index) { - error = stuffed_readpage(ip, page); - unlock_page(page); - } else - error = zero_readpage(page); + error = stuffed_readpage(ip, page); + unlock_page(page); } else error = mpage_readpage(page, gfs2_get_block); @@ -242,6 +246,90 @@ out: return error; out_unlock: unlock_page(page); + if (file != &gfs2_internal_file_sentinal) + gfs2_holder_uninit(&gh); + goto out; +} + +#define list_to_page(head) (list_entry((head)->prev, struct page, lru)) + +/** + * gfs2_readpages - Read a bunch of pages at once + * + * Some notes: + * 1. This is only for readahead, so we can simply ignore any things + * which are slightly inconvenient (such as locking conflicts between + * the page lock and the glock) and return having done no I/O. Its + * obviously not something we'd want to do on too regular a basis. + * Any I/O we ignore at this time will be done via readpage later. + * 2. We have to handle stuffed files here too. + * 3. mpage_readpages() does most of the heavy lifting in the common case. + * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places. + * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as + * well as read-ahead. + */ +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_holder gh; + unsigned page_idx; + int ret; + + if (likely(file != &gfs2_internal_file_sentinal)) { + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, + LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh); + ret = gfs2_glock_nq_m_atime(1, &gh); + if (ret == GLR_TRYFAILED) + goto out_noerror; + if (unlikely(ret)) + goto out_unlock; + } + + if (gfs2_is_stuffed(ip)) { + struct pagevec lru_pvec; + pagevec_init(&lru_pvec, 0); + for (page_idx = 0; page_idx < nr_pages; page_idx++) { + struct page *page = list_to_page(pages); + list_del(&page->lru); + if (!add_to_page_cache(page, mapping, + page->index, GFP_KERNEL)) { + ret = stuffed_readpage(ip, page); + unlock_page(page); + if (!pagevec_add(&lru_pvec, page)) + __pagevec_lru_add(&lru_pvec); + } + page_cache_release(page); + } + pagevec_lru_add(&lru_pvec); + ret = 0; + } else { + /* What we really want to do .... */ + ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); + } + + if (likely(file != &gfs2_internal_file_sentinal)) { + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); + } +out: + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = -EIO; + return ret; +out_noerror: + ret = 0; +out_unlock: + /* unlock all pages, we can't do any I/O right now */ + for (page_idx = 0; page_idx < nr_pages; page_idx++) { + struct page *page = list_to_page(pages); + list_del(&page->lru); + unlock_page(page); + page_cache_release(page); + } + if (likely(file != &gfs2_internal_file_sentinal)) + gfs2_holder_uninit(&gh); goto out; } @@ -572,6 +660,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, struct address_space_operations gfs2_file_aops = { .writepage = gfs2_writepage, .readpage = gfs2_readpage, + .readpages = gfs2_readpages, .sync_page = block_sync_page, .prepare_write = gfs2_prepare_write, .commit_write = gfs2_commit_write, diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 60bf2563c7b..5910c7b5c84 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb) if (error) gfs2_io_error(sdp); } - /* At this point, we're through modifying the disk */ /* Release stuff */ @@ -125,12 +124,10 @@ static void gfs2_put_super(struct super_block *sb) 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); vfree(sdp); sb->s_fs_info = NULL; diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index dbc57071e7b..d67248cae9b 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -90,8 +90,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) if (error) goto out_gunlock_q; - gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, - &data_blocks, &ind_blocks); + gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); al->al_requested = data_blocks + ind_blocks; @@ -99,8 +98,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) if (error) goto out_gunlock_q; - error = gfs2_trans_begin(sdp, - al->al_rgd->rd_ri.ri_length + + error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length + ind_blocks + RES_DINODE + RES_STATFS + RES_QUOTA, 0); if (error) @@ -117,7 +115,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) unsigned int extlen; int new = 1; - error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); if (error) goto out_trans; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 942c4c8b9f5..d49ff43b3a8 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -255,6 +255,7 @@ static int bh_get(struct gfs2_quota_data *qd) int new = 0; struct buffer_head *bh; int error; + int boundary; mutex_lock(&sdp->sd_quota_mutex); @@ -266,7 +267,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, block, &new, &dblock, NULL); + error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary); if (error) goto fail; error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); @@ -1162,7 +1163,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) if (!extlen) { int new = 0; - error = gfs2_block_map(ip, x, &new, &dblock, &extlen); + error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen); if (error) goto fail; } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index d916817fb6e..87adebea3bc 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -40,8 +40,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, uint32_t extlen; int error; - error = gfs2_block_map(ip, blk, &new, &dblock, - &extlen); + error = gfs2_extent_map(ip->i_vnode, blk, &new, &dblock, &extlen); if (error) return error; if (!dblock) { @@ -378,10 +377,11 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) uint32_t hash; struct buffer_head *bh; int error; - + int boundary; + lblock = head->lh_blkno; gfs2_replay_incr_blk(sdp, &lblock); - error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); + error = gfs2_block_map(ip->i_vnode, lblock, &new, &dblock, &boundary); if (error) return error; if (!dblock) { diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 4ae55969439..15c326ce13d 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -956,8 +956,7 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, 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, + blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset, bi->bi_len, goal, old_state); else blk = gfs2_bitfit(rgd, @@ -976,12 +975,10 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, blk = 0; gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); - gfs2_setbit(rgd, - bi->bi_bh->b_data + bi->bi_offset, + 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, + gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset, bi->bi_len, blk, new_state); return bi->bi_start * GFS2_NBBY + blk; @@ -1064,8 +1061,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip) else goal = rgd->rd_last_alloc_data; - blk = rgblk_search(rgd, goal, - GFS2_BLKST_FREE, GFS2_BLKST_USED); + blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); rgd->rd_last_alloc_data = blk; block = rgd->rd_ri.ri_data0 + blk; @@ -1109,8 +1105,7 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) else goal = rgd->rd_last_alloc_meta; - blk = rgblk_search(rgd, goal, - GFS2_BLKST_FREE, GFS2_BLKST_USED); + blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); rgd->rd_last_alloc_meta = blk; block = rgd->rd_ri.ri_data0 + blk; diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 24b91c23bc2..0d2314a5252 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -35,11 +35,12 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, 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, block, &new, &dblock, NULL); + 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); @@ -354,7 +355,7 @@ int gfs2_unlinked_init(struct gfs2_sbd *sdp) if (!extlen) { int new = 0; - error = gfs2_block_map(ip, x, &new, &dblock, &extlen); + error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen); if (error) goto fail; } -- GitLab From e90c01e148b967d30caf59e76accb3a58ca6b74b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 12 May 2006 12:09:15 -0400 Subject: [PATCH 0107/1619] [GFS2] Reverse block order in build_height The original code ordered the blocks allocated in the build_height routine backwards causing excessive disk seeks during a read of the metadata. This patch reverses the order to try and reduce disk seeks. Example: A five level metadata tree, I = Inode, P = Pointers, D = Data You need to read the blocks in the order: I P5 P4 P3 P2 P1 D in order to read a single data block. The new code now orders the blocks in this way. The old code used to order them as: I P1 P2 P3 P4 P5 D requiring two extra seeks on average. Note that for files which are grown by gradual extension rather than by truncate or by llseek/write at a large offset, this doesn't apply. In the case of writing to a file linearly, this routine will only be called upon to extend the height of the tree by one block at a time, so the ordering is determined by when its called rather than by the internals of the routine itself. Optimising that part of the ordering is a much harder problem. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 102 ++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 56 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 474b9a16f0f..31c3e92820e 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -164,72 +164,62 @@ static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size) * @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) +static int build_height(struct inode *inode, unsigned height) { - struct gfs2_sbd *sdp = ip->i_sbd; - struct buffer_head *bh, *dibh; - uint64_t block = 0, *bp; - unsigned int x; - int new_block; + struct gfs2_inode *ip = inode->u.generic_ip; + unsigned new_height = height - ip->i_di.di_height; + struct buffer_head *dibh; + struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; int error; + u64 *bp; + u64 bn; + unsigned n; - 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 */ + if (height <= ip->i_di.di_height) + return 0; - block = gfs2_alloc_meta(ip); + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; - bh = gfs2_meta_new(ip->i_gl, block); - gfs2_trans_add_bh(ip->i_gl, bh, 1); - gfs2_metatype_set(bh, - GFS2_METATYPE_IN, + for(n = 0; n < new_height; n++) { + bn = gfs2_alloc_meta(ip); + blocks[n] = gfs2_meta_new(ip->i_gl, bn); + gfs2_trans_add_bh(ip->i_gl, blocks[n], 1); + } + + n = 0; + bn = blocks[0]->b_blocknr; + if (new_height > 1) { + for(; n < new_height-1; n++) { + gfs2_metatype_set(blocks[n], 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, 1); - - 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++; + gfs2_buffer_clear_tail(blocks[n], + sizeof(struct gfs2_meta_header)); + bp = (u64 *)(blocks[n]->b_data + + sizeof(struct gfs2_meta_header)); + *bp = cpu_to_be64(blocks[n+1]->b_blocknr); + brelse(blocks[n]); + blocks[n] = NULL; } - - ip->i_di.di_height++; - - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); } - - return 0; + gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); + gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header), + dibh, sizeof(struct gfs2_dinode)); + brelse(blocks[n]); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + bp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode)); + *bp = cpu_to_be64(bn); + ip->i_di.di_height += new_height; + ip->i_di.di_blocks += new_height; + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + return error; } /** @@ -416,7 +406,7 @@ static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, if (!create) goto out; - error = build_height(ip, height); + error = build_height(inode, height); if (error) goto out; } @@ -806,7 +796,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, h); + error = build_height(ip->i_vnode, h); up_write(&ip->i_rw_mutex); if (error) goto out_end_trans; -- GitLab From 9801f6461eb994e4eda29cba97f4596dffafbf32 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 12 May 2006 14:06:02 -0400 Subject: [PATCH 0108/1619] [GFS2] Remove incorrect initialisation of gh_owner The gh_owner field shouldn't be set or reset outside the glock code. These were left over from when recursive locking was allowed. It isn't any more, so they are not needed. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 1 - fs/gfs2/ops_fstype.c | 5 ----- 2 files changed, 6 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 0817f6ede18..5522fa74729 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -319,7 +319,6 @@ static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, if (error) goto fail; } - ip->i_iopen_gh.gh_owner = NULL; spin_lock(&io_gl->gl_spin); gfs2_glock_hold(i_gl); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index f252723b37d..44c64effc96 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -468,11 +468,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) 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) { -- GitLab From b9cb981310bc22f165726e99385c2d85196e2f41 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 12 May 2006 17:07:56 -0400 Subject: [PATCH 0109/1619] [GFS2] Fix attributes setting logic The attributes logic for immutable was wrong so that there was not way to remove this attribute once set. This fixes the bug. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index c2dbc300a50..cf724800e0e 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -611,8 +611,10 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); - if (error) + if (error) { + gfs2_holder_uninit(&gh); return error; + } flags = ip->i_di.di_flags; new_flags = (flags & ~mask) | (reqflags & mask); @@ -635,9 +637,14 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) goto out; if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY)) goto out; - error = gfs2_repermission(inode, MAY_WRITE, NULL); - if (error) + if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) && + !capable(CAP_LINUX_IMMUTABLE)) goto out; + if (!IS_IMMUTABLE(inode)) { + error = gfs2_repermission(inode, MAY_WRITE, NULL); + if (error) + goto out; + } error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) -- GitLab From 64c14ea73b58e2c3759682d67eeb00d088355f08 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 16 May 2006 13:37:11 -0400 Subject: [PATCH 0110/1619] [GFS2] Fix ref count bug that used to bite us on umount The ref count of certain glock's got elevated too far during unlink which caused umount to fail. This fixes it. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5522fa74729..5bc9542c7fc 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -297,19 +297,13 @@ static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, 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) { @@ -318,27 +312,23 @@ static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, &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); + 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: +fail: gfs2_meta_cache_flush(ip); kmem_cache_free(gfs2_inode_cachep, ip); *ipp = NULL; - return error; } -- GitLab From 88c8ab1fcb53feadb8ebdcb4cda7e6137c6416bd Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 13:52:39 -0400 Subject: [PATCH 0111/1619] [GFS2] Merge bits.[ch] into rgrp.c Since they are small and will be inlined by the complier, it makes sense to merge the contents of bits.[ch] into rgrp.c Signed-off-by: Steven Whitehouse --- fs/gfs2/bits.c | 182 ------------------------------------------------- fs/gfs2/bits.h | 28 -------- fs/gfs2/rgrp.c | 162 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 161 insertions(+), 211 deletions(-) delete mode 100644 fs/gfs2/bits.c delete mode 100644 fs/gfs2/bits.h diff --git a/fs/gfs2/bits.c b/fs/gfs2/bits.c deleted file mode 100644 index 49585e3de09..00000000000 --- a/fs/gfs2/bits.c +++ /dev/null @@ -1,182 +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. - */ - -/* - * 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 - -#include "gfs2.h" -#include "lm_interface.h" -#include "incore.h" -#include "bits.h" -#include "util.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 deleted file mode 100644 index 36ccbdcb1ee..00000000000 --- a/fs/gfs2/bits.h +++ /dev/null @@ -1,28 +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 __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/rgrp.c b/fs/gfs2/rgrp.c index 15c326ce13d..5a32d693297 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -19,7 +19,6 @@ #include "gfs2.h" #include "lm_interface.h" #include "incore.h" -#include "bits.h" #include "glock.h" #include "glops.h" #include "lops.h" @@ -31,6 +30,167 @@ #include "ops_file.h" #include "util.h" +#define BFITNOENT 0xFFFFFFFF + +/* + * 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. + */ + +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; +} + /** * gfs2_rgrp_verify - Verify that a resource group is consistent * @sdp: the filesystem -- GitLab From 3efd7534a84a3eacb9d43e7f02fadeec4a5b79ff Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 14:02:52 -0400 Subject: [PATCH 0112/1619] [GFS2] Make newly moved functions static The functions moved from bits.c can now be made static. Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 5a32d693297..6d918a7c622 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -58,8 +58,9 @@ static const char valid_change[16] = { * */ -void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, uint32_t block, unsigned char new_state) +static 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; @@ -87,8 +88,8 @@ void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * */ -unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, uint32_t block) +static 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; @@ -120,9 +121,9 @@ unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * 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) +static 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; @@ -167,8 +168,8 @@ uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * Returns: The number of bits */ -uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, unsigned char state) +static 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; -- GitLab From 02f211f4d0e67794020ba1babbdaf7c45d56db45 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 14:03:43 -0400 Subject: [PATCH 0113/1619] [GFS2] Remove bits.c from the Makefile Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 66de2cc7bb5..9974201aa16 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o -gfs2-y := acl.o bits.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ +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 \ -- GitLab From 1b50259bc33f2adfcb4c5fba4b740bf80789df22 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 14:10:52 -0400 Subject: [PATCH 0114/1619] [GFS2] Drop log lock on I/O error & tidy up This patch drops the log spinlock when an I/O error occurs to avoid any possible problems in case of blocking or recursion in the I/O error routine. It also has a few cosmetic changes to tidy up various other files. Signed-off-by: Steven Whitehouse --- fs/gfs2/meta_io.c | 5 ++++- fs/gfs2/ops_inode.c | 5 ++--- fs/gfs2/page.c | 6 ++---- fs/gfs2/unlinked.c | 17 +++++++++-------- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index da49973a90d..fe46d563d3c 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -226,8 +226,11 @@ void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) gfs2_assert(sdp, bd->bd_ail == ai); if (!buffer_busy(bh)) { - if (!buffer_uptodate(bh)) + if (!buffer_uptodate(bh)) { + gfs2_log_unlock(sdp); gfs2_io_error_bh(sdp, bh); + gfs2_log_lock(sdp); + } list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); continue; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 62a12a59d91..b25ec4c8e56 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -213,8 +213,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (error) goto out_gunlock_q; - error = gfs2_trans_begin(sdp, - sdp->sd_max_dirres + + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_ri.ri_length + 2 * RES_DINODE + RES_STATFS + RES_QUOTA, 0); @@ -303,7 +302,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) if (error) goto out_gunlock; - error = gfs2_unlinki(dip, &dentry->d_name, ip,ul); + error = gfs2_unlinki(dip, &dentry->d_name, ip, ul); gfs2_trans_end(sdp); diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index a2c9e93c7c3..495db559416 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -155,11 +155,9 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, if (!PageUptodate(page)) { void *kaddr = kmap(page); - memcpy(kaddr, - dibh->b_data + sizeof(struct gfs2_dinode), + memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), ip->i_di.di_size); - memset(kaddr + ip->i_di.di_size, - 0, + memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size); kunmap(page); diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 0d2314a5252..2824b1665f9 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -130,11 +130,12 @@ 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); - } + 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); @@ -187,7 +188,7 @@ int gfs2_unlinked_get(struct gfs2_sbd *sdp, struct gfs2_unlinked **ul) goto fail; - found: +found: for (b = 0; b < 8; b++) if (!(byte & (1 << b))) break; @@ -202,7 +203,7 @@ int gfs2_unlinked_get(struct gfs2_sbd *sdp, struct gfs2_unlinked **ul) return 0; - fail: +fail: spin_unlock(&sdp->sd_unlinked_spin); kfree(*ul); return -ENOSPC; @@ -410,7 +411,7 @@ int gfs2_unlinked_init(struct gfs2_sbd *sdp) return 0; - fail: +fail: gfs2_unlinked_cleanup(sdp); return error; } -- GitLab From bd8968010a9a08e67a0ddb3ddee9feb8882e8c2f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 14:54:58 -0400 Subject: [PATCH 0115/1619] [GFS2] Remove semaphore.h from C files We no longer use semaphores, everything has been converted to mutex or rwsem, so we don't need to include this header any more. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 1 - fs/gfs2/bmap.c | 1 - fs/gfs2/daemon.c | 1 - fs/gfs2/eaops.c | 1 - fs/gfs2/eattr.c | 1 - fs/gfs2/glock.c | 1 - fs/gfs2/glops.c | 1 - fs/gfs2/inode.c | 1 - fs/gfs2/lm.c | 1 - fs/gfs2/log.c | 1 - fs/gfs2/lops.c | 1 - fs/gfs2/lvb.c | 1 - fs/gfs2/main.c | 1 - fs/gfs2/meta_io.c | 1 - fs/gfs2/mount.c | 1 - fs/gfs2/ondisk.c | 1 - fs/gfs2/ops_address.c | 1 - fs/gfs2/ops_dentry.c | 1 - fs/gfs2/ops_export.c | 1 - fs/gfs2/ops_file.c | 1 - fs/gfs2/ops_fstype.c | 1 - fs/gfs2/ops_inode.c | 1 - fs/gfs2/ops_super.c | 1 - fs/gfs2/ops_vm.c | 1 - fs/gfs2/page.c | 1 - fs/gfs2/quota.c | 1 - fs/gfs2/recovery.c | 1 - fs/gfs2/rgrp.c | 1 - fs/gfs2/super.c | 1 - fs/gfs2/sys.c | 1 - fs/gfs2/trans.c | 1 - fs/gfs2/unlinked.c | 1 - fs/gfs2/util.c | 1 - 33 files changed, 33 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index e9d05fe9435..d822256c7a5 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 31c3e92820e..32b1d66e68e 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index c2b5d69044c..aa4d13002bb 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 1b376eceb6a..e5e2565ac29 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index af4f1c3f592..3930304bc51 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 9d4ae094fa2..2029df4b349 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d180c89dd56..5e8ec6a6182 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5bc9542c7fc..d218cbf98aa 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 06a785e9b58..600b2bc48ba 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 02d31e35f0c..0e5e9cf9dd4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 4d90eb31149..22a4f038e3b 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c index 47867db92ea..a56b23e0a3f 100644 --- a/fs/gfs2/lvb.c +++ b/fs/gfs2/lvb.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c8d17b7ba60..b0a4582e78d 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index fe46d563d3c..92c1a3f823d 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index e90ea7d32f9..7e001356824 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index f6aba3b156c..90d398d2d04 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -12,7 +12,6 @@ #include #include #include -#include #include "gfs2.h" #include diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index d89179b316f..6d2fc107bbd 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index 95837107609..6cbff891063 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index be16c68263d..a90397f2819 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index cf724800e0e..00522fc927c 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 44c64effc96..5899ac33451 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index b25ec4c8e56..c8aeaafec50 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 5910c7b5c84..3661b2f25b8 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index d67248cae9b..23161be5db1 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index 495db559416..bc80247060f 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index d49ff43b3a8..adfb8062f5d 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -45,7 +45,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 87adebea3bc..527544b68a6 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 6d918a7c622..1b1a2aee8f6 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 75a8def8d0b..788dbea45c8 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index f05ba8f6913..bbfa9e16abc 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "gfs2.h" diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 18c606d0712..a4c414c5935 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 2824b1665f9..9ed0a6b8fc6 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "gfs2.h" #include "lm_interface.h" diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 7cd9e25639c..7c3806c6740 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "gfs2.h" -- GitLab From 3a8a9a1034813aa99f5ae3150f652d490c5ff10d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 15:09:15 -0400 Subject: [PATCH 0116/1619] [GFS2] Update copyright date to 2006 Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 2 +- fs/gfs2/acl.h | 2 +- fs/gfs2/bmap.c | 2 +- fs/gfs2/bmap.h | 2 +- fs/gfs2/daemon.c | 2 +- fs/gfs2/daemon.h | 2 +- fs/gfs2/dir.c | 2 +- fs/gfs2/dir.h | 2 +- fs/gfs2/eaops.c | 2 +- fs/gfs2/eaops.h | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/eattr.h | 2 +- fs/gfs2/format.h | 2 +- fs/gfs2/gfs2.h | 2 +- fs/gfs2/glock.c | 2 +- fs/gfs2/glock.h | 2 +- fs/gfs2/glops.c | 2 +- fs/gfs2/glops.h | 2 +- fs/gfs2/incore.h | 2 +- fs/gfs2/inode.c | 2 +- fs/gfs2/inode.h | 2 +- fs/gfs2/lm.c | 2 +- fs/gfs2/lm.h | 2 +- fs/gfs2/lm_interface.h | 2 +- fs/gfs2/locking.c | 2 +- fs/gfs2/log.c | 2 +- fs/gfs2/log.h | 2 +- fs/gfs2/lops.c | 2 +- fs/gfs2/lops.h | 2 +- fs/gfs2/lvb.c | 2 +- fs/gfs2/lvb.h | 2 +- fs/gfs2/main.c | 2 +- fs/gfs2/meta_io.c | 2 +- fs/gfs2/meta_io.h | 2 +- fs/gfs2/mount.c | 2 +- fs/gfs2/mount.h | 2 +- fs/gfs2/ondisk.c | 2 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/ops_address.h | 2 +- fs/gfs2/ops_dentry.c | 2 +- fs/gfs2/ops_dentry.h | 2 +- fs/gfs2/ops_export.c | 2 +- fs/gfs2/ops_export.h | 2 +- fs/gfs2/ops_file.c | 2 +- fs/gfs2/ops_file.h | 2 +- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/ops_fstype.h | 2 +- fs/gfs2/ops_inode.c | 2 +- fs/gfs2/ops_inode.h | 2 +- fs/gfs2/ops_super.c | 2 +- fs/gfs2/ops_super.h | 2 +- fs/gfs2/ops_vm.c | 2 +- fs/gfs2/ops_vm.h | 2 +- fs/gfs2/page.c | 2 +- fs/gfs2/page.h | 2 +- fs/gfs2/quota.c | 2 +- fs/gfs2/quota.h | 2 +- fs/gfs2/recovery.c | 2 +- fs/gfs2/recovery.h | 2 +- fs/gfs2/rgrp.c | 2 +- fs/gfs2/rgrp.h | 2 +- fs/gfs2/super.c | 2 +- fs/gfs2/super.h | 2 +- fs/gfs2/sys.c | 2 +- fs/gfs2/sys.h | 2 +- fs/gfs2/trans.c | 2 +- fs/gfs2/trans.h | 2 +- fs/gfs2/unlinked.c | 2 +- fs/gfs2/unlinked.h | 2 +- fs/gfs2/util.c | 2 +- fs/gfs2/util.h | 2 +- 71 files changed, 71 insertions(+), 71 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index d822256c7a5..343dbe3e87b 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index a174b4f6bcc..067105786ea 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 32b1d66e68e..41abd3f4fc7 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index bc46c114912..06ccb2d808a 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index aa4d13002bb..9e7b9f29678 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h index a27fdeda5fb..aa68e7a1b0b 100644 --- a/fs/gfs2/daemon.h +++ b/fs/gfs2/daemon.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 7f8b27e4091..6918a58261e 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index d209f1fcb8a..173403095eb 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index e5e2565ac29..85c1dbace88 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 30ec6a09bfd..3dece17e311 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 3930304bc51..f5169a42a91 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index ffd56686225..19fb1dc4ddc 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/format.h b/fs/gfs2/format.h index c7bf32ce3ec..239f0c3553f 100644 --- a/fs/gfs2/format.h +++ b/fs/gfs2/format.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h index 57175f70e2b..6edbd551a4c 100644 --- a/fs/gfs2/gfs2.h +++ b/fs/gfs2/gfs2.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 2029df4b349..c0415903153 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index a36b26585fb..9df09c7eeb9 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 5e8ec6a6182..e262f22f744 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h index 94f2d264aa6..5c1e9491024 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 84dd2f579e6..fc4a983e3c8 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index d218cbf98aa..27fbcd9b12f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 13bc4eacac6..5ef21317b2f 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 600b2bc48ba..f45c0ffd1c3 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h index 4ee5c34434b..e821101d19c 100644 --- a/fs/gfs2/lm.h +++ b/fs/gfs2/lm.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index 378432f17f2..9d34bf3df10 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 6a78aacb26a..183192836e9 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 0e5e9cf9dd4..2a8b4b71dd1 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 84a3e902e84..8cfd0f1d29f 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 22a4f038e3b..e4c75a74df5 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 0c78d222d6f..8a1029d3d38 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c index a56b23e0a3f..e88e9cce14e 100644 --- a/fs/gfs2/lvb.c +++ b/fs/gfs2/lvb.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/lvb.h b/fs/gfs2/lvb.h index 3c4c17405e9..1b1a8b75219 100644 --- a/fs/gfs2/lvb.h +++ b/fs/gfs2/lvb.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index b0a4582e78d..9ce56b5c780 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 92c1a3f823d..b9895bbd5fe 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index d72144d5d72..23c6a596fd9 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 7e001356824..0d4b230785a 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h index bc8331cd7b2..2eb14722144 100644 --- a/fs/gfs2/mount.h +++ b/fs/gfs2/mount.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 90d398d2d04..b3bc21a6ba0 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 6d2fc107bbd..16d3ebd3209 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index f201a059fd9..b88adddaffb 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index 6cbff891063..fef415e2068 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h index 94e3ee17016..1b6e75c0a4a 100644 --- a/fs/gfs2/ops_dentry.h +++ b/fs/gfs2/ops_dentry.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index a90397f2819..a376ead7d0c 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h index 2f342f3d875..88d58e57f51 100644 --- a/fs/gfs2/ops_export.h +++ b/fs/gfs2/ops_export.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 00522fc927c..1e8f602c1e5 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index 192577b411f..a2edce38f5c 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 5899ac33451..a4598204550 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h index c6452874483..622f5760d6b 100644 --- a/fs/gfs2/ops_fstype.h +++ b/fs/gfs2/ops_fstype.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index c8aeaafec50..0c06f92368f 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index 5fafd87c8d7..930aaae9137 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 3661b2f25b8..6fa7b8649f1 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h index a41d208dc55..a15ccc27611 100644 --- a/fs/gfs2/ops_super.h +++ b/fs/gfs2/ops_super.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 23161be5db1..263c1fb7bba 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h index 54e3a8769cb..077cffcd408 100644 --- a/fs/gfs2/ops_vm.h +++ b/fs/gfs2/ops_vm.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index bc80247060f..cd93644c7d7 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h index 346e296420c..2c853a90ac0 100644 --- a/fs/gfs2/page.h +++ b/fs/gfs2/page.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index adfb8062f5d..f752b018469 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 1baeeb23d23..af05492f964 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 527544b68a6..c504ac1b831 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 24848118930..ac0f1d6ce45 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 1b1a2aee8f6..c1c6fa9c0e4 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 4c44a191b1c..d2db3719cc0 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 788dbea45c8..a943a505bc5 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 175afdde43b..df249523040 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index bbfa9e16abc..d32a2c54dae 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h index 62c8ed89ab9..c46a700e801 100644 --- a/fs/gfs2/sys.h +++ b/fs/gfs2/sys.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index a4c414c5935..05e0b72d56f 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 6b5e9e8bf56..60ef163dd9b 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 9ed0a6b8fc6..b92d7300205 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/unlinked.h b/fs/gfs2/unlinked.h index 51e77f88d74..159cf5ffe47 100644 --- a/fs/gfs2/unlinked.h +++ b/fs/gfs2/unlinked.h @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 7c3806c6740..0b37d6bcc36 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -1,6 +1,6 @@ /* * 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 diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 4532dbab0a2..8216d28bd81 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -1,6 +1,6 @@ /* * 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 -- GitLab From 320dd101e2d595a03439adb92b319f3af53dd1d0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 18 May 2006 16:25:27 -0400 Subject: [PATCH 0117/1619] [GFS2] glock debugging and inode cache changes This adds some extra debugging to glock.c and changes inode.c's deallocation code to call the debugging code at a suitable moment. I'm chasing down a particular bug to do with deallocation at the moment and the code can go again once the bug is fixed. Also this includes the first part of some changes to unify the Linux struct inode and GFS2's struct gfs2_inode. This transformation will happen in small parts over the next short period. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 26 ++++++++++++++++---- fs/gfs2/glock.h | 1 + fs/gfs2/incore.h | 8 +++++++ fs/gfs2/inode.c | 58 ++++++++++++++++----------------------------- fs/gfs2/main.c | 18 +++++++++++++- fs/gfs2/ops_super.c | 24 +++++++++++++++++++ 6 files changed, 92 insertions(+), 43 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index c0415903153..2ef8accf1cb 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -47,6 +47,7 @@ struct greedy { typedef void (*glock_examiner) (struct gfs2_glock * gl); static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); +static int dump_glock(struct gfs2_glock *gl); /** * relaxed_state_ok - is a requested lock compatible with the current lock mode? @@ -290,6 +291,8 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, spin_lock_init(&gl->gl_spin); gl->gl_state = LM_ST_UNLOCKED; + gl->gl_owner = NULL; + gl->gl_ip = 0; INIT_LIST_HEAD(&gl->gl_holders); INIT_LIST_HEAD(&gl->gl_waiters1); INIT_LIST_HEAD(&gl->gl_waiters2); @@ -661,8 +664,11 @@ void gfs2_glmutex_lock(struct gfs2_glock *gl) 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 + else { + gl->gl_owner = current; + gl->gl_ip = (unsigned long)__builtin_return_address(0); complete(&gh.gh_wait); + } spin_unlock(&gl->gl_spin); wait_for_completion(&gh.gh_wait); @@ -683,6 +689,10 @@ static int gfs2_glmutex_trylock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) acquired = 0; + else { + gl->gl_owner = current; + gl->gl_ip = (unsigned long)__builtin_return_address(0); + } spin_unlock(&gl->gl_spin); return acquired; @@ -698,6 +708,8 @@ void gfs2_glmutex_unlock(struct gfs2_glock *gl) { spin_lock(&gl->gl_spin); clear_bit(GLF_LOCK, &gl->gl_flags); + gl->gl_owner = NULL; + gl->gl_ip = 0; run_queue(gl); BUG_ON(!spin_is_locked(&gl->gl_spin)); spin_unlock(&gl->gl_spin); @@ -1173,7 +1185,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh) struct gfs2_sbd *sdp = gl->gl_sbd; int error = 0; - restart: +restart: if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) { set_bit(HIF_ABORTED, &gh->gh_iflags); return -EIO; @@ -1196,6 +1208,9 @@ int gfs2_glock_nq(struct gfs2_holder *gh) clear_bit(GLF_PREFETCH, &gl->gl_flags); + if (error == GLR_TRYFAILED && (gh->gh_flags & GL_DUMP)) + dump_glock(gl); + return error; } @@ -2212,9 +2227,8 @@ static int dump_glock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); - printk(KERN_INFO "Glock (%u, %llu)\n", - gl->gl_name.ln_type, - gl->gl_name.ln_number); + printk(KERN_INFO "Glock (%u, %llu)\n", gl->gl_name.ln_type, + gl->gl_name.ln_number); printk(KERN_INFO " gl_flags ="); for (x = 0; x < 32; x++) if (test_bit(x, &gl->gl_flags)) @@ -2222,6 +2236,8 @@ static int dump_glock(struct gfs2_glock *gl) printk(" \n"); printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref.refcount)); printk(KERN_INFO " gl_state = %u\n", gl->gl_state); + printk(KERN_INFO " gl_owner = %s\n", gl->gl_owner->comm); + print_symbol(KERN_INFO " gl_ip = %s\n", gl->gl_ip); printk(KERN_INFO " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no"); printk(KERN_INFO " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no"); printk(KERN_INFO " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 9df09c7eeb9..2e0a2ba92aa 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -27,6 +27,7 @@ #define GL_SYNC 0x00000800 #define GL_NOCANCEL 0x00001000 #define GL_AOP 0x00004000 +#define GL_DUMP 0x00008000 #define GLR_TRYFAILED 13 #define GLR_CANCELED 14 diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index fc4a983e3c8..92091d006a0 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -183,6 +183,8 @@ struct gfs2_glock { spinlock_t gl_spin; unsigned int gl_state; + struct task_struct *gl_owner; + unsigned long gl_ip; struct list_head gl_holders; struct list_head gl_waiters1; /* HIF_MUTEX */ struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */ @@ -244,6 +246,7 @@ enum { }; struct gfs2_inode { + struct inode i_inode; struct gfs2_inum i_num; atomic_t i_count; @@ -270,6 +273,11 @@ struct gfs2_inode { struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT]; }; +static inline struct gfs2_inode *GFS2_I(struct inode *inode) +{ + return container_of(inode, struct gfs2_inode, i_inode); +} + enum { GFF_DID_DIRECT_ALLOC = 0, }; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 27fbcd9b12f..c2c7d2b63a5 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -504,7 +504,7 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr, &gfs2_inode_glops, LM_ST_EXCLUSIVE, - LM_FLAG_TRY_1CB, &i_gh); + LM_FLAG_TRY_1CB|GL_DUMP, &i_gh); switch(error) { case 0: break; @@ -724,9 +724,8 @@ struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, 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; + igrab(dir); + return dir; } error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); @@ -734,7 +733,7 @@ struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, return ERR_PTR(error); if (!is_root) { - error = gfs2_repermission(dip->i_vnode, MAY_EXEC, NULL); + error = gfs2_repermission(dir, MAY_EXEC, NULL); if (error) goto out; } @@ -756,7 +755,6 @@ struct inode *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) { @@ -1058,7 +1056,6 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, int error; munge_mode_uid_gid(dip, &mode, &uid, &gid); - gfs2_alloc_get(dip); error = gfs2_quota_lock(dip, uid, gid); @@ -1069,19 +1066,14 @@ 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_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); - + 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: @@ -1089,7 +1081,6 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, out: gfs2_alloc_put(dip); - return error; } @@ -1123,8 +1114,7 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, if (error) goto fail_quota_locks; - error = gfs2_trans_begin(sdp, - sdp->sd_max_dirres + + 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); @@ -1157,19 +1147,18 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, return 0; - fail_end_trans: +fail_end_trans: gfs2_trans_end(sdp); - fail_ipreserv: +fail_ipreserv: if (dip->i_alloc.al_rgd) gfs2_inplace_release(dip); - fail_quota_locks: +fail_quota_locks: gfs2_quota_unlock(dip); - fail: +fail: gfs2_alloc_put(dip); - return error; } @@ -1226,11 +1215,9 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, 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); + 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 ERR_PTR(error); @@ -1248,11 +1235,9 @@ 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, - &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, - ghs + 1); + 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; } @@ -1285,18 +1270,17 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, return ERR_PTR(-ENOMEM); return inode; - fail_iput: +fail_iput: gfs2_inode_put(ip); - fail_gunlock2: +fail_gunlock2: gfs2_glock_dq_uninit(ghs + 1); - fail_gunlock: +fail_gunlock: gfs2_glock_dq(ghs); - fail: +fail: gfs2_unlinked_put(sdp, ul); - return ERR_PTR(error); } diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 9ce56b5c780..b24d0b40d96 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -23,6 +23,20 @@ #include "sys.h" #include "util.h" +static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +{ + struct gfs2_inode *ip = foo; + 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)); + } +} + /** * init_gfs2_fs - Register GFS2 as a filesystem * @@ -49,7 +63,9 @@ static int __init init_gfs2_fs(void) gfs2_inode_cachep = kmem_cache_create("gfs2_inode", sizeof(struct gfs2_inode), - 0, 0, NULL, NULL); + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_PANIC|SLAB_MEM_SPREAD), + gfs2_init_inode_once, NULL); if (!gfs2_inode_cachep) goto fail; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 6fa7b8649f1..1c17acc946f 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -361,7 +361,31 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) return 0; } +static struct inode *gfs2_alloc_inode(struct super_block *sb) +{ + struct gfs2_sbd *sdp = sb->s_fs_info; + struct gfs2_inode *ip; + + ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL); + 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; + } + return &ip->i_inode; +} + +static void gfs2_destroy_inode(struct inode *inode) +{ + kmem_cache_free(gfs2_inode_cachep, inode); +} + struct super_operations gfs2_super_ops = { + .alloc_inode = gfs2_alloc_inode, + .destroy_inode = gfs2_destroy_inode, .write_inode = gfs2_write_inode, .put_super = gfs2_put_super, .write_super = gfs2_write_super, -- GitLab From d2f222e6310b073ae3d91b8d3d676621fae1314e Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 19 May 2006 08:24:02 -0400 Subject: [PATCH 0118/1619] [GFS2] setup lock_dlm kobject earlier Setup the lock_dlm kobject before setting up the dlm lockspace instead of after. We want to use the sysfs files to detect the mount without having to wait for the dlm setup which can take a while. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/mount.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index aa79fbecaf6..3caeafc02a1 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -143,19 +143,19 @@ static int gdlm_mount(char *table_name, char *host_data, if (error) goto out_free; + error = gdlm_kobject_setup(ls, fskobj); + if (error) + goto out_thread; + error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), &ls->dlm_lockspace, nodir ? DLM_LSFL_NODIR : 0, GDLM_LVB_SIZE); if (error) { log_error("dlm_new_lockspace error %d", error); - goto out_thread; + goto out_kobj; } - error = gdlm_kobject_setup(ls, fskobj); - if (error) - goto out_dlm; - lockstruct->ls_jid = ls->jid; lockstruct->ls_first = ls->first; lockstruct->ls_lockspace = ls; @@ -164,8 +164,8 @@ static int gdlm_mount(char *table_name, char *host_data, lockstruct->ls_lvb_size = GDLM_LVB_SIZE; return 0; - out_dlm: - dlm_release_lockspace(ls->dlm_lockspace, 2); + out_kobj: + gdlm_kobject_release(ls); out_thread: gdlm_release_threads(ls); out_free: -- GitLab From 639b6d79b8c20cce4079fb035640c65456324d1c Mon Sep 17 00:00:00 2001 From: Ryan O'Hara Date: Mon, 22 May 2006 10:08:35 -0400 Subject: [PATCH 0119/1619] [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(-) diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 85c1dbace88..2243b44ecb0 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 3dece17e311..965a235c96e 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 f5169a42a91..187fba1c467 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 19fb1dc4ddc..ae199692e51 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 4356e386464..3893aac4e3a 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 */ -- GitLab From 90cdd2083aea9a536ecdef62840db01fff2e645d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 22 May 2006 10:36:25 -0400 Subject: [PATCH 0120/1619] [GFS2] Flag up issue in selinux code Signed-off-by: Steven Whitehouse --- fs/gfs2/eattr.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 187fba1c467..346601538ac 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -395,17 +395,14 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, l = 9; break; default: + /* FIXME: Needs looking at again */ break; } - memcpy(er->er_data + ei->ei_size, - prefix, l); - memcpy(er->er_data + ei->ei_size + l, - GFS2_EA2NAME(ea), + 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); + memcpy(er->er_data + ei->ei_size + ea_size - 1, &c, 1); } ei->ei_size += ea_size; -- GitLab From 9229f013495dcdae76e9942ebc2cfc69851fe10a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 24 May 2006 09:21:30 -0400 Subject: [PATCH 0121/1619] [GFS2] Cast 64 bit printk args to unsigned long long. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/recover.c | 2 +- fs/gfs2/locking/dlm/lock.c | 39 ++++++++++++++++++++----------------- fs/gfs2/locking/dlm/plock.c | 7 ++++--- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index b036ee7dcb3..34876f60f29 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -421,7 +421,7 @@ int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc) r = recover_list_find(ls, rc->rc_id); if (!r) { log_error(ls, "dlm_recover_master_reply no id %llx", - rc->rc_id); + (unsigned long long)rc->rc_id); goto out; } diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 3b0dfd7ae26..e74f1215672 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -35,7 +35,8 @@ static inline void gdlm_bast(void *astarg, int mode) if (!mode) { printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n", - lp->lockname.ln_type, lp->lockname.ln_number); + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); return; } @@ -154,7 +155,7 @@ static inline void make_strname(struct lm_lockname *lockname, struct gdlm_strname *str) { sprintf(str->name, "%8x%16llx", lockname->ln_type, - lockname->ln_number); + (unsigned long long)lockname->ln_number); str->namelen = GDLM_STRNAME_BYTES; } @@ -197,8 +198,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), - "%x,%llx", lp->lockname.ln_type, lp->lockname.ln_number); + gdlm_assert(!list_empty(&lp->all_list), "%x,%llx", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); list_del_init(&lp->all_list); ls->all_locks_count--; spin_unlock(&ls->async_lock); @@ -253,7 +254,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp) set_bit(LFL_ACTIVE, &lp->flags); log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type, - lp->lockname.ln_number, lp->lksb.sb_lkid, + (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid, lp->cur, lp->req, lp->lkf); error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf, @@ -269,8 +270,8 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp) 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->flags); + (unsigned long long)lp->lockname.ln_number, error, + lp->cur, lp->req, lp->lkf, lp->flags); return LM_OUT_ERROR; } return LM_OUT_ASYNC; @@ -289,15 +290,16 @@ static unsigned int gdlm_do_unlock(struct gdlm_lock *lp) lkf = DLM_LKF_VALBLK; log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type, - lp->lockname.ln_number, lp->lksb.sb_lkid, lp->cur, lkf); + (unsigned long long)lp->lockname.ln_number, + lp->lksb.sb_lkid, lp->cur, lkf); error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp); 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); + (unsigned long long)lp->lockname.ln_number, error, + lp->cur, lp->req, lp->lkf, lp->flags); return LM_OUT_ERROR; } return LM_OUT_ASYNC; @@ -338,8 +340,8 @@ void gdlm_cancel(lm_lock_t *lock) if (test_bit(LFL_DLM_CANCEL, &lp->flags)) return; - log_info("gdlm_cancel %x,%llx flags %lx", - lp->lockname.ln_type, lp->lockname.ln_number, lp->flags); + log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); spin_lock(&ls->async_lock); if (!list_empty(&lp->delay_list)) { @@ -356,10 +358,10 @@ void gdlm_cancel(lm_lock_t *lock) } if (!test_bit(LFL_ACTIVE, &lp->flags) || - test_bit(LFL_DLM_UNLOCK, &lp->flags)) { + test_bit(LFL_DLM_UNLOCK, &lp->flags)) { log_info("gdlm_cancel skip %x,%llx flags %lx", - lp->lockname.ln_type, lp->lockname.ln_number, - lp->flags); + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); return; } @@ -372,7 +374,8 @@ void gdlm_cancel(lm_lock_t *lock) NULL, lp); log_info("gdlm_cancel rv %d %x,%llx flags %lx", error, - lp->lockname.ln_type, lp->lockname.ln_number, lp->flags); + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); if (error == -EBUSY) clear_bit(LFL_DLM_CANCEL, &lp->flags); @@ -448,8 +451,8 @@ static void unhold_null_lock(struct gdlm_lock *lp) { struct gdlm_lock *lpn = lp->hold_null; - gdlm_assert(lpn, "%x,%llx", - lp->lockname.ln_type, lp->lockname.ln_number); + gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type, + (unsigned long long)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/plock.c b/fs/gfs2/locking/dlm/plock.c index 86312d96147..6adfb2d4fd8 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -93,7 +93,8 @@ int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, 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); + name->ln_type, + (unsigned long long)name->ln_number); } kfree(op); @@ -113,7 +114,7 @@ int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, if (posix_lock_file_wait(file, fl) < 0) log_error("gdlm_punlock: vfs unlock error %x,%llx", - name->ln_type, name->ln_number); + name->ln_type, (unsigned long long)name->ln_number); op->info.optype = GDLM_PLOCK_OP_UNLOCK; op->info.pid = fl->fl_pid; @@ -243,7 +244,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, wake_up(&recv_wq); else printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, - info.number); + (unsigned long long)info.number); return count; } -- GitLab From 382066da251132f768380f4852ed5afb72d88f80 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 24 May 2006 10:22:09 -0400 Subject: [PATCH 0122/1619] [GFS2] Casts for printing 64bit numbers Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 5 +++-- fs/gfs2/meta_io.c | 7 ++++--- fs/gfs2/ondisk.c | 24 ++++++++++++------------ fs/gfs2/rgrp.c | 4 ++-- fs/gfs2/util.c | 11 ++++++----- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 2ef8accf1cb..0603a6de52c 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2196,7 +2196,8 @@ static int dump_inode(struct gfs2_inode *ip) printk(KERN_INFO " Inode:\n"); printk(KERN_INFO " num = %llu %llu\n", - ip->i_num.no_formal_ino, ip->i_num.no_addr); + (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 ="); @@ -2228,7 +2229,7 @@ static int dump_glock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); printk(KERN_INFO "Glock (%u, %llu)\n", gl->gl_name.ln_type, - gl->gl_name.ln_number); + (unsigned long long)gl->gl_name.ln_number); printk(KERN_INFO " gl_flags ="); for (x = 0; x < 32; x++) if (test_bit(x, &gl->gl_flags)) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index b9895bbd5fe..c78517225f6 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -65,7 +65,7 @@ static void stuck_releasepage(struct buffer_head *bh) fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", - (uint64_t)bh->b_blocknr, atomic_read(&bh->b_count)); + (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"); @@ -75,7 +75,7 @@ static void stuck_releasepage(struct buffer_head *bh) gl = bd->bd_gl; fs_warn(sdp, "gl = (%u, %llu)\n", - gl->gl_name.ln_type, gl->gl_name.ln_number); + 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", @@ -89,7 +89,8 @@ static void stuck_releasepage(struct buffer_head *bh) return; fs_warn(sdp, "ip = %llu %llu\n", - ip->i_num.no_formal_ino, ip->i_num.no_addr); + (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"); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index b3bc21a6ba0..be5c86e5787 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -50,8 +50,8 @@ void gfs2_inum_out(const struct gfs2_inum *no, char *buf) static void gfs2_inum_print(struct gfs2_inum *no) { - pv(no, no_formal_ino, "%llu"); - pv(no, no_addr, "%llu"); + 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) @@ -111,10 +111,10 @@ void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) void gfs2_rindex_print(struct gfs2_rindex *ri) { - pv(ri, ri_addr, "%llu"); + printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)ri->ri_addr); pv(ri, ri_length, "%u"); - pv(ri, ri_data0, "%llu"); + printk(KERN_INFO " ri_data0 = %llu\n", (unsigned long long)ri->ri_data0); pv(ri, ri_data, "%u"); pv(ri, ri_bitbytes, "%u"); @@ -226,16 +226,16 @@ void gfs2_dinode_print(struct gfs2_dinode *di) 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"); + 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); pv(di, di_major, "%u"); pv(di, di_minor, "%u"); - pv(di, di_goal_meta, "%llu"); - pv(di, di_goal_data, "%llu"); + 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); pv(di, di_flags, "0x%.8X"); pv(di, di_payload_format, "%u"); @@ -244,7 +244,7 @@ void gfs2_dinode_print(struct gfs2_dinode *di) pv(di, di_depth, "%u"); pv(di, di_entries, "%u"); - pv(di, di_eattr, "%llu"); + 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) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index c1c6fa9c0e4..691e6f3ce43 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1165,7 +1165,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, rgd = gfs2_blk2rgrpd(sdp, bstart); if (!rgd) { if (gfs2_consist(sdp)) - fs_err(sdp, "block = %llu\n", bstart); + fs_err(sdp, "block = %llu\n", (unsigned long long)bstart); return NULL; } @@ -1452,7 +1452,7 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, rgd = gfs2_blk2rgrpd(sdp, block); if (!rgd) { if (gfs2_consist(sdp)) - fs_err(sdp, "block = %llu\n", block); + fs_err(sdp, "block = %llu\n", (unsigned long long)block); return; } diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 0b37d6bcc36..88974e9824f 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -116,7 +116,8 @@ int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide, "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, (unsigned long long)ip->i_num.no_formal_ino, + (unsigned long long)ip->i_num.no_addr, sdp->sd_fsname, function, file, line); return rv; } @@ -137,7 +138,7 @@ int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide, "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, (unsigned long long)rgd->rd_ri.ri_addr, sdp->sd_fsname, function, file, line); return rv; } @@ -158,7 +159,7 @@ int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, "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, (unsigned long long)bh->b_blocknr, type, sdp->sd_fsname, function, file, line); return (me) ? -1 : -2; } @@ -179,7 +180,7 @@ int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, "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, (unsigned long long)bh->b_blocknr, type, t, sdp->sd_fsname, function, file, line); return (me) ? -1 : -2; } @@ -217,7 +218,7 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, "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, (unsigned long long)bh->b_blocknr, sdp->sd_fsname, function, file, line); return rv; } -- GitLab From e79664886ddd569afa1b198ca436a63aefc19073 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 25 May 2006 12:47:04 -0400 Subject: [PATCH 0123/1619] [GFS2] Remove unused entry in ioctl-number.txt GFS2 doesn't use any ioctl numbers of its own, so we don't need a reserved range of numbers for it. Signed-off-by: Steven Whitehouse --- Documentation/ioctl-number.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index 93a86ac23cd..171a44ebd93 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -124,7 +124,6 @@ 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 -- GitLab From e70409f5f37587e101b4fd6d268686ae8e03ba88 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara Date: Thu, 25 May 2006 17:36:15 -0400 Subject: [PATCH 0124/1619] [GFS2] Fix for selinux support This should fix the mount problems with gfs2 and selinux. Signed-off-by: Ryan O'Hara Signed-off-by: Steven Whitehouse --- fs/gfs2/eaops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 2243b44ecb0..1c5ac3160b3 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -225,5 +225,6 @@ struct gfs2_eattr_operations *gfs2_ea_ops[] = { NULL, &gfs2_user_eaops, &gfs2_system_eaops, + &gfs2_security_eaops, }; -- GitLab From 47c96298cd0b04b4478206fde55fd6a6431de980 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 25 May 2006 17:43:14 -0400 Subject: [PATCH 0125/1619] [GFS2] Change name due to local_nodeid being a macro Change names of local_nodeid to dlm_local_nodeid to prevent a namespace collision. Changed other local variable to match. Cc: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index cdd168e4bf4..75010da95b3 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -55,9 +55,9 @@ #include "config.h" #include "midcomms.h" -static struct sockaddr_storage *local_addr[DLM_MAX_ADDR_COUNT]; -static int local_count; -static int local_nodeid; +static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT]; +static int dlm_local_count; +static int dlm_local_nodeid; /* One of these per connected node */ @@ -153,14 +153,14 @@ static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr) struct sockaddr_storage addr; int error; - if (!local_count) + if (!dlm_local_count) return -1; error = dlm_nodeid_to_addr(nodeid, &addr); if (error) return error; - if (local_addr[0]->ss_family == AF_INET) { + if (dlm_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; @@ -260,21 +260,21 @@ static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port, struct sockaddr_in *local4_addr; struct sockaddr_in6 *local6_addr; - if (!local_count) + if (!dlm_local_count) return; if (!port) { - if (local_addr[0]->ss_family == AF_INET) { - local4_addr = (struct sockaddr_in *)local_addr[0]; + if (dlm_local_addr[0]->ss_family == AF_INET) { + local4_addr = (struct sockaddr_in *)dlm_local_addr[0]; port = be16_to_cpu(local4_addr->sin_port); } else { - local6_addr = (struct sockaddr_in6 *)local_addr[0]; + local6_addr = (struct sockaddr_in6 *)dlm_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) { + saddr->ss_family = dlm_local_addr[0]->ss_family; + if (dlm_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)); @@ -636,7 +636,7 @@ static void init_local(void) struct sockaddr_storage sas, *addr; int i; - local_nodeid = dlm_our_nodeid(); + dlm_local_nodeid = dlm_our_nodeid(); for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) { if (dlm_our_addr(&sas, i)) @@ -646,7 +646,7 @@ static void init_local(void) if (!addr) break; memcpy(addr, &sas, sizeof(*addr)); - local_addr[local_count++] = addr; + dlm_local_addr[dlm_local_count++] = addr; } } @@ -659,15 +659,15 @@ static int init_sock(void) struct sctp_event_subscribe subscribe; int result = -EINVAL, num = 1, i, addr_len; - if (!local_count) { + if (!dlm_local_count) { init_local(); - if (!local_count) { + if (!dlm_local_count) { log_print("no local IP address has been set"); goto out; } } - result = sock_create_kern(local_addr[0]->ss_family, SOCK_SEQPACKET, + result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (result < 0) { log_print("Can't create comms socket, check SCTP is loaded"); @@ -700,8 +700,8 @@ static int init_sock(void) 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)); + for (i = 0; i < dlm_local_count; i++) { + memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr)); make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len); result = add_bind_addr(&localaddr, addr_len, num); @@ -879,7 +879,7 @@ static void initiate_association(int nodeid) 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_ppid = cpu_to_le32(dlm_local_nodeid); outmessage.msg_controllen = cmsg->cmsg_len; ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1); @@ -924,7 +924,7 @@ static int send_to_sock(struct nodeinfo *ni) 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_ppid = cpu_to_le32(dlm_local_nodeid); sinfo->sinfo_assoc_id = ni->assoc_id; outmsg.msg_controllen = cmsg->cmsg_len; @@ -1231,9 +1231,9 @@ void dlm_lowcomms_exit(void) { int i; - for (i = 0; i < local_count; i++) - kfree(local_addr[i]); - local_count = 0; - local_nodeid = 0; + for (i = 0; i < dlm_local_count; i++) + kfree(dlm_local_addr[i]); + dlm_local_count = 0; + dlm_local_nodeid = 0; } -- GitLab From 6b61b072a8b54212ab0808c443e5c16699390d25 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 6 Jun 2006 14:49:39 -0400 Subject: [PATCH 0126/1619] [GFS2] Move some fields around to reduce wasted space We can reclaim some space by moving fields in some structures in order to allow them to pack better on 64 bit architectures. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 92091d006a0..8caefec8885 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -158,7 +158,7 @@ struct gfs2_holder { unsigned gh_flags; int gh_error; - unsigned long gh_iflags; + unsigned gh_iflags; struct completion gh_wait; unsigned long gh_ip; }; @@ -217,25 +217,21 @@ struct gfs2_glock { struct gfs2_alloc { /* Quota stuff */ - unsigned int al_qd_num; struct gfs2_quota_data *al_qd[4]; struct gfs2_holder al_qd_ghs[4]; + unsigned int al_qd_num; - /* Filled in by the caller to gfs2_inplace_reserve() */ - - uint32_t al_requested; + u32 al_requested; /* Filled in by caller of gfs2_inplace_reserve() */ + u32 al_alloced; /* Filled in by gfs2_alloc_*() */ /* Filled in by gfs2_inplace_reserve() */ - char *al_file; unsigned int al_line; + char *al_file; 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 { -- GitLab From 01eb7c07968fdab0cca0d2474346cff176537de8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 6 Jun 2006 17:31:30 -0400 Subject: [PATCH 0127/1619] [GFS2] Fix warning on impossible event in eattr code The caller ensures that ea_list_i() is never called with an invalid type, so lets BUG() if we see one. This clears up a couple of compiler warnings too. Signed-off-by: Steven Whitehouse --- fs/gfs2/eattr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 346601538ac..2e114c07570 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -374,8 +374,8 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, return 0; if (er->er_data_len) { - char *prefix; - unsigned int l; + char *prefix = NULL; + unsigned int l = 0; char c = 0; if (ei->ei_size + ea_size > er->er_data_len) @@ -394,11 +394,10 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, prefix = "security."; l = 9; break; - default: - /* FIXME: Needs looking at again */ - break; } + BUG_ON(l == 0); + memcpy(er->er_data + ei->ei_size, prefix, l); memcpy(er->er_data + ei->ei_size + l, GFS2_EA2NAME(ea), ea->ea_name_len); -- GitLab From 22da645fd6675b7abc55cf937ddf6132f343e5b9 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Fri, 9 Jun 2006 16:14:20 -0400 Subject: [PATCH 0128/1619] [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(-) diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 49a20d54921..47798fe46d7 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 f8ba1981aa9..2a2dd189b9f 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; }; -- GitLab From feaa7bba026c181ce071d5a4884f7f9dd26207a1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 14 Jun 2006 15:32:57 -0400 Subject: [PATCH 0129/1619] [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 diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 9974201aa16..0b7977623b8 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 343dbe3e87b..9ef4cf2c03d 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 41abd3f4fc7..98fa07c2b71 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 9e7b9f29678..1453605c8f3 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 aa68e7a1b0b..aa93eb6f668 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 6918a58261e..b0353884dd7 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 1c5ac3160b3..b7e6a37cab6 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 2e114c07570..96736932260 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 0603a6de52c..35bac90878a 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 2e0a2ba92aa..fdf58db44ae 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 e262f22f744..013bf5f1552 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 8caefec8885..9a67a595412 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 c2c7d2b63a5..4e9c42119ae 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 5ef21317b2f..30cfcc10beb 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 2a8b4b71dd1..483d4fa987f 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 e4c75a74df5..a76f1a77892 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 b24d0b40d96..c112943ee8c 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 c78517225f6..2523d42a02d 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 be5c86e5787..09154ad7b27 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 16d3ebd3209..207363aed11 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 fef415e2068..fd55979ec42 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 a376ead7d0c..eacc1c092f9 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 1e8f602c1e5..222f3be3e06 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 a4598204550..b68eb6b4a4c 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 0c06f92368f..f678f6b62af 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 1c17acc946f..317d497f8f8 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 263c1fb7bba..08709f19ea9 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 cd93644c7d7..a8165a693b5 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 f752b018469..d3cd5171d7c 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 c504ac1b831..7aabc03e4ab 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 691e6f3ce43..75df79eb50b 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 d2db3719cc0..e86a532cc15 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 a943a505bc5..f2d287660cc 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 d32a2c54dae..3c4cb455890 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 60ef163dd9b..fbef3f5a99e 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 b92d7300205..00000000000 --- 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 159cf5ffe47..00000000000 --- 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 88974e9824f..39e67b1ec70 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 3893aac4e3a..1181da83193 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 */ -- GitLab From 3a8476dda13bc6690c5c2d5f1d3078048392c188 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 19 Jun 2006 09:10:39 -0400 Subject: [PATCH 0130/1619] [GFS2] Remove debugging printks A few of my printks slipped through last time. Also fix a couple of minor bugs. Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 3 --- fs/gfs2/lops.c | 2 +- fs/gfs2/ops_inode.c | 5 +---- fs/gfs2/ops_super.c | 2 +- fs/gfs2/rgrp.c | 11 ----------- 5 files changed, 3 insertions(+), 20 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 013bf5f1552..a01874c5883 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -129,7 +129,6 @@ 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); } @@ -148,7 +147,6 @@ 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); @@ -226,7 +224,6 @@ 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; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index a76f1a77892..93563e72ae4 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -650,7 +650,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } else gfs2_log_unlock(sdp); - kfree(bd1); + kmem_cache_free(gfs2_bufdata_cachep, bd1); } /* We've removed all the ordered write bufs here, so only jdata left */ diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index f678f6b62af..2fe37aeac7b 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -56,7 +56,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; - int new = 1; gfs2_holder_init(dip->i_gl, 0, 0, ghs); @@ -69,6 +68,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, gfs2_quota_unlock(dip); gfs2_alloc_put(dip); gfs2_glock_dq_uninit_m(2, ghs); + mark_inode_dirty(inode); break; } else if (PTR_ERR(inode) != -EEXIST || (nd->intent.open.flags & O_EXCL)) { @@ -79,7 +79,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); if (inode) { if (!IS_ERR(inode)) { - new = 0; gfs2_holder_uninit(ghs); break; } else { @@ -90,8 +89,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, } d_instantiate(dentry, inode); - if (new) - mark_inode_dirty(inode); return 0; } diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 317d497f8f8..5f5fc3c4290 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -59,7 +59,7 @@ static int gfs2_write_inode(struct inode *inode, int sync) if (current->flags & PF_MEMALLOC) return 0; if (sync) - gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); + gfs2_log_flush(GFS2_SB(inode), ip->i_gl); } return 0; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 75df79eb50b..65134191883 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -447,8 +447,6 @@ static int gfs2_ri_update(struct gfs2_inode *ip) 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; @@ -456,12 +454,9 @@ 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) @@ -485,15 +480,12 @@ 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; @@ -501,14 +493,11 @@ 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: - printk(KERN_INFO "fail\n"); clear_rgrpdi(sdp); - printk(KERN_INFO "cleared rgrps\n"); return error; } -- GitLab From 7d5513d58d072cf38cae9c886653aadac38ef4a9 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 19 Jun 2006 09:15:38 -0400 Subject: [PATCH 0131/1619] [DLM] init rwsem earlier The nodeinfo_lock rwsem needs to be initialized when the module is loaded instead of when the dlm is first used. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 75010da95b3..7ab40422ab5 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1190,10 +1190,6 @@ 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; @@ -1224,6 +1220,9 @@ void dlm_lowcomms_stop(void) int dlm_lowcomms_init(void) { init_waitqueue_head(&lowcomms_recv_wait); + spin_lock_init(&write_nodes_lock); + INIT_LIST_HEAD(&write_nodes); + init_rwsem(&nodeinfo_lock); return 0; } -- GitLab From b61dde795f120f5dca2c865a1860dd9ff76705a1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 19 Jun 2006 10:51:11 -0400 Subject: [PATCH 0132/1619] [GFS2] Always include glock in transaction Include the glock in the transaction, even when not journaling data in order that ordered write data will be correctly flushed when the lock is released. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 93563e72ae4..af03bf380f4 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -467,11 +467,11 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) 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); tr->tr_num_buf_new++; } + gfs2_trans_add_gl(bd->bd_gl); gfs2_log_lock(sdp); if (!list_empty(&le->le_list)) { if (ip->i_di.di_flags & GFS2_DIF_JDATA) -- GitLab From 9f5aa2a921797ce6eb4542c7517915bd1d5fbd0b Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Mon, 19 Jun 2006 16:27:52 -0400 Subject: [PATCH 0133/1619] [DLM] Fix potential conflict in DLM userland locks Just spotted this one. The lockinfo structs are hashed by lockid but into a global structure. So that if there are two lockspaces with the same lockid all hell breaks loose. I'm not exactly sure what will happen but it can't be good! The attached patch moves the lockinfo_idr into the user_ls structure so that lockids are localised. patrick Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/device.c | 60 +++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 47798fe46d7..825bbc0a09c 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -45,10 +45,6 @@ static const char *name_prefix="dlm"; static struct list_head user_ls_list; static struct mutex 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 @@ -99,6 +95,10 @@ struct user_ls { atomic_t ls_refcnt; long ls_flags; + /* Lock infos are stored in here indexed by lock ID */ + struct idr lockinfo_idr; + rwlock_t lockinfo_lock; + /* Passed into misc_register() */ struct miscdevice ls_miscinfo; struct list_head ls_list; @@ -240,13 +240,13 @@ static void put_file_info(struct file_info *f) kfree(f); } -static void release_lockinfo(struct lock_info *li) +static void release_lockinfo(struct user_ls *ls, 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); + write_lock(&ls->lockinfo_lock); + idr_remove(&ls->lockinfo_idr, li->li_lksb.sb_lkid); + write_unlock(&ls->lockinfo_lock); if (li->li_lksb.sb_lvbptr) kfree(li->li_lksb.sb_lvbptr); @@ -255,46 +255,46 @@ static void release_lockinfo(struct lock_info *li) module_put(THIS_MODULE); } -static struct lock_info *get_lockinfo(uint32_t lockid) +static struct lock_info *get_lockinfo(struct user_ls *ls, uint32_t lockid) { struct lock_info *li; - read_lock(&lockinfo_lock); - li = idr_find(&lockinfo_idr, lockid); - read_unlock(&lockinfo_lock); + read_lock(&ls->lockinfo_lock); + li = idr_find(&ls->lockinfo_idr, lockid); + read_unlock(&ls->lockinfo_lock); return li; } -static int add_lockinfo(struct lock_info *li) +static int add_lockinfo(struct user_ls *ls, struct lock_info *li) { int n; int r; int ret = -EINVAL; - write_lock(&lockinfo_lock); + write_lock(&ls->lockinfo_lock); - if (idr_find(&lockinfo_idr, li->li_lksb.sb_lkid)) + if (idr_find(&ls->lockinfo_idr, li->li_lksb.sb_lkid)) goto out_up; ret = -ENOMEM; - r = idr_pre_get(&lockinfo_idr, GFP_KERNEL); + r = idr_pre_get(&ls->lockinfo_idr, GFP_KERNEL); if (!r) goto out_up; - r = idr_get_new_above(&lockinfo_idr, li, li->li_lksb.sb_lkid, &n); + r = idr_get_new_above(&ls->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); + idr_remove(&ls->lockinfo_idr, n); goto out_up; } ret = 0; out_up: - write_unlock(&lockinfo_lock); + write_unlock(&ls->lockinfo_lock); return ret; } @@ -358,6 +358,9 @@ static int register_lockspace(char *name, struct user_ls **ls, int flags) return status; } + idr_init(&newls->lockinfo_idr); + rwlock_init(&newls->lockinfo_lock); + snprintf((char*)newls->ls_miscinfo.name, namelen, "%s_%s", name_prefix, name); @@ -486,13 +489,13 @@ static void ast_routine(void *param) list_del(&li->li_ownerqueue); clear_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&li->li_file->fi_li_lock); - release_lockinfo(li); + release_lockinfo(li->li_file->fi_ls, li); return; } /* Free unlocks & queries */ if (li->li_lksb.sb_status == -DLM_EUNLOCK || li->li_cmd == DLM_USER_QUERY) { - release_lockinfo(li); + release_lockinfo(li->li_file->fi_ls, li); } } else { /* Synchronous request, just wake up the caller */ @@ -641,7 +644,7 @@ static int dlm_close(struct inode *inode, struct file *file) old_li->li_lksb.sb_lkid, status); /* But tidy our references in it */ - release_lockinfo(old_li); + release_lockinfo(old_li->li_file->fi_ls, old_li); continue; } @@ -662,7 +665,7 @@ static int dlm_close(struct inode *inode, struct file *file) /* Unlock suceeded, free the lock_info struct. */ if (status == 0) - release_lockinfo(old_li); + release_lockinfo(old_li->li_file->fi_ls, old_li); } remove_wait_queue(&li.li_waitq, &wq); @@ -920,7 +923,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, unless we are adopting an orphaned persistent lock */ if (kparams->flags & DLM_LKF_CONVERT) { - li = get_lockinfo(kparams->lkid); + li = get_lockinfo(fi->fi_ls, kparams->lkid); /* If this is a persistent lock we will have to create a lockinfo again */ @@ -938,7 +941,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, fail we want rid of it */ init_completion(&li->li_firstcomp); set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); - add_lockinfo(li); + add_lockinfo(fi->fi_ls, li); /* TODO: do a query to get the current state ?? */ } @@ -1014,7 +1017,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, list_add(&li->li_ownerqueue, &fi->fi_li_list); set_bit(LI_FLAG_ONLIST, &li->li_flags); spin_unlock(&fi->fi_li_lock); - if (add_lockinfo(li)) + if (add_lockinfo(fi->fi_ls, li)) printk(KERN_WARNING "Add lockinfo failed\n"); complete(&li->li_firstcomp); @@ -1025,7 +1028,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, out_err: if (test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags)) - release_lockinfo(li); + release_lockinfo(fi->fi_ls, li); return status; } @@ -1037,7 +1040,7 @@ static int do_user_unlock(struct file_info *fi, uint8_t cmd, int status; int convert_cancel = 0; - li = get_lockinfo(kparams->lkid); + li = get_lockinfo(fi->fi_ls, kparams->lkid); if (!li) { li = allocate_lockinfo(fi, cmd, kparams); if (!li) @@ -1209,7 +1212,6 @@ static int __init dlm_device_init(void) INIT_LIST_HEAD(&user_ls_list); mutex_init(&user_ls_lock); - rwlock_init(&lockinfo_lock); ctl_device.name = "dlm-control"; ctl_device.fops = &_dlm_ctl_fops; -- GitLab From 695165dfba5204791bc4ae8911ed8b6326ce6d91 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 Jun 2006 13:44:27 +0100 Subject: [PATCH 0134/1619] [GFS2] Fix use of bitops on unsigned int (struct gfs2_holder->gh_iflags) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/gfs2/glock.c: In function ‘gfs2_holder_get’: fs/gfs2/glock.c:439: warning: passing argument 2 of ‘set_bit’ from incompatible pointer type fs/gfs2/glock.c: In function ‘rq_promote’: fs/gfs2/glock.c:512: warning: passing argument 2 of ‘set_bit’ from incompatible pointer type fs/gfs2/glock.c:526: warning: passing argument 2 of ‘set_bit’ from incompatible pointer type ... Signed-off-by: David Woodhouse --- fs/gfs2/incore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 9a67a595412..034a855a14b 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -157,7 +157,7 @@ struct gfs2_holder { unsigned gh_flags; int gh_error; - unsigned gh_iflags; + unsigned long gh_iflags; struct completion gh_wait; unsigned long gh_ip; }; -- GitLab From 0239c4ae8aa5cdee6dc3792effc2800d65292c04 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 Jun 2006 13:48:31 +0100 Subject: [PATCH 0135/1619] [GFS2] Fix printk format warnings in DLM code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/gfs2/locking/dlm/thread.c: In function ‘process_complete’: fs/gfs2/locking/dlm/thread.c:56: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 3 has type ‘uint64_t’ fs/gfs2/locking/dlm/thread.c:69: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 4 has type ‘uint64_t’ fs/gfs2/locking/dlm/thread.c:102: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 3 has type ‘uint64_t’ fs/gfs2/locking/dlm/thread.c:124: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 4 has type ‘uint64_t’ fs/gfs2/locking/dlm/thread.c:146: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 4 has type ‘uint64_t’ fs/gfs2/locking/dlm/thread.c:148: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 4 has type ‘uint64_t’ Signed-off-by: David Woodhouse --- fs/gfs2/locking/dlm/thread.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 3e2edcc2dbf..489235b2edb 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -54,7 +54,8 @@ static void process_complete(struct gdlm_lock *lp) if (lp->lksb.sb_status == -DLM_ECANCEL) { log_info("complete dlm cancel %x,%llx flags %lx", - lp->lockname.ln_type, lp->lockname.ln_number, + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); lp->req = lp->cur; @@ -68,7 +69,8 @@ static void process_complete(struct gdlm_lock *lp) if (lp->lksb.sb_status != -DLM_EUNLOCK) { log_info("unlock sb_status %d %x,%llx flags %lx", lp->lksb.sb_status, lp->lockname.ln_type, - lp->lockname.ln_number, lp->flags); + (unsigned long long)lp->lockname.ln_number, + lp->flags); return; } @@ -100,7 +102,8 @@ static void process_complete(struct gdlm_lock *lp) if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) { log_info("complete internal cancel %x,%llx", - lp->lockname.ln_type, lp->lockname.ln_number); + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); lp->req = lp->cur; acb.lc_ret |= LM_OUT_CANCELED; goto out; @@ -123,7 +126,8 @@ static void process_complete(struct gdlm_lock *lp) /* this could only happen with cancels I think */ log_info("ast sb_status %d %x,%llx flags %lx", lp->lksb.sb_status, lp->lockname.ln_type, - lp->lockname.ln_number, lp->flags); + (unsigned long long)lp->lockname.ln_number, + lp->flags); return; } @@ -144,9 +148,11 @@ static void process_complete(struct gdlm_lock *lp) if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) { gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx", - lp->lockname.ln_type, lp->lockname.ln_number); + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx", - lp->lockname.ln_type, lp->lockname.ln_number); + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); lp->cur = DLM_LOCK_NL; lp->req = lp->prev_req; @@ -183,7 +189,8 @@ static void process_complete(struct gdlm_lock *lp) lp->lkf &= ~DLM_LKF_CONVDEADLK; log_debug("rereq %x,%llx id %x %d,%d", - lp->lockname.ln_type, lp->lockname.ln_number, + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid, lp->cur, lp->req); set_bit(LFL_REREQUEST, &lp->flags); -- GitLab From 0d42e54220ba34e031167138ef91cbd42d8b5876 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 20 Jun 2006 16:13:49 -0400 Subject: [PATCH 0136/1619] [GFS2] Remove unused ra_state variable As per Nick Piggin's comments on lkml, remove the unused ra_state variable. Signed-off-by: Steven Whitehouse Cc: Nick Piggin --- fs/gfs2/quota.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index d3cd5171d7c..1892b29ec98 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -649,7 +649,6 @@ 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 = GFS2_I(sdp->sd_quota_inode); unsigned int data_blocks, ind_blocks; - struct file_ra_state ra_state; struct gfs2_holder *ghs, i_gh; unsigned int qx, x; struct gfs2_quota_data *qd; @@ -716,7 +715,6 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) goto out_gunlock; } - file_ra_state_init(&ra_state, ip->i_inode.i_mapping); for (x = 0; x < num_qd; x++) { qd = qda[x]; offset = qd2offset(qd); @@ -790,10 +788,8 @@ 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(ip, - &ra_state, buf, - &pos, - sizeof(struct gfs2_quota)); + error = gfs2_internal_read(ip, &ra_state, buf, + &pos, sizeof(struct gfs2_quota)); if (error < 0) goto fail_gunlock; -- GitLab From bf9f424d9acf461fabcb0e9f47b356e08186d91f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 21 Jun 2006 11:54:43 -0400 Subject: [PATCH 0137/1619] [GFS2] Make file_read_actor export _GPL Make file_read_actor export a _GPL export. Signed-off-by: Steven Whitehouse --- mm/filemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/filemap.c b/mm/filemap.c index 82c448898d0..a02a0b2c986 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1044,7 +1044,7 @@ success: desc->arg.buf += size; return size; } -EXPORT_SYMBOL(file_read_actor); +EXPORT_SYMBOL_GPL(file_read_actor); /* * This is the "read()" routine for all filesystems -- GitLab From d9d1ca30505c6fed867e1724b16fdad0c281d7d1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 21 Jun 2006 15:38:17 -0400 Subject: [PATCH 0138/1619] [GFS2] Fix double locking problem in rename The rename inode operation was trying to lock the same inode twice in the case of renaming with the source and destination directories the same. We now test for this and just lock once. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_inode.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 2fe37aeac7b..3a2769ebfe4 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -615,13 +615,19 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_gunlock_r; } + num_gh = 1; 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 (odip != ndip) { + gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); + num_gh++; + } + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); + num_gh++; - if (nip) - gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); + if (nip) { + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); + num_gh++; + } error = gfs2_glock_nq_m(num_gh, ghs); if (error) -- GitLab From faf450ef4a8567e4c75a905aadae01cf401d893a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 22 Jun 2006 10:59:10 -0400 Subject: [PATCH 0139/1619] [GFS2] Remove gfs2_repermission gfs2_repermission is just a wrapper for permission, so remove it and call permission directly where required. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 4 +--- fs/gfs2/inode.c | 11 +++-------- fs/gfs2/inode.h | 2 -- fs/gfs2/ops_file.c | 2 +- fs/gfs2/ops_inode.c | 10 ++++------ 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 9ef4cf2c03d..39931784150 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -179,9 +179,7 @@ int gfs2_check_acl(struct inode *inode, int mask) struct gfs2_holder i_gh; int error; - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_SHARED, LM_FLAG_ANY, - &i_gh); + 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); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 4e9c42119ae..c19feb9697b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -420,7 +420,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, return ERR_PTR(error); if (!is_root) { - error = gfs2_repermission(dir, MAY_EXEC, NULL); + error = permission(dir, MAY_EXEC, NULL); if (error) goto out; } @@ -571,7 +571,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, { int error; - error = gfs2_repermission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL); + error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL); if (error) return error; @@ -1003,7 +1003,7 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, if (IS_APPEND(&dip->i_inode)) return -EPERM; - error = gfs2_repermission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL); + error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL); if (error) return error; @@ -1356,8 +1356,3 @@ int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) 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 index 30cfcc10beb..8bb8b559bce 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -50,8 +50,6 @@ int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs); int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); -int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd); - struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); #endif /* __INODE_DOT_H__ */ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 222f3be3e06..5e754198f5b 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -640,7 +640,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) !capable(CAP_LINUX_IMMUTABLE)) goto out; if (!IS_IMMUTABLE(inode)) { - error = gfs2_repermission(inode, MAY_WRITE, NULL); + error = permission(inode, MAY_WRITE, NULL); if (error) goto out; } diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 3a2769ebfe4..5d5ebbcba53 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -155,7 +155,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (error) goto out; - error = gfs2_repermission(dir, MAY_WRITE | MAY_EXEC, NULL); + error = permission(dir, MAY_WRITE | MAY_EXEC, NULL); if (error) goto out_gunlock; @@ -659,7 +659,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, } } } else { - error = gfs2_repermission(ndir, MAY_WRITE | MAY_EXEC, NULL); + error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL); if (error) goto out_gunlock; @@ -694,7 +694,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Check out the dir to be renamed */ if (dir_rename) { - error = gfs2_repermission(odentry->d_inode, MAY_WRITE, NULL); + error = permission(odentry->d_inode, MAY_WRITE, NULL); if (error) goto out_gunlock; } @@ -888,9 +888,7 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) 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); + 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); -- GitLab From 43f5d210a02dcf9d8bafb147044f27add10a459a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 22 Jun 2006 11:16:40 -0400 Subject: [PATCH 0140/1619] [GFS2] [-mm patch] fs/gfs2/: make code static This patch makes the following needlessly global code static: - eaops.c: struct gfs2_security_eaops - rgrp.c: gfs2_free_uninit_di() Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/eaops.c | 2 +- fs/gfs2/eaops.h | 2 -- fs/gfs2/rgrp.c | 2 +- fs/gfs2/rgrp.h | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index b7e6a37cab6..3ace242f2b1 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -214,7 +214,7 @@ struct gfs2_eattr_operations gfs2_system_eaops = { .eo_name = "system", }; -struct gfs2_eattr_operations gfs2_security_eaops = { +static struct gfs2_eattr_operations gfs2_security_eaops = { .eo_get = security_eo_get, .eo_set = security_eo_set, .eo_remove = security_eo_remove, diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 965a235c96e..3dece17e311 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -23,8 +23,6 @@ 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/rgrp.c b/fs/gfs2/rgrp.c index 65134191883..14c1f88bfb5 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1401,7 +1401,7 @@ void gfs2_unlink_di(struct inode *inode) gfs2_trans_add_rg(rgd); } -void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) +static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) { struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_rgrpd *tmp_rgd; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index e86a532cc15..9c42d2252dd 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -43,7 +43,6 @@ 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); void gfs2_unlink_di(struct inode *inode); -- GitLab From bdd512aeeab860f7a9a537142dd0983f884d723a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 22 Jun 2006 15:26:33 -0400 Subject: [PATCH 0141/1619] [GFS2] Remove unused flag The flag GIF_MIN_INIT is no longer used or required. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 1 - fs/gfs2/inode.c | 1 - 2 files changed, 2 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 034a855a14b..90e0624d806 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -234,7 +234,6 @@ struct gfs2_alloc { }; enum { - GIF_MIN_INIT = 0, GIF_QD_LOCKED = 1, GIF_PAGED = 2, GIF_SW_PAGED = 3, diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c19feb9697b..6499c4f9107 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -236,7 +236,6 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) } gfs2_dinode_in(&ip->i_di, dibh->b_data); - set_bit(GIF_MIN_INIT, &ip->i_flags); brelse(dibh); -- GitLab From a464418425192da270a9944d0e48c33e186af601 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 22 Jun 2006 15:29:57 -0400 Subject: [PATCH 0142/1619] [GFS2] gfs2/dlm: mailing list and web page List new development mailing list and correct web page url. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- MAINTAINERS | 4 ++-- fs/gfs2/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 50817bf6069..b7206bbc96f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -845,7 +845,7 @@ P: Patrick Caulfield M: pcaulfie@redhat.com P: David Teigland M: teigland@redhat.com -L: linux-cluster@redhat.com +L: cluster-devel@redhat.com W: http://sources.redhat.com/cluster/ T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git S: Supported @@ -1103,7 +1103,7 @@ S: Maintained GFS2 FILE SYSTEM P: Steven Whitehouse M: swhiteho@redhat.com -L: linux-cluster@redhat.com +L: cluster-devel@redhat.com W: http://sources.redhat.com/cluster/ T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git S: Supported diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 115f30d8c22..8c27de8b956 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -15,7 +15,7 @@ config GFS2_FS 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/ + be found here: http://sources.redhat.com/cluster config GFS2_FS_LOCKING_NOLOCK tristate "GFS2 \"nolock\" locking module" -- GitLab From a53311d4d9e1cde15aebc2048847ea19fb33ac3a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 23 Jun 2006 16:16:29 -0400 Subject: [PATCH 0143/1619] [GFS2] Use generic_file_sendfile directly Don't use a wrapper for generic_file_sendfile but call it directly. Cc: Christoph Hellwig Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 5e754198f5b..ecef76e8373 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -859,24 +859,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) 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) -{ - return generic_file_sendfile(in_file, offset, count, actor, target); -} - static int do_flock(struct file *file, int cmd, struct file_lock *fl) { struct gfs2_file *fp = file->private_data; @@ -982,7 +964,7 @@ struct file_operations gfs2_file_fops = { .release = gfs2_close, .fsync = gfs2_fsync, .lock = gfs2_lock, - .sendfile = gfs2_sendfile, + .sendfile = generic_file_sendfile, .flock = gfs2_flock, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, -- GitLab From af18ddb8864b096e3ed4732e2d4b21c956dcfe3a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sat, 24 Jun 2006 15:42:21 -0400 Subject: [PATCH 0144/1619] [GFS2] Eliminate one instance of __GFP_NOFAIL This removes one instance of GFP_NOFAIL from the glock callback function. It also fixes a bug where a , was used at a line end rather than ; causing unintended results. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 8 +++++--- fs/gfs2/ops_inode.c | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 35bac90878a..dbeb4ad836b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -416,7 +416,7 @@ void gfs2_holder_uninit(struct gfs2_holder *gh) * @gl: the glock * @state: the state we're requesting * @flags: the modifier flags - * @gfp_flags: __GFP_NOFAIL + * @gfp_flags: * * Figure out how big an impact this function has. Either: * 1) Replace it with a cache of structures hanging off the struct gfs2_sbd @@ -720,6 +720,7 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl) * @gl: the glock * @state: the state the caller wants us to change to * + * Note: This may fail sliently if we are out of memory. */ static void handle_callback(struct gfs2_glock *gl, unsigned int state) @@ -744,8 +745,9 @@ restart: } else { spin_unlock(&gl->gl_spin); - new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, - GFP_KERNEL | __GFP_NOFAIL), + new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_KERNEL); + if (!new_gh) + return; set_bit(HIF_DEMOTE, &new_gh->gh_iflags); set_bit(HIF_DEALLOC, &new_gh->gh_iflags); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 5d5ebbcba53..8895baafc64 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -962,10 +962,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) 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); + 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: -- GitLab From 02630a12c7f72fa294981c8d86e38038781c25b7 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 3 Jul 2006 11:20:06 -0400 Subject: [PATCH 0145/1619] [GFS2] Remove dependance on tty_write_message() This removes the call in GFS2 to tty_write_message and replaces it with a printk. As the export was added by GFS2, we remove this as well. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 23 ++++------------------- kernel/printk.c | 1 - 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 1892b29ec98..3ca65c37c35 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -929,25 +928,11 @@ void gfs2_quota_unlock(struct gfs2_inode *ip) 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); + printk(KERN_INFO "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); return 0; } diff --git a/kernel/printk.c b/kernel/printk.c index 9772b9e8fee..39ae24d2a41 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1040,7 +1040,6 @@ void tty_write_message(struct tty_struct *tty, char *msg) tty->driver->write(tty, msg, strlen(msg)); return; } -EXPORT_SYMBOL_GPL(tty_write_message); /* * printk rate limiting, lifted from the networking subsystem. -- GitLab From ccd6efd0cd1244d5d4404393576c37f269de4c5a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 30 Jun 2006 02:16:34 -0700 Subject: [PATCH 0146/1619] [patch 1/1] gfs2: get_sb_dev() fix Update GFS2 for dhowells API changes. Cc: Steven Whitehouse Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index b68eb6b4a4c..b040fda1f54 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -812,11 +812,10 @@ static int fill_super(struct super_block *sb, void *data, int silent) return error; } -static struct super_block *gfs2_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int gfs2_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, fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); } static void gfs2_kill_sb(struct super_block *sb) -- GitLab From 0c0834a30cceeaf2748705d2b31f0d058693b716 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 3 Jul 2006 11:38:01 -0400 Subject: [PATCH 0147/1619] [GFS2] API change for gfs2_statfs The kernel API for super_operations->statfs() has changed so this updates GFS2 to the new API. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 5f5fc3c4290..50ea7f21f9c 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -202,8 +202,9 @@ static void gfs2_unlockfs(struct super_block *sb) * Returns: 0 on success or error code */ -static int gfs2_statfs(struct super_block *sb, struct kstatfs *buf) +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; int error; -- GitLab From 66de045d9fe6147b065c47236d3b9d8d8a6cbd57 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 3 Jul 2006 13:37:30 -0400 Subject: [PATCH 0148/1619] [GFS2] Make our address_space_operations const As per Christoph's patch: http://www.kernel.org/git/?p=linux/kernel/git/steve/gfs2-2.6.git;a=commitdiff;h=f5e54d6e53a20cef45af7499e86164f0e0d16bb2 We mark struct address_space_operations const in GFS2. Signed-off-by: Steven Whitehouse --- fs/gfs2/meta_io.c | 2 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/ops_address.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 2523d42a02d..ddcd4dc1081 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -159,7 +159,7 @@ static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) return try_to_free_buffers(page); } -static struct address_space_operations aspace_aops = { +static const struct address_space_operations aspace_aops = { .writepage = gfs2_aspace_writepage, .releasepage = gfs2_aspace_releasepage, }; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 207363aed11..26db3335d4b 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -655,7 +655,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, DIO_OWN_LOCKING); } -struct address_space_operations gfs2_file_aops = { +const struct address_space_operations gfs2_file_aops = { .writepage = gfs2_writepage, .readpage = gfs2_readpage, .readpages = gfs2_readpages, diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index b88adddaffb..a7ef3bf36f3 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -10,7 +10,7 @@ #ifndef __OPS_ADDRESS_DOT_H__ #define __OPS_ADDRESS_DOT_H__ -extern struct address_space_operations gfs2_file_aops; +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); -- GitLab From b0dd9308b703310e9a988df70f6ed3e87cb55655 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 3 Jul 2006 13:47:02 -0400 Subject: [PATCH 0149/1619] [GFS2] Mark file_operations const As per Arjan's patches: http://www.kernel.org/git/?p=linux/kernel/git/steve/gfs2-2.6.git;a=commitdiff;h=99ac48f54a91d02140c497edc31dc57d4bc5c85d and http://www.kernel.org/git/?p=linux/kernel/git/steve/gfs2-2.6.git;a=commitdiff;h=4b6f5d20b04dcbc3d888555522b90ba6d36c4106 make the GFS2 file_operations structures const. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 4 ++-- fs/gfs2/ops_file.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index ecef76e8373..c8e2c98700a 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -950,7 +950,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) return do_flock(file, cmd, fl); } -struct file_operations gfs2_file_fops = { +const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, .read = gfs2_read, .readv = gfs2_file_readv, @@ -970,7 +970,7 @@ struct file_operations gfs2_file_fops = { .splice_write = generic_file_splice_write, }; -struct file_operations gfs2_dir_fops = { +const struct file_operations gfs2_dir_fops = { .readdir = gfs2_readdir, .unlocked_ioctl = gfs2_ioctl, .open = gfs2_open, diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index a2edce38f5c..46302b51393 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -14,7 +14,7 @@ extern int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, char *buf, loff_t *pos, unsigned size); -extern struct file_operations gfs2_file_fops; -extern struct file_operations gfs2_dir_fops; +extern const struct file_operations gfs2_file_fops; +extern const struct file_operations gfs2_dir_fops; #endif /* __OPS_FILE_DOT_H__ */ -- GitLab From faac9bd0e3ce7cb0572ec66e0a426cacf6afa970 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 5 Jul 2006 08:24:34 -0400 Subject: [PATCH 0150/1619] [GFS2] Fix locking for Direct I/O reads We need to hold i_mutex when doing direct i/o reads. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 26db3335d4b..27ce30148e6 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -642,6 +642,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_mapping->host; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); + int ret; if (rw == WRITE) return gfs2_direct_IO_write(iocb, iov, offset, nr_segs); @@ -650,9 +651,12 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) return -EINVAL; - return __blockdev_direct_IO(READ, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, gfs2_get_block, NULL, - DIO_OWN_LOCKING); + mutex_lock(&inode->i_mutex); + ret = __blockdev_direct_IO(READ, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, gfs2_get_block, NULL, + DIO_OWN_LOCKING); + mutex_unlock(&inode->i_mutex); + return ret; } const struct address_space_operations gfs2_file_aops = { -- GitLab From ecb1460dc44ffb8d3e570597f394504898f088bb Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 5 Jul 2006 10:41:39 -0400 Subject: [PATCH 0151/1619] [GFS2] Make GFS2 work with lock validator Change our one existing old-style lock initialiser to a new-style one. This allows the lock validator to work as intended. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index b040fda1f54..a86ce67949d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -57,7 +57,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *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; + rwlock_init(&sdp->sd_gl_hash[x].hb_lock); INIT_LIST_HEAD(&sdp->sd_gl_hash[x].hb_list); } INIT_LIST_HEAD(&sdp->sd_reclaim_list); -- GitLab From 3864caea2ed2b43bfc92e5cfbe001abe3f002a06 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 5 Jul 2006 11:17:36 -0400 Subject: [PATCH 0152/1619] [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(-) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 2b8a7d68fae..2121cde187d 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 \ -- GitLab From fd4de2d41a9de2d949b0850d637aa84616f87ab8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 5 Jul 2006 13:14:59 -0400 Subject: [PATCH 0153/1619] [GFS2] Add cast for printk Cast a uint64_t to unsigned long long for a printk. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 483d4fa987f..1596e9436c4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -214,7 +214,7 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) 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); + printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, (unsigned long long)dbn, lbn); } gfs2_assert_withdraw(sdp, !error && dbn); -- GitLab From 627add2d1385394d020c84533c91ad26bc37b166 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 5 Jul 2006 13:16:19 -0400 Subject: [PATCH 0154/1619] [GFS2] Correct logic in glock scanner Under certain circumstances the glock scanning logic would demote locks which ought not to have been selected for demotion. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index dbeb4ad836b..7f362d0c3f7 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1967,8 +1967,11 @@ 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) + if (ip == NULL) { + struct gfs2_sbd *sdp = gl->gl_sbd; + gfs2_assert_withdraw(sdp, gl->gl_state == LM_ST_UNLOCKED); goto out_schedule; + } } if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && @@ -1982,7 +1985,7 @@ static void scan_glock(struct gfs2_glock *gl) return; - out_schedule: +out_schedule: gfs2_glmutex_unlock(gl); gfs2_glock_schedule_for_reclaim(gl); gfs2_glock_put(gl); -- GitLab From 29937ac6caa68d60c7f1a3e07b6137cf53e09e24 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 6 Jul 2006 17:58:03 -0400 Subject: [PATCH 0155/1619] [GFS2] Fixes to scanning of glocks (again) This really is the correct fix this time. We just ignore all glocks associated with inodes until the inodes are pushed from the inode cache. At that point the glocks are queued for reclaim, so we don't need to do it here. Also fix one or two other minor bugs. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 12 +++--------- fs/gfs2/inode.c | 2 ++ fs/gfs2/ops_inode.c | 1 + fs/gfs2/page.c | 3 +-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 7f362d0c3f7..0381d4cc414 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1965,19 +1965,13 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, 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 == NULL) { - struct gfs2_sbd *sdp = gl->gl_sbd; - gfs2_assert_withdraw(sdp, gl->gl_state == LM_ST_UNLOCKED); - goto out_schedule; - } - } + if (gl->gl_ops == &gfs2_inode_glops) + goto out; if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) goto out_schedule; - +out: gfs2_glmutex_unlock(gl); } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6499c4f9107..f4c48395208 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -325,6 +325,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) uint32_t nlink; int error; + BUG_ON(ip->i_di.di_nlink != ip->i_inode.i_nlink); nlink = ip->i_di.di_nlink + diff; /* If we are reducing the nlink count, but the new value ends up being @@ -341,6 +342,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) ip->i_di.di_nlink = nlink; 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->i_di, dibh->b_data); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 8895baafc64..caecafe0469 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -250,6 +250,7 @@ out: gfs2_holder_uninit(ghs + 1); if (!error) { + atomic_inc(&inode->i_count); d_instantiate(dentry, inode); mark_inode_dirty(inode); } diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index a8165a693b5..b93caf294b9 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -256,8 +256,7 @@ void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, struct buffer_head *bh; unsigned int start, end; - for (bh = head, start = 0; - bh != head || !start; + for (bh = head, start = 0; bh != head || !start; bh = bh->b_this_page, start = end) { end = start + bsize; if (end <= from || start >= to) -- GitLab From dc3e130a08996e2b56381365a5ac7bb1ce2a9f47 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 10 Jul 2006 11:19:29 -0400 Subject: [PATCH 0156/1619] [GFS2] Remove unused code from dir.c Remove a couple of commented out, and unused lines of code. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index b0353884dd7..13d3709e0c0 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -78,13 +78,8 @@ #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, -- GitLab From ffeb874b2b893aea7d10b0b088e06a7b1ded2a3e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 10 Jul 2006 15:47:01 -0400 Subject: [PATCH 0157/1619] [GFS2] Bug fix to gfs2_readpages() This fixes a bug where we were releasing a page incorrectly sometimes when reading a stuffed file. This fixes the bug that Kevin reported when using Xen. Cc: Kevin Anderson Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 27ce30148e6..2c4ec5cf21f 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -249,8 +249,6 @@ out_unlock: goto out; } -#define list_to_page(head) (list_entry((head)->prev, struct page, lru)) - /** * gfs2_readpages - Read a bunch of pages at once * @@ -290,7 +288,8 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, struct pagevec lru_pvec; pagevec_init(&lru_pvec, 0); for (page_idx = 0; page_idx < nr_pages; page_idx++) { - struct page *page = list_to_page(pages); + struct page *page = list_entry(pages->prev, struct page, lru); + prefetchw(&page->flags); list_del(&page->lru); if (!add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { @@ -298,8 +297,9 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, unlock_page(page); if (!pagevec_add(&lru_pvec, page)) __pagevec_lru_add(&lru_pvec); + } else { + page_cache_release(page); } - page_cache_release(page); } pagevec_lru_add(&lru_pvec); ret = 0; @@ -321,7 +321,7 @@ out_noerror: out_unlock: /* unlock all pages, we can't do any I/O right now */ for (page_idx = 0; page_idx < nr_pages; page_idx++) { - struct page *page = list_to_page(pages); + struct page *page = list_entry(pages->prev, struct page, lru); list_del(&page->lru); unlock_page(page); page_cache_release(page); -- GitLab From 4340fe62531f7d1dafb6f5359ffe0378bdb0db80 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 11 Jul 2006 09:46:33 -0400 Subject: [PATCH 0158/1619] [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(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f4c48395208..22ca3b5ddae 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 ddcd4dc1081..cad44fd70d6 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 09154ad7b27..39c7f0345fc 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 2c4ec5cf21f..031270ad55e 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 a7ef3bf36f3..dfc3dda6de1 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 c8e2c98700a..26f1d3249b0 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 14c1f88bfb5..65eea0b88bf 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 9c42d2252dd..14600944d18 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 1181da83193..3ebd8743ce8 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_... */ -- GitLab From f3bba03fd16e25a262323293e5a07dea173c89f7 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 11 Jul 2006 09:50:54 -0400 Subject: [PATCH 0159/1619] [GFS2] Fix deadlock in memory allocation We must not call GFP_KERNEL memory allocations while we are holding the log lock (read or write) since that may trigger a log flush resulting in a deadlock. Eventually we need to fix the locking in log.c, for now this solves the problem at the expense of freeing up memory as fast as we would like to. This needs to be revisited later on. Cc: Kevin Anderson Signed-off-by: Steven Whitehouse --- fs/gfs2/meta_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index cad44fd70d6..42dfd32059b 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -75,7 +75,7 @@ struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) aspace = new_inode(sdp->sd_vfs); if (aspace) { - mapping_set_gfp_mask(aspace->i_mapping, GFP_KERNEL); + mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS); aspace->i_mapping->a_ops = &aspace_aops; aspace->i_size = ~0ULL; aspace->u.generic_ip = NULL; -- GitLab From b2a580d87b33816aa9b50268f70666368e12f7df Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Mon, 10 Jul 2006 12:36:12 -0500 Subject: [PATCH 0160/1619] [PATCH] patch to init di_payload_format field in gfs2_dinode A missing initialisation when creating a new on disk inode. Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 22ca3b5ddae..e76f345517b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -696,6 +696,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_height = cpu_to_be32(0); di->__pad2 = 0; di->__pad3 = 0; -- GitLab From 4da3c6463ef6759fb50d12c8652bc29c5c1730a4 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 11 Jul 2006 13:19:13 -0400 Subject: [PATCH 0161/1619] [GFS2] Fix a coupls of warnings in dir.c Fix a couple of compiler warnings in dir.c caused by potentially uninitialised variables. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 13d3709e0c0..e96b5322c84 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -936,7 +936,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) 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; + struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new; uint32_t start, len, half_len, divider; uint64_t bn, *lp, leaf_no; uint32_t index; @@ -1356,7 +1356,7 @@ static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, uint64_t *lp; int copied = 0; int error = 0; - unsigned depth; + unsigned depth = 0; hsize = 1 << dip->i_di.di_depth; if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { -- GitLab From 2eb168ca94aba3bcae350ad9b31870955174a218 Mon Sep 17 00:00:00 2001 From: Wendy Cheng Date: Tue, 11 Jul 2006 13:28:53 -0400 Subject: [PATCH 0162/1619] [GFS2] NFS update Update the NFS filehandles so that they contain the file type. Signed-off-by: Wendy Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_export.c | 32 ++++++++++++++++++++------------ fs/gfs2/ops_export.h | 4 ++++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index eacc1c092f9..6354f4799e6 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -34,30 +34,34 @@ static struct dentry *gfs2_decode_fh(struct super_block *sb, struct dentry *dentry), void *context) { - struct gfs2_inum this, parent; + struct gfs2_fh_obj fh_obj; + struct gfs2_inum *this, parent; if (fh_type != fh_len) return NULL; + this = &fh_obj.this; + fh_obj.imode = DT_UNKNOWN; memset(&parent, 0, sizeof(struct gfs2_inum)); switch (fh_type) { - case 8: + case 10: 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]); + fh_obj.imode = be32_to_cpu(fh[8]); 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]); + 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, + return gfs2_export_ops.find_exported_dentry(sb, &fh_obj, &parent, acceptable, context); } @@ -68,7 +72,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, struct super_block *sb = inode->i_sb; struct gfs2_inode *ip = GFS2_I(inode); - if (*len < 4 || (connectable && *len < 8)) + if (*len < 4 || (connectable && *len < 10)) return 255; fh[0] = ip->i_num.no_formal_ino >> 32; @@ -98,7 +102,10 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[6] = cpu_to_be32(fh[6]); fh[7] = ip->i_num.no_addr & 0xFFFFFFFF; fh[7] = cpu_to_be32(fh[7]); - *len = 8; + + fh[8] = cpu_to_be32(inode->i_mode); + fh[9] = 0; /* pad to double word */ + *len = 10; iput(inode); @@ -186,10 +193,11 @@ static struct dentry *gfs2_get_parent(struct dentry *child) return dentry; } -static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) +static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) { struct gfs2_sbd *sdp = sb->s_fs_info; - struct gfs2_inum *inum = inum_p; + struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj; + struct gfs2_inum *inum = &fh_obj->this; struct gfs2_holder i_gh, ri_gh, rgd_gh; struct gfs2_rgrpd *rgd; struct inode *inode; @@ -233,7 +241,7 @@ 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); - inode = gfs2_inode_lookup(sb, inum, DT_UNKNOWN); + inode = gfs2_inode_lookup(sb, inum, fh_obj->imode); if (!inode) goto fail; if (IS_ERR(inode)) { diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h index 88d58e57f51..09fc077657d 100644 --- a/fs/gfs2/ops_export.h +++ b/fs/gfs2/ops_export.h @@ -11,5 +11,9 @@ #define __OPS_EXPORT_DOT_H__ extern struct export_operations gfs2_export_ops; +struct gfs2_fh_obj { + struct gfs2_inum this; + __u32 imode; +}; #endif /* __OPS_EXPORT_DOT_H__ */ -- GitLab From 597d0cae0f99f62501e229bed50e8149604015bb Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 12 Jul 2006 16:44:04 -0500 Subject: [PATCH 0163/1619] [DLM] dlm: user locks This changes the way the dlm handles user locks. The core dlm is now aware of user locks so they can be dealt with more efficiently. There is no more dlm_device module which previously managed its own duplicate copy of every user lock. Signed-off-by: Patrick Caulfield Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/Kconfig | 8 - fs/dlm/Makefile | 4 +- fs/dlm/ast.c | 7 +- fs/dlm/device.c | 1239 ----------------------------------------- fs/dlm/dlm_internal.h | 44 ++ fs/dlm/lock.c | 304 +++++++++- fs/dlm/lock.h | 11 + fs/dlm/lockspace.c | 32 +- fs/dlm/lockspace.h | 1 + fs/dlm/main.c | 8 + fs/dlm/memory.c | 9 + fs/dlm/user.c | 769 +++++++++++++++++++++++++ fs/dlm/user.h | 16 + 13 files changed, 1192 insertions(+), 1260 deletions(-) delete mode 100644 fs/dlm/device.c create mode 100644 fs/dlm/user.c create mode 100644 fs/dlm/user.h diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig index 09e78bf6e7a..490f85b3fa5 100644 --- a/fs/dlm/Kconfig +++ b/fs/dlm/Kconfig @@ -10,14 +10,6 @@ config DLM 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 diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile index 1e6232e7d8e..1832e0297f7 100644 --- a/fs/dlm/Makefile +++ b/fs/dlm/Makefile @@ -1,6 +1,4 @@ obj-$(CONFIG_DLM) += dlm.o -obj-$(CONFIG_DLM_DEVICE) += dlm_device.o - dlm-y := ast.o \ config.o \ dir.o \ @@ -15,7 +13,7 @@ dlm-y := ast.o \ recover.o \ recoverd.o \ requestqueue.o \ + user.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 index 57bdf09b520..a211330cbc4 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -13,7 +13,7 @@ #include "dlm_internal.h" #include "lock.h" -#include "ast.h" +#include "user.h" #define WAKE_ASTS 0 @@ -34,6 +34,11 @@ void dlm_del_ast(struct dlm_lkb *lkb) void dlm_add_ast(struct dlm_lkb *lkb, int type) { + if (lkb->lkb_flags & DLM_IFL_USER) { + dlm_user_add_ast(lkb, type); + return; + } + spin_lock(&ast_queue_lock); if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { kref_get(&lkb->lkb_ref); diff --git a/fs/dlm/device.c b/fs/dlm/device.c deleted file mode 100644 index 825bbc0a09c..00000000000 --- a/fs/dlm/device.c +++ /dev/null @@ -1,1239 +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. -** -******************************************************************************* -******************************************************************************/ - -/* - * 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 mutex user_ls_lock; - -/* Flags in li_flags */ -#define LI_FLAG_COMPLETE 1 -#define LI_FLAG_FIRSTLOCK 2 -#define LI_FLAG_PERSISTENT 3 -#define LI_FLAG_ONLIST 4 - -/* flags in ls_flags*/ -#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 - -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 completion li_firstcomp; -}; - -/* 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; - - /* Lock infos are stored in here indexed by lock ID */ - struct idr lockinfo_idr; - rwlock_t lockinfo_lock; - - /* 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; -}; - -#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 - 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 user_ls *ls, struct lock_info *li) -{ - put_file_info(li->li_file); - - write_lock(&ls->lockinfo_lock); - idr_remove(&ls->lockinfo_idr, li->li_lksb.sb_lkid); - write_unlock(&ls->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(struct user_ls *ls, uint32_t lockid) -{ - struct lock_info *li; - - read_lock(&ls->lockinfo_lock); - li = idr_find(&ls->lockinfo_idr, lockid); - read_unlock(&ls->lockinfo_lock); - - return li; -} - -static int add_lockinfo(struct user_ls *ls, struct lock_info *li) -{ - int n; - int r; - int ret = -EINVAL; - - write_lock(&ls->lockinfo_lock); - - if (idr_find(&ls->lockinfo_idr, li->li_lksb.sb_lkid)) - goto out_up; - - ret = -ENOMEM; - r = idr_pre_get(&ls->lockinfo_idr, GFP_KERNEL); - if (!r) - goto out_up; - - r = idr_get_new_above(&ls->lockinfo_idr, li, li->li_lksb.sb_lkid, &n); - if (r) - goto out_up; - - if (n != li->li_lksb.sb_lkid) { - idr_remove(&ls->lockinfo_idr, n); - goto out_up; - } - - ret = 0; - - out_up: - write_unlock(&ls->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; - - mutex_lock(&user_ls_lock); - lsinfo = __find_lockspace(minor); - mutex_unlock(&user_ls_lock); - - return lsinfo; -} - -static void add_lockspace_to_list(struct user_ls *lsinfo) -{ - mutex_lock(&user_ls_lock); - list_add(&lsinfo->ls_list, &user_ls_list); - mutex_unlock(&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 = kzalloc(sizeof(struct user_ls), GFP_KERNEL); - if (!newls) - return -ENOMEM; - - newls->ls_miscinfo.name = kzalloc(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; - } - - idr_init(&newls->lockinfo_idr); - rwlock_init(&newls->lockinfo_lock); - - 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 mutex 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 = kzalloc(sizeof(struct ast_info), GFP_KERNEL); - if (!ast) - return; - - 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(FI_FLAG_OPEN, &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 */ - wait_for_completion(&li->li_firstcomp); - - spin_lock(&li->li_file->fi_li_lock); - list_del(&li->li_ownerqueue); - clear_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&li->li_file->fi_li_lock); - release_lockinfo(li->li_file->fi_ls, li); - return; - } - /* Free unlocks & queries */ - if (li->li_lksb.sb_status == -DLM_EUNLOCK || - li->li_cmd == DLM_USER_QUERY) { - release_lockinfo(li->li_file->fi_ls, 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 = kzalloc(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(FI_FLAG_OPEN, &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(FI_FLAG_OPEN, &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); - 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->li_file->fi_ls, 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->li_file->fi_ls, 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. - */ - mutex_lock(&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); - } - } - mutex_unlock(&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; - - mutex_lock(&user_ls_lock); - lsinfo = __find_lockspace(kparams->minor); - if (!lsinfo) { - mutex_unlock(&user_ls_lock); - return -EINVAL; - } - - if (kparams->flags & DLM_USER_LSFLG_FORCEFREE) - force = 3; - - status = unregister_lockspace(lsinfo, force); - mutex_unlock(&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; - 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); - 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 */ -#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 = struct_size; - - /* 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; - -#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, data, struct_size)) - 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 = kzalloc(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(fi->fi_ls, kparams->lkid); - - /* If this is a persistent lock we will have to create a - lockinfo again */ - if (!li && (kparams->flags & DLM_LKF_PERSISTENT)) { - li = allocate_lockinfo(fi, cmd, kparams); - if (!li) - return -ENOMEM; - - 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_completion(&li->li_firstcomp); - set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); - add_lockinfo(fi->fi_ls, 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; - - /* 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_completion(&li->li_firstcomp); - 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); - 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); - set_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&fi->fi_li_lock); - if (add_lockinfo(fi->fi_ls, li)) - printk(KERN_WARNING "Add lockinfo failed\n"); - - complete(&li->li_firstcomp); - } - - /* 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(fi->fi_ls, 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(fi->fi_ls, kparams->lkid); - if (!li) { - li = allocate_lockinfo(fi, cmd, kparams); - if (!li) - return -ENOMEM; - spin_lock(&fi->fi_li_lock); - list_add(&li->li_ownerqueue, &fi->fi_li_list); - set_bit(LI_FLAG_ONLIST, &li->li_flags); - spin_unlock(&fi->fi_li_lock); - } - - 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; - - /* Wait until dlm_lock() has completed */ - if (!test_bit(LI_FLAG_ONLIST, &li->li_flags)) { - wait_for_completion(&li->li_firstcomp); - } - - /* 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); - clear_bit(LI_FLAG_ONLIST, &li->li_flags); - 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; - -#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 */ - 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; - -#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); - - 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); - mutex_init(&user_ls_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/dlm_internal.h b/fs/dlm/dlm_internal.h index 149106f2b80..db080de2a7e 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ struct dlm_mhandle; #define log_error(ls, fmt, args...) \ printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args) +#define DLM_LOG_DEBUG #ifdef DLM_LOG_DEBUG #define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args) #else @@ -204,6 +206,9 @@ struct dlm_args { #define DLM_IFL_MSTCPY 0x00010000 #define DLM_IFL_RESEND 0x00020000 +#define DLM_IFL_DEAD 0x00040000 +#define DLM_IFL_USER 0x00000001 +#define DLM_IFL_ORPHAN 0x00000002 struct dlm_lkb { struct dlm_rsb *lkb_resource; /* the rsb */ @@ -231,6 +236,7 @@ struct dlm_lkb { 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 */ + struct list_head lkb_ownqueue; /* list of locks for a process */ char *lkb_lvbptr; struct dlm_lksb *lkb_lksb; /* caller's status block */ @@ -409,6 +415,7 @@ struct rcom_lock { struct dlm_ls { struct list_head ls_list; /* list of lockspaces */ + dlm_lockspace_t *ls_local_handle; uint32_t ls_global_id; /* global unique lockspace ID */ uint32_t ls_exflags; int ls_lvblen; @@ -444,6 +451,8 @@ struct dlm_ls { wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ int ls_uevent_result; + struct miscdevice ls_device; + /* recovery related */ struct timer_list ls_timer; @@ -461,6 +470,7 @@ struct dlm_ls { spinlock_t ls_recover_list_lock; int ls_recover_list_count; wait_queue_head_t ls_wait_general; + struct mutex ls_clear_proc_locks; struct list_head ls_root_list; /* root resources */ struct rw_semaphore ls_root_sem; /* protect root_list */ @@ -475,6 +485,40 @@ struct dlm_ls { #define LSFL_RCOM_READY 3 #define LSFL_UEVENT_WAIT 4 +/* much of this is just saving user space pointers associated with the + lock that we pass back to the user lib with an ast */ + +struct dlm_user_args { + struct dlm_user_proc *proc; /* each process that opens the lockspace + device has private data + (dlm_user_proc) on the struct file, + the process's locks point back to it*/ + struct dlm_lksb lksb; + int old_mode; + int update_user_lvb; + struct dlm_lksb __user *user_lksb; + void __user *castparam; + void __user *castaddr; + void __user *bastparam; + void __user *bastaddr; +}; + +#define DLM_PROC_FLAGS_CLOSING 1 +#define DLM_PROC_FLAGS_COMPAT 2 + +/* locks list is kept so we can remove all a process's locks when it + exits (or orphan those that are persistent) */ + +struct dlm_user_proc { + dlm_lockspace_t *lockspace; + unsigned long flags; /* DLM_PROC_FLAGS */ + struct list_head asts; + spinlock_t asts_spin; + struct list_head locks; + spinlock_t locks_spin; + wait_queue_head_t wait; +}; + static inline int dlm_locking_stopped(struct dlm_ls *ls) { return !test_bit(LSFL_RUNNING, &ls->ls_flags); diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 5f696390410..4e222f873b6 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -55,8 +55,9 @@ R: do_xxxx() L: receive_xxxx_reply() <- R: send_xxxx_reply() */ - +#include #include "dlm_internal.h" +#include #include "memory.h" #include "lowcomms.h" #include "requestqueue.h" @@ -69,6 +70,7 @@ #include "rcom.h" #include "recover.h" #include "lvb_table.h" +#include "user.h" #include "config.h" static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb); @@ -84,6 +86,8 @@ 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); +#define FAKE_USER_AST (void*)0xff00ff00 + /* * Lock compatibilty matrix - thanks Steve * UN = Unlocked state. Not really a state, used as a flag @@ -152,7 +156,7 @@ static const int __quecvt_compat_matrix[8][8] = { {0, 0, 0, 0, 0, 0, 0, 0} /* PD */ }; -static void dlm_print_lkb(struct dlm_lkb *lkb) +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", @@ -291,7 +295,7 @@ static int search_rsb_list(struct list_head *head, char *name, int len, if (len == r->res_length && !memcmp(name, r->res_name, len)) goto found; } - return -ENOENT; + return -EBADR; found: if (r->res_nodeid && (flags & R_MASTER)) @@ -376,7 +380,7 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen, if (!error) goto out; - if (error == -ENOENT && !(flags & R_CREATE)) + if (error == -EBADR && !(flags & R_CREATE)) goto out; /* the rsb was found but wasn't a master copy */ @@ -920,7 +924,7 @@ static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb, if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) return; - b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1]; + 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); @@ -963,6 +967,8 @@ 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_GRANTED: + break; case DLM_LKSTS_CONVERT: move_lkb(r, lkb, DLM_LKSTS_GRANTED); break; @@ -1727,6 +1733,11 @@ static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) return -DLM_EUNLOCK; } +/* FIXME: if revert_lock() finds that the lkb is granted, we should + skip the queue_cast(ECANCEL). It indicates that the request/convert + completed (and queued a normal ast) just before the cancel; we don't + want to clobber the sb_result for the normal ast with ECANCEL. */ + static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb) { revert_lock(r, lkb); @@ -2739,7 +2750,7 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) confirm_master(r, error); break; - case -ENOENT: + case -EBADR: case -ENOTBLK: /* find_rsb failed to find rsb or rsb wasn't master */ r->res_nodeid = -1; @@ -3545,3 +3556,284 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc) return 0; } +int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, + int mode, uint32_t flags, void *name, unsigned int namelen, + uint32_t parent_lkid) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + int error; + + lock_recovery(ls); + + error = create_lkb(ls, &lkb); + if (error) { + kfree(ua); + goto out; + } + + if (flags & DLM_LKF_VALBLK) { + ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL); + if (!ua->lksb.sb_lvbptr) { + kfree(ua); + __put_lkb(ls, lkb); + error = -ENOMEM; + goto out; + } + } + + /* After ua is attached to lkb it will be freed by free_lkb(). + When DLM_IFL_USER is set, the dlm knows that this is a userspace + lock and that lkb_astparam is the dlm_user_args structure. */ + + error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid, + FAKE_USER_AST, ua, FAKE_USER_AST, &args); + lkb->lkb_flags |= DLM_IFL_USER; + ua->old_mode = DLM_LOCK_IV; + + if (error) { + __put_lkb(ls, lkb); + goto out; + } + + error = request_lock(ls, lkb, name, namelen, &args); + + switch (error) { + case 0: + break; + case -EINPROGRESS: + error = 0; + break; + case -EAGAIN: + error = 0; + /* fall through */ + default: + __put_lkb(ls, lkb); + goto out; + } + + /* add this new lkb to the per-process list of locks */ + spin_lock(&ua->proc->locks_spin); + kref_get(&lkb->lkb_ref); + list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks); + spin_unlock(&ua->proc->locks_spin); + out: + unlock_recovery(ls); + return error; +} + +int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + int mode, uint32_t flags, uint32_t lkid, char *lvb_in) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + int error; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + /* user can change the params on its lock when it converts it, or + add an lvb that didn't exist before */ + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + + if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) { + ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL); + if (!ua->lksb.sb_lvbptr) { + error = -ENOMEM; + goto out_put; + } + } + if (lvb_in && ua->lksb.sb_lvbptr) + memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); + + ua->castparam = ua_tmp->castparam; + ua->castaddr = ua_tmp->castaddr; + ua->bastparam = ua_tmp->bastparam; + ua->bastaddr = ua_tmp->bastaddr; + ua->old_mode = lkb->lkb_grmode; + + error = set_lock_args(mode, &ua->lksb, flags, 0, 0, FAKE_USER_AST, ua, + FAKE_USER_AST, &args); + if (error) + goto out_put; + + error = convert_lock(ls, lkb, &args); + + if (error == -EINPROGRESS || error == -EAGAIN) + error = 0; + out_put: + dlm_put_lkb(lkb); + out: + unlock_recovery(ls); + kfree(ua_tmp); + return error; +} + +int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid, char *lvb_in) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + int error; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + + if (lvb_in && ua->lksb.sb_lvbptr) + memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); + ua->castparam = ua_tmp->castparam; + + error = set_unlock_args(flags, ua, &args); + if (error) + goto out_put; + + error = unlock_lock(ls, lkb, &args); + + if (error == -DLM_EUNLOCK) + error = 0; + if (error) + goto out_put; + + spin_lock(&ua->proc->locks_spin); + list_del(&lkb->lkb_ownqueue); + spin_unlock(&ua->proc->locks_spin); + + /* this removes the reference for the proc->locks list added by + dlm_user_request */ + unhold_lkb(lkb); + out_put: + dlm_put_lkb(lkb); + out: + unlock_recovery(ls); + return error; +} + +int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid) +{ + struct dlm_lkb *lkb; + struct dlm_args args; + struct dlm_user_args *ua; + int error; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + ua->castparam = ua_tmp->castparam; + + error = set_unlock_args(flags, ua, &args); + if (error) + goto out_put; + + error = cancel_lock(ls, lkb, &args); + + if (error == -DLM_ECANCEL) + error = 0; + if (error) + goto out_put; + + /* this lkb was removed from the WAITING queue */ + if (lkb->lkb_grmode == DLM_LOCK_IV) { + spin_lock(&ua->proc->locks_spin); + list_del(&lkb->lkb_ownqueue); + spin_unlock(&ua->proc->locks_spin); + unhold_lkb(lkb); + } + out_put: + dlm_put_lkb(lkb); + out: + unlock_recovery(ls); + return error; +} + +static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam; + + if (ua->lksb.sb_lvbptr) + kfree(ua->lksb.sb_lvbptr); + kfree(ua); + lkb->lkb_astparam = (long)NULL; + + /* TODO: propogate to master if needed */ + return 0; +} + +/* The force flag allows the unlock to go ahead even if the lkb isn't granted. + Regardless of what rsb queue the lock is on, it's removed and freed. */ + +static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam; + struct dlm_args args; + int error; + + /* FIXME: we need to handle the case where the lkb is in limbo + while the rsb is being looked up, currently we assert in + _unlock_lock/is_remote because rsb nodeid is -1. */ + + set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args); + + error = unlock_lock(ls, lkb, &args); + if (error == -DLM_EUNLOCK) + error = 0; + return error; +} + +/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which + 1) references lkb->ua which we free here and 2) adds lkbs to proc->asts, + which we clear here. */ + +/* proc CLOSING flag is set so no more device_reads should look at proc->asts + list, and no more device_writes should add lkb's to proc->locks list; so we + shouldn't need to take asts_spin or locks_spin here. this assumes that + device reads/writes/closes are serialized -- FIXME: we may need to serialize + them ourself. */ + +void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) +{ + struct dlm_lkb *lkb, *safe; + + lock_recovery(ls); + mutex_lock(&ls->ls_clear_proc_locks); + + list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) { + if (lkb->lkb_ast_type) { + list_del(&lkb->lkb_astqueue); + unhold_lkb(lkb); + } + + list_del(&lkb->lkb_ownqueue); + + if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) { + lkb->lkb_flags |= DLM_IFL_ORPHAN; + orphan_proc_lock(ls, lkb); + } else { + lkb->lkb_flags |= DLM_IFL_DEAD; + unlock_proc_lock(ls, lkb); + } + + /* this removes the reference for the proc->locks list + added by dlm_user_request, it may result in the lkb + being freed */ + + dlm_put_lkb(lkb); + } + mutex_unlock(&ls->ls_clear_proc_locks); + unlock_recovery(ls); +} diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 56cdc073b1f..8d2660f0ab1 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -14,6 +14,7 @@ #define __LOCK_DOT_H__ void dlm_print_rsb(struct dlm_rsb *r); +void dlm_print_lkb(struct dlm_lkb *lkb); 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, @@ -31,6 +32,16 @@ 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); +int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode, + uint32_t flags, void *name, unsigned int namelen, uint32_t parent_lkid); +int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + int mode, uint32_t flags, uint32_t lkid, char *lvb_in); +int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid, char *lvb_in); +int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, + uint32_t flags, uint32_t lkid); +void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc); + static inline int is_master(struct dlm_rsb *r) { return !r->res_nodeid; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 9ed4b70348f..3f6cb422ac4 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -270,12 +270,36 @@ struct dlm_ls *dlm_find_lockspace_global(uint32_t id) return ls; } -struct dlm_ls *dlm_find_lockspace_local(void *id) +struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace) { - struct dlm_ls *ls = id; + struct dlm_ls *ls; spin_lock(&lslist_lock); - ls->ls_count++; + list_for_each_entry(ls, &lslist, ls_list) { + if (ls->ls_local_handle == lockspace) { + ls->ls_count++; + goto out; + } + } + ls = NULL; + out: + spin_unlock(&lslist_lock); + return ls; +} + +struct dlm_ls *dlm_find_lockspace_device(int minor) +{ + struct dlm_ls *ls; + + spin_lock(&lslist_lock); + list_for_each_entry(ls, &lslist, ls_list) { + if (ls->ls_device.minor == minor) { + ls->ls_count++; + goto out; + } + } + ls = NULL; + out: spin_unlock(&lslist_lock); return ls; } @@ -436,6 +460,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, init_rwsem(&ls->ls_in_recovery); INIT_LIST_HEAD(&ls->ls_requestqueue); mutex_init(&ls->ls_requestqueue_mutex); + mutex_init(&ls->ls_clear_proc_locks); ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL); if (!ls->ls_recover_buf) @@ -444,6 +469,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, INIT_LIST_HEAD(&ls->ls_recover_list); spin_lock_init(&ls->ls_recover_list_lock); ls->ls_recover_list_count = 0; + ls->ls_local_handle = ls; init_waitqueue_head(&ls->ls_wait_general); INIT_LIST_HEAD(&ls->ls_root_list); init_rwsem(&ls->ls_root_sem); diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h index 17bd3ba863a..891eabbdd02 100644 --- a/fs/dlm/lockspace.h +++ b/fs/dlm/lockspace.h @@ -18,6 +18,7 @@ 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); +struct dlm_ls *dlm_find_lockspace_device(int minor); void dlm_put_lockspace(struct dlm_ls *ls); #endif /* __LOCKSPACE_DOT_H__ */ diff --git a/fs/dlm/main.c b/fs/dlm/main.c index 81bf4cb2203..a8da8dc36b2 100644 --- a/fs/dlm/main.c +++ b/fs/dlm/main.c @@ -14,6 +14,7 @@ #include "dlm_internal.h" #include "lockspace.h" #include "lock.h" +#include "user.h" #include "memory.h" #include "lowcomms.h" #include "config.h" @@ -50,10 +51,16 @@ static int __init init_dlm(void) if (error) goto out_debug; + error = dlm_user_init(); + if (error) + goto out_lowcomms; + printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); return 0; + out_lowcomms: + dlm_lowcomms_exit(); out_debug: dlm_unregister_debugfs(); out_config: @@ -68,6 +75,7 @@ static int __init init_dlm(void) static void __exit exit_dlm(void) { + dlm_user_exit(); dlm_lowcomms_exit(); dlm_config_exit(); dlm_memory_exit(); diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index f7cf4589fae..48dfc27861f 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -84,6 +84,15 @@ struct dlm_lkb *allocate_lkb(struct dlm_ls *ls) void free_lkb(struct dlm_lkb *lkb) { + if (lkb->lkb_flags & DLM_IFL_USER) { + struct dlm_user_args *ua; + ua = (struct dlm_user_args *)lkb->lkb_astparam; + if (ua) { + if (ua->lksb.sb_lvbptr) + kfree(ua->lksb.sb_lvbptr); + kfree(ua); + } + } kmem_cache_free(lkb_cache, lkb); } diff --git a/fs/dlm/user.c b/fs/dlm/user.c new file mode 100644 index 00000000000..1f05960a916 --- /dev/null +++ b/fs/dlm/user.c @@ -0,0 +1,769 @@ +/* + * Copyright (C) 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 +#include +#include +#include + +#include "dlm_internal.h" +#include "lockspace.h" +#include "lock.h" +#include "lvb_table.h" + +static const char *name_prefix="dlm"; +static struct miscdevice ctl_device; +static struct file_operations device_fops; + +#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 *kb, + struct dlm_write_request32 *kb32) +{ + kb->version[0] = kb32->version[0]; + kb->version[1] = kb32->version[1]; + kb->version[2] = kb32->version[2]; + + kb->cmd = kb32->cmd; + kb->is64bit = kb32->is64bit; + if (kb->cmd == DLM_USER_CREATE_LOCKSPACE || + kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { + kb->i.lspace.flags = kb32->i.lspace.flags; + kb->i.lspace.minor = kb32->i.lspace.minor; + strcpy(kb->i.lspace.name, kb32->i.lspace.name); + } else { + kb->i.lock.mode = kb32->i.lock.mode; + kb->i.lock.namelen = kb32->i.lock.namelen; + kb->i.lock.flags = kb32->i.lock.flags; + kb->i.lock.lkid = kb32->i.lock.lkid; + kb->i.lock.parent = kb32->i.lock.parent; + kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam; + kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr; + kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam; + kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; + kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; + memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); + memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen); + } +} + +static 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 + + +void dlm_user_add_ast(struct dlm_lkb *lkb, int type) +{ + struct dlm_ls *ls; + struct dlm_user_args *ua; + struct dlm_user_proc *proc; + + /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each + lkb before dealing with it. We need to check this + flag before taking ls_clear_proc_locks mutex because if + it's set, dlm_clear_proc_locks() holds the mutex. */ + + if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) { + /* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */ + return; + } + + ls = lkb->lkb_resource->res_ls; + mutex_lock(&ls->ls_clear_proc_locks); + + /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast + can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed + lkb->ua so we can't try to use it. */ + + if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) { + /* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */ + goto out; + } + + DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb);); + ua = (struct dlm_user_args *)lkb->lkb_astparam; + proc = ua->proc; + + if (type == AST_BAST && ua->bastaddr == NULL) + goto out; + + spin_lock(&proc->asts_spin); + if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { + kref_get(&lkb->lkb_ref); + list_add_tail(&lkb->lkb_astqueue, &proc->asts); + lkb->lkb_ast_type |= type; + wake_up_interruptible(&proc->wait); + } + + /* We want to copy the lvb to userspace when the completion + ast is read if the status is 0, the lock has an lvb and + lvb_ops says we should. We could probably have set_lvb_lock() + set update_user_lvb instead and not need old_mode */ + + if ((lkb->lkb_ast_type & AST_COMP) && + (lkb->lkb_lksb->sb_status == 0) && + lkb->lkb_lksb->sb_lvbptr && + dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1]) + ua->update_user_lvb = 1; + else + ua->update_user_lvb = 0; + + spin_unlock(&proc->asts_spin); + out: + mutex_unlock(&ls->ls_clear_proc_locks); +} + +static int device_user_lock(struct dlm_user_proc *proc, + struct dlm_lock_params *params) +{ + struct dlm_ls *ls; + struct dlm_user_args *ua; + int error = -ENOMEM; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + if (!params->castaddr || !params->lksb) { + error = -EINVAL; + goto out; + } + + ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL); + if (!ua) + goto out; + ua->proc = proc; + ua->user_lksb = params->lksb; + ua->castparam = params->castparam; + ua->castaddr = params->castaddr; + ua->bastparam = params->bastparam; + ua->bastaddr = params->bastaddr; + + if (params->flags & DLM_LKF_CONVERT) + error = dlm_user_convert(ls, ua, + params->mode, params->flags, + params->lkid, params->lvb); + else { + error = dlm_user_request(ls, ua, + params->mode, params->flags, + params->name, params->namelen, + params->parent); + if (!error) + error = ua->lksb.sb_lkid; + } + out: + dlm_put_lockspace(ls); + return error; +} + +static int device_user_unlock(struct dlm_user_proc *proc, + struct dlm_lock_params *params) +{ + struct dlm_ls *ls; + struct dlm_user_args *ua; + int error = -ENOMEM; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL); + if (!ua) + goto out; + ua->proc = proc; + ua->user_lksb = params->lksb; + ua->castparam = params->castparam; + ua->castaddr = params->castaddr; + + if (params->flags & DLM_LKF_CANCEL) + error = dlm_user_cancel(ls, ua, params->flags, params->lkid); + else + error = dlm_user_unlock(ls, ua, params->flags, params->lkid, + params->lvb); + out: + dlm_put_lockspace(ls); + return error; +} + +static int device_create_lockspace(struct dlm_lspace_params *params) +{ + dlm_lockspace_t *lockspace; + struct dlm_ls *ls; + int error, len; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + error = dlm_new_lockspace(params->name, strlen(params->name), + &lockspace, 0, DLM_USER_LVB_LEN); + if (error) + return error; + + ls = dlm_find_lockspace_local(lockspace); + if (!ls) + return -ENOENT; + + error = -ENOMEM; + len = strlen(params->name) + strlen(name_prefix) + 2; + ls->ls_device.name = kzalloc(len, GFP_KERNEL); + if (!ls->ls_device.name) + goto fail; + snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix, + params->name); + ls->ls_device.fops = &device_fops; + ls->ls_device.minor = MISC_DYNAMIC_MINOR; + + error = misc_register(&ls->ls_device); + if (error) { + kfree(ls->ls_device.name); + goto fail; + } + + error = ls->ls_device.minor; + dlm_put_lockspace(ls); + return error; + + fail: + dlm_put_lockspace(ls); + dlm_release_lockspace(lockspace, 0); + return error; +} + +static int device_remove_lockspace(struct dlm_lspace_params *params) +{ + dlm_lockspace_t *lockspace; + struct dlm_ls *ls; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ls = dlm_find_lockspace_device(params->minor); + if (!ls) + return -ENOENT; + + error = misc_deregister(&ls->ls_device); + if (error) { + dlm_put_lockspace(ls); + goto out; + } + kfree(ls->ls_device.name); + + lockspace = ls->ls_local_handle; + + /* dlm_release_lockspace waits for references to go to zero, + so all processes will need to close their device for the ls + before the release will procede */ + + dlm_put_lockspace(ls); + error = dlm_release_lockspace(lockspace, 0); +out: + return error; +} + +/* 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; +} + +/* + * device_write + * + * device_user_lock + * dlm_user_request -> request_lock + * dlm_user_convert -> convert_lock + * + * device_user_unlock + * dlm_user_unlock -> unlock_lock + * dlm_user_cancel -> cancel_lock + * + * device_create_lockspace + * dlm_new_lockspace + * + * device_remove_lockspace + * dlm_release_lockspace + */ + +/* a write to a lockspace device is a lock or unlock request, a write + to the control device is to create/remove a lockspace */ + +static ssize_t device_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dlm_user_proc *proc = file->private_data; + struct dlm_write_request *kbuf; + sigset_t tmpsig, allsigs; + int error; + +#ifdef CONFIG_COMPAT + if (count < sizeof(struct dlm_write_request32)) +#else + if (count < sizeof(struct dlm_write_request)) +#endif + return -EINVAL; + + kbuf = kmalloc(count, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + if (copy_from_user(kbuf, buf, count)) { + error = -EFAULT; + goto out_free; + } + + if (check_version(kbuf)) { + error = -EBADE; + goto out_free; + } + +#ifdef CONFIG_COMPAT + if (!kbuf->is64bit) { + struct dlm_write_request32 *k32buf; + k32buf = (struct dlm_write_request32 *)kbuf; + kbuf = kmalloc(count + (sizeof(struct dlm_write_request) - + sizeof(struct dlm_write_request32)), GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + if (proc) + set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); + compat_input(kbuf, k32buf); + kfree(k32buf); + } +#endif + + /* do we really need this? can a write happen after a close? */ + if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) && + test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) + return -EINVAL; + + sigfillset(&allsigs); + sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); + + error = -EINVAL; + + switch (kbuf->cmd) + { + case DLM_USER_LOCK: + if (!proc) { + log_print("no locking on control device"); + goto out_sig; + } + error = device_user_lock(proc, &kbuf->i.lock); + break; + + case DLM_USER_UNLOCK: + if (!proc) { + log_print("no locking on control device"); + goto out_sig; + } + error = device_user_unlock(proc, &kbuf->i.lock); + break; + + case DLM_USER_CREATE_LOCKSPACE: + if (proc) { + log_print("create/remove only on control device"); + goto out_sig; + } + error = device_create_lockspace(&kbuf->i.lspace); + break; + + case DLM_USER_REMOVE_LOCKSPACE: + if (proc) { + log_print("create/remove only on control device"); + goto out_sig; + } + error = device_remove_lockspace(&kbuf->i.lspace); + break; + + default: + log_print("Unknown command passed to DLM device : %d\n", + kbuf->cmd); + } + + out_sig: + sigprocmask(SIG_SETMASK, &tmpsig, NULL); + recalc_sigpending(); + out_free: + kfree(kbuf); + return error; +} + +/* Every process that opens the lockspace device has its own "proc" structure + hanging off the open file that's used to keep track of locks owned by the + process and asts that need to be delivered to the process. */ + +static int device_open(struct inode *inode, struct file *file) +{ + struct dlm_user_proc *proc; + struct dlm_ls *ls; + + ls = dlm_find_lockspace_device(iminor(inode)); + if (!ls) + return -ENOENT; + + proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); + if (!proc) { + dlm_put_lockspace(ls); + return -ENOMEM; + } + + proc->lockspace = ls->ls_local_handle; + INIT_LIST_HEAD(&proc->asts); + INIT_LIST_HEAD(&proc->locks); + spin_lock_init(&proc->asts_spin); + spin_lock_init(&proc->locks_spin); + init_waitqueue_head(&proc->wait); + file->private_data = proc; + + return 0; +} + +static int device_close(struct inode *inode, struct file *file) +{ + struct dlm_user_proc *proc = file->private_data; + struct dlm_ls *ls; + sigset_t tmpsig, allsigs; + + ls = dlm_find_lockspace_local(proc->lockspace); + if (!ls) + return -ENOENT; + + sigfillset(&allsigs); + sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); + + set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags); + + dlm_clear_proc_locks(ls, proc); + + /* at this point no more lkb's should exist for this lockspace, + so there's no chance of dlm_user_add_ast() being called and + looking for lkb->ua->proc */ + + kfree(proc); + file->private_data = NULL; + + dlm_put_lockspace(ls); + dlm_put_lockspace(ls); /* for the find in device_open() */ + + /* FIXME: AUTOFREE: if this ls is no longer used do + device_remove_lockspace() */ + + sigprocmask(SIG_SETMASK, &tmpsig, NULL); + recalc_sigpending(); + + return 0; +} + +static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, + int bmode, char __user *buf, size_t count) +{ +#ifdef CONFIG_COMPAT + struct dlm_lock_result32 result32; +#endif + struct dlm_lock_result result; + void *resultptr; + int error=0; + int len; + int struct_len; + + memset(&result, 0, sizeof(struct dlm_lock_result)); + memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb)); + result.user_lksb = ua->user_lksb; + + /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated + in a conversion unless the conversion is successful. See code + in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though, + notes that a new blocking AST address and parameter are set even if + the conversion fails, so maybe we should just do that. */ + + if (type == AST_BAST) { + result.user_astaddr = ua->bastaddr; + result.user_astparam = ua->bastparam; + result.bast_mode = bmode; + } else { + result.user_astaddr = ua->castaddr; + result.user_astparam = ua->castparam; + } + +#ifdef CONFIG_COMPAT + if (compat) + len = sizeof(struct dlm_lock_result32); + else +#endif + len = sizeof(struct dlm_lock_result); + struct_len = len; + + /* copy lvb to userspace if there is one, it's been updated, and + the user buffer has space for it */ + + if (ua->update_user_lvb && ua->lksb.sb_lvbptr && + count >= len + DLM_USER_LVB_LEN) { + if (copy_to_user(buf+len, ua->lksb.sb_lvbptr, + DLM_USER_LVB_LEN)) { + error = -EFAULT; + goto out; + } + + result.lvb_offset = len; + len += DLM_USER_LVB_LEN; + } + + result.length = len; + resultptr = &result; +#ifdef CONFIG_COMPAT + if (compat) { + compat_output(&result, &result32); + resultptr = &result32; + } +#endif + + if (copy_to_user(buf, resultptr, struct_len)) + error = -EFAULT; + else + error = len; + out: + return error; +} + +/* a read returns a single ast described in a struct dlm_lock_result */ + +static ssize_t device_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct dlm_user_proc *proc = file->private_data; + struct dlm_lkb *lkb; + struct dlm_user_args *ua; + DECLARE_WAITQUEUE(wait, current); + int error, type=0, bmode=0, removed = 0; + +#ifdef CONFIG_COMPAT + if (count < sizeof(struct dlm_lock_result32)) +#else + if (count < sizeof(struct dlm_lock_result)) +#endif + return -EINVAL; + + /* do we really need this? can a read happen after a close? */ + if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) + return -EINVAL; + + spin_lock(&proc->asts_spin); + if (list_empty(&proc->asts)) { + if (file->f_flags & O_NONBLOCK) { + spin_unlock(&proc->asts_spin); + return -EAGAIN; + } + + add_wait_queue(&proc->wait, &wait); + + repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&proc->asts) && !signal_pending(current)) { + spin_unlock(&proc->asts_spin); + schedule(); + spin_lock(&proc->asts_spin); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&proc->wait, &wait); + + if (signal_pending(current)) { + spin_unlock(&proc->asts_spin); + return -ERESTARTSYS; + } + } + + if (list_empty(&proc->asts)) { + spin_unlock(&proc->asts_spin); + return -EAGAIN; + } + + /* there may be both completion and blocking asts to return for + the lkb, don't remove lkb from asts list unless no asts remain */ + + lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); + + if (lkb->lkb_ast_type & AST_COMP) { + lkb->lkb_ast_type &= ~AST_COMP; + type = AST_COMP; + } else if (lkb->lkb_ast_type & AST_BAST) { + lkb->lkb_ast_type &= ~AST_BAST; + type = AST_BAST; + bmode = lkb->lkb_bastmode; + } + + if (!lkb->lkb_ast_type) { + list_del(&lkb->lkb_astqueue); + removed = 1; + } + spin_unlock(&proc->asts_spin); + + ua = (struct dlm_user_args *)lkb->lkb_astparam; + error = copy_result_to_user(ua, + test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), + type, bmode, buf, count); + + /* removes reference for the proc->asts lists added by + dlm_user_add_ast() and may result in the lkb being freed */ + if (removed) + dlm_put_lkb(lkb); + + return error; +} + +static unsigned int device_poll(struct file *file, poll_table *wait) +{ + struct dlm_user_proc *proc = file->private_data; + + poll_wait(file, &proc->wait, wait); + + spin_lock(&proc->asts_spin); + if (!list_empty(&proc->asts)) { + spin_unlock(&proc->asts_spin); + return POLLIN | POLLRDNORM; + } + spin_unlock(&proc->asts_spin); + return 0; +} + +static int ctl_device_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int ctl_device_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations device_fops = { + .open = device_open, + .release = device_close, + .read = device_read, + .write = device_write, + .poll = device_poll, + .owner = THIS_MODULE, +}; + +static struct file_operations ctl_device_fops = { + .open = ctl_device_open, + .release = ctl_device_close, + .write = device_write, + .owner = THIS_MODULE, +}; + +int dlm_user_init(void) +{ + int error; + + ctl_device.name = "dlm-control"; + ctl_device.fops = &ctl_device_fops; + ctl_device.minor = MISC_DYNAMIC_MINOR; + + error = misc_register(&ctl_device); + if (error) + log_print("misc_register failed for control device"); + + return error; +} + +void dlm_user_exit(void) +{ + misc_deregister(&ctl_device); +} + diff --git a/fs/dlm/user.h b/fs/dlm/user.h new file mode 100644 index 00000000000..d38e9f3e415 --- /dev/null +++ b/fs/dlm/user.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 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 __USER_DOT_H__ +#define __USER_DOT_H__ + +void dlm_user_add_ast(struct dlm_lkb *lkb, int type); +int dlm_user_init(void); +void dlm_user_exit(void); + +#endif -- GitLab From 634ee0b9f458f3530b9c0ea7e6951dd03db7d678 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 17 Jul 2006 09:32:37 -0400 Subject: [PATCH 0164/1619] [GFS2] Fix use after free bug in dir.c Fix a use after free bug in dir.c spotted by Kevin Anderson. Cc: Kevin Anderson Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index e96b5322c84..f62223b9e53 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1763,9 +1763,8 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (error) goto out; leaf = (struct gfs2_leaf *)bh->b_data; - brelse(bh); - len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); + brelse(bh); error = lc(dip, index, len, leaf_no, data); if (error) @@ -1781,7 +1780,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) error = -EIO; } - out: +out: kfree(lp); return error; -- GitLab From e0f2bf780a970f7aae9263db2e14149132671cf2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 17 Jul 2006 09:36:28 -0400 Subject: [PATCH 0165/1619] [GFS2] Fix endian conversion bug Fix an endian coversion bug in log.c spotted by Kevin Anderson. Cc: Kevin Anderson Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 1596e9436c4..60fdc94ccc8 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -386,10 +386,10 @@ static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); lh->lh_header.mh_format = cpu_to_be32(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); + lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); + lh->lh_flags = cpu_to_be32(flags); + lh->lh_tail = cpu_to_be32(tail); + lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); lh->lh_hash = cpu_to_be32(hash); -- GitLab From 3b4a0a74949cf4f87f7ca84cc0457eb5687b2923 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 15 Jul 2006 02:36:31 +0200 Subject: [PATCH 0166/1619] [DLM] [RFC: -mm patch] fs/dlm/lock.c: unexport dlm_lvb_operations On Thu, Jul 13, 2006 at 10:48:00PM -0700, Andrew Morton wrote: >... > Changes since 2.6.18-rc1-mm1: >... > git-gfs2.patch >... > git trees. >... This patch removes the unused EXPORT_SYMBOL_GPL(dlm_lvb_operations). Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 4e222f873b6..82e1ac25184 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -128,7 +128,6 @@ const int dlm_lvb_operations[8][8] = { { -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] -- GitLab From 34e22bed19013c77f942083e25cfc7adf6c71a8f Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 18 Jul 2006 11:24:04 -0500 Subject: [PATCH 0167/1619] [DLM] fix leaking user locks User NOQUEUE lock requests to a remote node that failed with -EAGAIN were never being removed from a process's list of locks. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 7 ++++--- fs/dlm/user.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 82e1ac25184..22744321816 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -526,6 +526,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) lkb->lkb_nodeid = -1; lkb->lkb_grmode = DLM_LOCK_IV; kref_init(&lkb->lkb_ref); + INIT_LIST_HEAD(&lkb->lkb_ownqueue); get_random_bytes(&bucket, sizeof(bucket)); bucket &= (ls->ls_lkbtbl_size - 1); @@ -3705,7 +3706,7 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, goto out_put; spin_lock(&ua->proc->locks_spin); - list_del(&lkb->lkb_ownqueue); + list_del_init(&lkb->lkb_ownqueue); spin_unlock(&ua->proc->locks_spin); /* this removes the reference for the proc->locks list added by @@ -3749,7 +3750,7 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, /* this lkb was removed from the WAITING queue */ if (lkb->lkb_grmode == DLM_LOCK_IV) { spin_lock(&ua->proc->locks_spin); - list_del(&lkb->lkb_ownqueue); + list_del_init(&lkb->lkb_ownqueue); spin_unlock(&ua->proc->locks_spin); unhold_lkb(lkb); } @@ -3817,7 +3818,7 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) unhold_lkb(lkb); } - list_del(&lkb->lkb_ownqueue); + list_del_init(&lkb->lkb_ownqueue); if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) { lkb->lkb_flags |= DLM_IFL_ORPHAN; diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 1f05960a916..fd19caf9af9 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -133,6 +133,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) struct dlm_ls *ls; struct dlm_user_args *ua; struct dlm_user_proc *proc; + int remove_ownqueue = 0; /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each lkb before dealing with it. We need to check this @@ -171,6 +172,14 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) wake_up_interruptible(&proc->wait); } + /* noqueue requests that fail may need to be removed from the + proc's locks list, there should be a better way of detecting + this situation than checking all these things... */ + + if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV && + ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue)) + remove_ownqueue = 1; + /* We want to copy the lvb to userspace when the completion ast is read if the status is 0, the lock has an lvb and lvb_ops says we should. We could probably have set_lvb_lock() @@ -185,6 +194,13 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) ua->update_user_lvb = 0; spin_unlock(&proc->asts_spin); + + if (remove_ownqueue) { + spin_lock(&ua->proc->locks_spin); + list_del_init(&lkb->lkb_ownqueue); + spin_unlock(&ua->proc->locks_spin); + dlm_put_lkb(lkb); + } out: mutex_unlock(&ls->ls_clear_proc_locks); } -- GitLab From 36098198184b0644537f4b2257d861e9bdf124bd Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 20 Jul 2006 08:35:39 -0500 Subject: [PATCH 0168/1619] [DLM] fix whitespace damage My previous dlm patch added trailing whitespace damage, fix that. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/user.c b/fs/dlm/user.c index fd19caf9af9..494d00ac014 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -175,7 +175,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) /* noqueue requests that fail may need to be removed from the proc's locks list, there should be a better way of detecting this situation than checking all these things... */ - + if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV && ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue)) remove_ownqueue = 1; -- GitLab From c5921fd02e6c720938141a45f1f9dbd71b17fff2 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 20 Jul 2006 09:06:34 -0500 Subject: [PATCH 0169/1619] [GFS2] fix typo in locking/dlm Typo causes the error value from the wrong lock to be checked. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index e74f1215672..f769eac1a34 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -430,7 +430,7 @@ static int hold_null_lock(struct gdlm_lock *lp) init_completion(&lpn->ast_wait); gdlm_do_lock(lpn); wait_for_completion(&lpn->ast_wait); - error = lp->lksb.sb_status; + error = lpn->lksb.sb_status; if (error) { printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n", error); -- GitLab From 52f341cf75d2da84811127582616984eb0602360 Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Fri, 21 Jul 2006 02:03:21 -0400 Subject: [PATCH 0170/1619] [GFS2] gfs2_set_flags double locking patch traced the "umount hang due to spurious glock" issue that I was having with gfs2meta. It's in the do_gfs2_set_flags function, which does a gfs2_holder_init as well as a gfs2_glock_nq_init (increases ref count by 2 instead of 1). Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 26f1d3249b0..6764ca69bc5 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -608,12 +608,9 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) int error; u32 new_flags, flags; - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); - if (error) { - gfs2_holder_uninit(&gh); + if (error) return error; - } flags = ip->i_di.di_flags; new_flags = (flags & ~mask) | (reqflags & mask); -- GitLab From a9e5f4d0780ec9cda7a70b08294d7718431b62a1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 25 Jul 2006 17:24:12 -0400 Subject: [PATCH 0171/1619] [GFS2] Alter direct I/O path As per comments received, alter the GFS2 direct I/O path so that it uses the standard read functions "out of the box". Needs a small change to one of the VFS functions. This reduces the size of the code quite a lot and also removes the need for one new export. Some more work remains to be done, but this is the bones of the thing. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 54 ++++---------- fs/gfs2/ops_file.c | 170 +----------------------------------------- mm/filemap.c | 4 +- 3 files changed, 21 insertions(+), 207 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 031270ad55e..d33f6aa7973 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -589,8 +589,9 @@ static void gfs2_invalidatepage(struct page *page, unsigned long offset) return; } -static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +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; @@ -598,8 +599,10 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, struct gfs2_holder gh; int rv; + if (rw == READ) + mutex_lock(&inode->i_mutex); /* - * Shared lock, even though its write, since we do no allocation + * Shared lock, even if its a write, since we do no allocation * on this path. All we need change is atime. */ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); @@ -607,6 +610,9 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, if (rv) goto out; + if (offset > i_size_read(inode)) + goto out; + /* * Should we return an error here? I can't see that O_DIRECT for * a journaled file makes any sense. For now we'll silently fall @@ -619,47 +625,19 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, if (gfs2_is_stuffed(ip)) goto out; - rv = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, - iov, offset, nr_segs, gfs2_get_block, - NULL, DIO_OWN_LOCKING); + rv = blockdev_direct_IO_own_locking(rw, iocb, inode, + inode->i_sb->s_bdev, + iov, offset, nr_segs, + gfs2_get_block, NULL); out: gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); + if (rw == READ) + mutex_unlock(&inode->i_mutex); return rv; } -/** - * gfs2_direct_IO - * - * This is called with a shared lock already held for the read path. - * Currently, no locks are held when the write path is called. - */ -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 = GFS2_I(inode); - struct gfs2_sbd *sdp = GFS2_SB(inode); - int ret; - - if (rw == WRITE) - return gfs2_direct_IO_write(iocb, iov, offset, nr_segs); - - if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) || - gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) - return -EINVAL; - - mutex_lock(&inode->i_mutex); - ret = __blockdev_direct_IO(READ, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, gfs2_get_block, NULL, - DIO_OWN_LOCKING); - mutex_unlock(&inode->i_mutex); - return ret; -} - /** * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. * @bh: the buffer we're stuck on @@ -765,7 +743,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) } while (bh != head); - out: +out: return try_to_free_buffers(page); } diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 6764ca69bc5..d13e04e8a96 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -148,170 +148,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) return error; } - -static ssize_t gfs2_direct_IO_read(struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - ssize_t retval; - - retval = filemap_write_and_wait(mapping); - if (retval == 0) { - retval = mapping->a_ops->direct_IO(READ, iocb, iov, offset, - nr_segs); - } - return retval; -} - -/** - * __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 __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 = GFS2_I(filp->f_mapping->host); - struct gfs2_holder gh; - 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, 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 (gfs2_is_stuffed(ip)) { - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - goto fallback_to_normal; - } - 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; - } - file_accessed(filp); - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - goto out; - } - -fallback_to_normal: - 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; -} - -/** - * 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 *filp, char __user *buf, size_t size, - loff_t *offset) -{ - struct iovec local_iov = { .iov_base = buf, .iov_len = size }; - struct kiocb kiocb; - ssize_t ret; - - 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; -} - -static ssize_t gfs2_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 = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, - size_t count, loff_t pos) -{ - struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - - BUG_ON(iocb->ki_pos != pos); - return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); -} - - /** * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() * @opaque: opaque data used by the function @@ -949,9 +785,9 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, - .read = gfs2_read, - .readv = gfs2_file_readv, - .aio_read = gfs2_file_aio_read, + .read = generic_file_read, + .readv = generic_file_readv, + .aio_read = generic_file_aio_read, .write = generic_file_write, .writev = generic_file_writev, .aio_write = generic_file_aio_write, diff --git a/mm/filemap.c b/mm/filemap.c index b9c91ab7f0f..a92d690b3ae 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1122,7 +1122,6 @@ success: desc->arg.buf += size; return size; } -EXPORT_SYMBOL_GPL(file_read_actor); /** * __generic_file_aio_read - generic filesystem read routine @@ -1184,7 +1183,8 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, *ppos = pos + retval; } file_accessed(filp); - goto out; + if (retval != 0) + goto out; } retval = 0; -- GitLab From 5de6319b1839300ba6b461ed19531cdab90db9fc Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Jul 2006 13:44:31 -0500 Subject: [PATCH 0172/1619] [DLM] more info through debugfs Display more information from debugfs, particularly locks waiting for a master lookup or operations waiting for a remote reply. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 132 +++++++++++++++++++++++++++++++++++------- fs/dlm/dlm_internal.h | 3 +- fs/dlm/lockspace.c | 3 +- 3 files changed, 114 insertions(+), 24 deletions(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 49deca845db..5faa747c7ca 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -18,6 +18,9 @@ #include "dlm_internal.h" +#define DLM_DEBUG_BUF_LEN 4096 +static char debug_buf[DLM_DEBUG_BUF_LEN]; +static struct mutex debug_buf_lock; static struct dentry *dlm_root; @@ -28,6 +31,10 @@ struct rsb_iter { struct dlm_rsb *rsb; }; +/* + * dump all rsb's in the lockspace hash table + */ + static char *print_lockmode(int mode) { switch (mode) { @@ -76,7 +83,7 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, static int print_resource(struct dlm_rsb *res, struct seq_file *s) { struct dlm_lkb *lkb; - int i, lvblen = res->res_ls->ls_lvblen; + int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); for (i = 0; i < res->res_length; i++) { @@ -110,6 +117,15 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) seq_printf(s, "\n"); } + root_list = !list_empty(&res->res_root_list); + recover_list = !list_empty(&res->res_recover_list); + + if (root_list || recover_list) { + seq_printf(s, "Recovery: root %d recover %d flags %lx " + "count %d\n", root_list, recover_list, + res->flags, res->res_recover_locks_count); + } + /* Print the locks attached to this resource */ seq_printf(s, "Granted Queue\n"); list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) @@ -123,6 +139,18 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) print_lock(s, lkb, res); + if (list_empty(&res->res_lookup)) + goto out; + + seq_printf(s, "Lookup Queue\n"); + list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) { + seq_printf(s, "%08x %s", lkb->lkb_id, + print_lockmode(lkb->lkb_rqmode)); + if (lkb->lkb_wait_type) + seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); + seq_printf(s, "\n"); + } + out: return 0; } @@ -190,7 +218,7 @@ static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) return ri; } -static void *seq_start(struct seq_file *file, loff_t *pos) +static void *rsb_seq_start(struct seq_file *file, loff_t *pos) { struct rsb_iter *ri; loff_t n = *pos; @@ -209,7 +237,7 @@ static void *seq_start(struct seq_file *file, loff_t *pos) return ri; } -static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) +static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) { struct rsb_iter *ri = iter_ptr; @@ -223,12 +251,12 @@ static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) return ri; } -static void seq_stop(struct seq_file *file, void *iter_ptr) +static void rsb_seq_stop(struct seq_file *file, void *iter_ptr) { /* nothing for now */ } -static int seq_show(struct seq_file *file, void *iter_ptr) +static int rsb_seq_show(struct seq_file *file, void *iter_ptr) { struct rsb_iter *ri = iter_ptr; @@ -237,19 +265,19 @@ static int seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static struct seq_operations dlm_seq_ops = { - .start = seq_start, - .next = seq_next, - .stop = seq_stop, - .show = seq_show, +static struct seq_operations rsb_seq_ops = { + .start = rsb_seq_start, + .next = rsb_seq_next, + .stop = rsb_seq_stop, + .show = rsb_seq_show, }; -static int do_open(struct inode *inode, struct file *file) +static int rsb_open(struct inode *inode, struct file *file) { struct seq_file *seq; int ret; - ret = seq_open(file, &dlm_seq_ops); + ret = rsb_seq_open(file, &rsb_seq_ops); if (ret) return ret; @@ -259,32 +287,92 @@ static int do_open(struct inode *inode, struct file *file) return 0; } -static struct file_operations dlm_fops = { +static struct file_operations rsb_fops = { .owner = THIS_MODULE, - .open = do_open, + .open = rsb_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release }; +/* + * dump lkb's on the ls_waiters list + */ + +static int waiters_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t waiters_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct dlm_ls *ls = file->private_data; + struct dlm_lkb *lkb; + size_t len = DLM_DEBUG_BUF_LEN, pos = 0, rv; + + mutex_lock(&debug_buf_lock); + mutex_lock(&ls->ls_waiters_mutex); + memset(debug_buf, 0, sizeof(debug_buf)); + + list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { + pos += snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n", + lkb->lkb_id, lkb->lkb_wait_type, + lkb->lkb_nodeid, lkb->lkb_resource->res_name); + } + mutex_unlock(&ls->ls_waiters_mutex); + + rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos); + mutex_unlock(&debug_buf_lock); + return rv; +} + +static struct file_operations waiters_fops = { + .owner = THIS_MODULE, + .open = waiters_open, + .read = waiters_read +}; + 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; + char name[DLM_LOCKSPACE_LEN+8]; + + ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, + S_IFREG | S_IRUGO, + dlm_root, + ls, + &rsb_fops); + if (!ls->ls_rsb_debug_dentry) + return -ENOMEM; + + memset(name, 0, sizeof(name)); + snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); + + ls->ls_debug_waiters_dentry = debugfs_create_file(name, + S_IFREG | S_IRUGO, + dlm_root, + ls, + &waiters_fops); + if (!ls->ls_debug_waiters_dentry) { + debugfs_remove(ls->ls_debug_rsb_dentry); + return -ENOMEM; + } + + return 0; } void dlm_delete_debug_file(struct dlm_ls *ls) { - if (ls->ls_debug_dentry) - debugfs_remove(ls->ls_debug_dentry); + if (ls->ls_debug_rsb_dentry) + debugfs_remove(ls->ls_debug_rsb_dentry); + if (ls->ls_debug_waiters_dentry) + debugfs_remove(ls->ls_debug_waiters_dentry); } int dlm_register_debugfs(void) { + mutex_init(&debug_buf_lock); dlm_root = debugfs_create_dir("dlm", NULL); return dlm_root ? 0 : -ENOMEM; } diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index db080de2a7e..7c3c2d27c01 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -446,7 +446,8 @@ struct dlm_ls { 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 */ + struct dentry *ls_debug_rsb_dentry; /* debugfs */ + struct dentry *ls_debug_waiters_dentry; /* debugfs */ wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ int ls_uevent_result; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 3f6cb422ac4..31ed0fe16a3 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -446,7 +446,8 @@ static int new_lockspace(char *name, int namelen, void **lockspace, memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb)); ls->ls_stub_rsb.res_ls = ls; - ls->ls_debug_dentry = NULL; + ls->ls_debug_rsb_dentry = NULL; + ls->ls_debug_waiters_dentry = NULL; init_waitqueue_head(&ls->ls_uevent_wait); ls->ls_uevent_result = 0; -- GitLab From f7da790d743d2f0b4f39e4fa442079b3b54f3bef Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Jul 2006 13:53:33 -0500 Subject: [PATCH 0173/1619] [DLM] set purged flag on rsbs If a node becomes the new master of an rsb during recovery, the LOCKS_PURGED flag needs to be set on it so that any waiting/converting locks will try to be granted. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/recover.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index 34876f60f29..1a86dfc8034 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -305,7 +305,8 @@ static void set_master_lkbs(struct dlm_rsb *r) /* * 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. + * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which + * rsb's to consider. */ static void set_new_master(struct dlm_rsb *r, int nodeid) @@ -681,6 +682,16 @@ static void recover_conversion(struct dlm_rsb *r) } } +/* We've become the new master for this rsb and waiting/converting locks may + need to be granted in dlm_grant_after_purge() due to locks that may have + existed from a removed node. */ + +static void set_locks_purged(struct dlm_rsb *r) +{ + if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue)) + rsb_set_flag(r, RSB_LOCKS_PURGED); +} + void dlm_recover_rsbs(struct dlm_ls *ls) { struct dlm_rsb *r; @@ -694,10 +705,13 @@ void dlm_recover_rsbs(struct dlm_ls *ls) if (is_master(r)) { if (rsb_flag(r, RSB_RECOVER_CONVERT)) recover_conversion(r); + if (rsb_flag(r, RSB_NEW_MASTER2)) + set_locks_purged(r); recover_lvb(r); count++; } rsb_clear_flag(r, RSB_RECOVER_CONVERT); + rsb_clear_flag(r, RSB_NEW_MASTER2); unlock_rsb(r); } up_read(&ls->ls_root_sem); -- GitLab From 2b4e926aab7c854a536beee6ba8b9a78a9e00316 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Jul 2006 13:59:48 -0500 Subject: [PATCH 0174/1619] [DLM] fix loop in grant_after_purge The loop in grant_after_purge is intended to find all rsb's in each hash bucket that have the LOCKS_PURGED flag set. The loop was quitting the current bucket after finding just one rsb instead of going until there are no more. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 22744321816..eaad28e51ec 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3366,12 +3366,16 @@ static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket) void dlm_grant_after_purge(struct dlm_ls *ls) { struct dlm_rsb *r; - int i; + int bucket = 0; - for (i = 0; i < ls->ls_rsbtbl_size; i++) { - r = find_purged_rsb(ls, i); - if (!r) + while (1) { + r = find_purged_rsb(ls, bucket); + if (!r) { + if (bucket == ls->ls_rsbtbl_size - 1) + break; + bucket++; continue; + } lock_rsb(r); if (is_master(r)) { grant_pending_locks(r); @@ -3379,6 +3383,7 @@ void dlm_grant_after_purge(struct dlm_ls *ls) } unlock_rsb(r); put_rsb(r); + schedule(); } } -- GitLab From 81456807a33c2122e2f1f92acfbaaa77b3d06c3c Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Jul 2006 14:05:09 -0500 Subject: [PATCH 0175/1619] [DLM] schedule during long loop through locks The loop through all waiting locks in recover_waiters can potentially be long, so we should schedule explicitly. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index eaad28e51ec..7d38f914c5b 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3193,6 +3193,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) log_error(ls, "invalid lkb wait_type %d", lkb->lkb_wait_type); } + schedule(); } mutex_unlock(&ls->ls_waiters_mutex); } -- GitLab From f25ef0c1b4e032b2641857ac4cff3315c6eb90e3 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 26 Jul 2006 10:51:20 -0400 Subject: [PATCH 0176/1619] [GFS2] Tidy gfs2_unstuffer_page Tidy up gfs2_unstuffer_page by: a) Moving it into bmap.c b) Making it static c) Calling it directly from gfs2_unstuff_dinode d) Updating all callers of gfs2_unstuff_dinode due to one less required argument. It doesn't change the behaviour at all. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 67 +++++++++++++++++++++++++++++++++++++++---- fs/gfs2/bmap.h | 7 +---- fs/gfs2/dir.c | 2 +- fs/gfs2/ops_address.c | 3 +- fs/gfs2/ops_vm.c | 2 +- fs/gfs2/page.c | 60 -------------------------------------- fs/gfs2/page.h | 2 -- 7 files changed, 66 insertions(+), 77 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 98fa07c2b71..72b19c5d780 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -47,6 +47,65 @@ struct strip_mine { unsigned int sm_height; }; +/** + * 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 + */ + +static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, + uint64_t block, struct page *page) +{ + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct inode *inode = &ip->i_inode; + 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_is_jdata(ip)) + gfs2_trans_add_bh(ip->i_gl, bh, 0); + mark_buffer_dirty(bh); + + if (release) { + unlock_page(page); + page_cache_release(page); + } + + return 0; +} + /** * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big * @ip: The GFS2 inode to unstuff @@ -59,8 +118,7 @@ struct strip_mine { * Returns: errno */ -int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, - void *private) +int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) { struct buffer_head *bh, *dibh; uint64_t block = 0; @@ -90,7 +148,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, } else { block = gfs2_alloc_data(ip); - error = unstuffer(ip, dibh, block, private); + error = gfs2_unstuffer_page(ip, dibh, block, page); if (error) goto out_brelse; } @@ -786,8 +844,7 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) 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); + error = gfs2_unstuff_dinode(ip, NULL); if (error) goto out_end_trans; } diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 06ccb2d808a..1a265412f7e 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -10,12 +10,7 @@ #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_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, - void *private); - +int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f62223b9e53..563b99e419b 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -173,7 +173,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, return -EINVAL; if (gfs2_is_stuffed(ip)) { - error = gfs2_unstuff_dinode(ip, NULL, NULL); + error = gfs2_unstuff_dinode(ip, NULL); if (error) return error; } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index d33f6aa7973..93e00a8af8c 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -395,8 +395,7 @@ static int gfs2_prepare_write(struct file *file, struct page *page, 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); + error = gfs2_unstuff_dinode(ip, page); if (error == 0) goto prepare_write; } else if (!PageUptodate(page)) diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 08709f19ea9..910722d4c48 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -104,7 +104,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) goto out_ipres; if (gfs2_is_stuffed(ip)) { - error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, NULL); + error = gfs2_unstuff_dinode(ip, NULL); if (error) goto out_trans; } diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index b93caf294b9..0d6befed1ae 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -113,66 +113,6 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags) } -/** - * 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 = GFS2_SB(&ip->i_inode); - struct inode *inode = &ip->i_inode; - 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_is_jdata(ip)) - gfs2_trans_add_bh(ip->i_gl, bh, 0); - mark_buffer_dirty(bh); - - if (release) { - unlock_page(page); - page_cache_release(page); - } - - return 0; -} - /** * gfs2_block_truncate_page - Deal with zeroing out data for truncate * diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h index 2c853a90ac0..67a4f4b79aa 100644 --- a/fs/gfs2/page.h +++ b/fs/gfs2/page.h @@ -14,8 +14,6 @@ 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_block_truncate_page(struct address_space *mapping); void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, unsigned int from, unsigned int to); -- GitLab From ba7f72901cfd437d6de087bf44d2b64357cb38a5 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 26 Jul 2006 11:27:10 -0400 Subject: [PATCH 0177/1619] [GFS2] Remove page.[ch] The remaining routines in page.c were all only used in one other file, so they are now moved into the files where they are referenced and made static. Thus page.[ch] are no longer required. Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 2 +- fs/gfs2/bmap.c | 78 +++++++++++++++- fs/gfs2/glops.c | 89 +++++++++++++++++- fs/gfs2/ops_address.c | 19 +++- fs/gfs2/ops_inode.c | 1 - fs/gfs2/ops_super.c | 1 - fs/gfs2/ops_vm.c | 1 - fs/gfs2/page.c | 207 ------------------------------------------ fs/gfs2/page.h | 21 ----- 9 files changed, 184 insertions(+), 235 deletions(-) delete mode 100644 fs/gfs2/page.c delete mode 100644 fs/gfs2/page.h diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 0b7977623b8..b92852b6662 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o 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 \ + ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 72b19c5d780..d20d41e1c02 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -22,12 +22,12 @@ #include "glock.h" #include "inode.h" #include "meta_io.h" -#include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" #include "dir.h" #include "util.h" +#include "ops_address.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 @@ -885,6 +885,82 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) return error; } + +/** + * gfs2_block_truncate_page - Deal with zeroing out data for truncate + * + * This is partly borrowed from ext3. + */ +static int gfs2_block_truncate_page(struct address_space *mapping) +{ + struct inode *inode = mapping->host; + 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); + unsigned blocksize, iblock, length, pos; + struct buffer_head *bh; + struct page *page; + void *kaddr; + int err; + + page = grab_cache_page(mapping, index); + if (!page) + return 0; + + blocksize = inode->i_sb->s_blocksize; + length = blocksize - (offset & (blocksize - 1)); + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + + 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_mapped(bh)) { + gfs2_get_block(inode, iblock, bh, 0); + /* unmapped? It's a hole - nothing to do */ + if (!buffer_mapped(bh)) + 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 (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); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + +unlock: + unlock_page(page); + page_cache_release(page); + return err; +} + static int trunc_start(struct gfs2_inode *ip, uint64_t size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index a01874c5883..3f909a81a07 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -23,11 +23,98 @@ #include "inode.h" #include "log.h" #include "meta_io.h" -#include "page.h" #include "recovery.h" #include "rgrp.h" #include "util.h" + +/** + * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock + * @gl: the glock + * + */ + +static void gfs2_pte_inval(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + 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; + + 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); + + clear_bit(GIF_SW_PAGED, &ip->i_flags); +} + +/** + * gfs2_page_inval - Invalidate all pages associated with a glock + * @gl: the glock + * + */ + +static void gfs2_page_inval(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + struct inode *inode; + + ip = gl->gl_object; + inode = &ip->i_inode; + if (!ip || !S_ISREG(ip->i_di.di_mode)) + return; + + 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); +} + +/** + * 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. + */ + +static 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; + + mapping = inode->i_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. */ + + if (error == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else if (error) + set_bit(AS_EIO, &mapping->flags); + +} + /** * meta_go_sync - sync out the metadata for this glock * @gl: the glock diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 93e00a8af8c..fca69f12e4d 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -27,7 +27,6 @@ #include "log.h" #include "meta_io.h" #include "ops_address.h" -#include "page.h" #include "quota.h" #include "trans.h" #include "rgrp.h" @@ -35,6 +34,24 @@ #include "util.h" #include "glops.h" + +static void gfs2_page_add_databufs(struct gfs2_inode *ip, 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_bh(ip->i_gl, bh, 0); + } +} + /** * gfs2_get_block - Fills in a buffer head with details about a block * @inode: The inode diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index caecafe0469..8fb7c5c9a7c 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -34,7 +34,6 @@ #include "meta_io.h" #include "ops_dentry.h" #include "ops_inode.h" -#include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 50ea7f21f9c..730c7228f6a 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -30,7 +30,6 @@ #include "log.h" #include "mount.h" #include "ops_super.h" -#include "page.h" #include "quota.h" #include "recovery.h" #include "rgrp.h" diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 910722d4c48..aff66373b7e 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -23,7 +23,6 @@ #include "glock.h" #include "inode.h" #include "ops_vm.h" -#include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c deleted file mode 100644 index 0d6befed1ae..00000000000 --- a/fs/gfs2/page.c +++ /dev/null @@ -1,207 +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 - -#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 - * @gl: the glock - * - */ - -void gfs2_pte_inval(struct gfs2_glock *gl) -{ - struct gfs2_inode *ip; - 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; - - 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); - - 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 = gl->gl_object; - inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) - return; - - 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); -} - -/** - * 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; - 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; - - mapping = inode->i_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. */ - - if (error == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else if (error) - set_bit(AS_EIO, &mapping->flags); - -} - -/** - * gfs2_block_truncate_page - Deal with zeroing out data for truncate - * - * This is partly borrowed from ext3. - */ -int gfs2_block_truncate_page(struct address_space *mapping) -{ - struct inode *inode = mapping->host; - 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); - unsigned blocksize, iblock, length, pos; - struct buffer_head *bh; - struct page *page; - void *kaddr; - int err; - - page = grab_cache_page(mapping, index); - if (!page) - return 0; - - blocksize = inode->i_sb->s_blocksize; - length = blocksize - (offset & (blocksize - 1)); - iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); - - 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_mapped(bh)) { - gfs2_get_block(inode, iblock, bh, 0); - /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(bh)) - 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 (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); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - -unlock: - unlock_page(page); - page_cache_release(page); - return err; -} - -void gfs2_page_add_databufs(struct gfs2_inode *ip, 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_bh(ip->i_gl, bh, 0); - } -} - diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h deleted file mode 100644 index 67a4f4b79aa..00000000000 --- a/fs/gfs2/page.h +++ /dev/null @@ -1,21 +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 __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_block_truncate_page(struct address_space *mapping); -void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, - unsigned int from, unsigned int to); - -#endif /* __PAGE_DOT_H__ */ -- GitLab From 20abf975f75d6fb45d8c055d30cdcb112ca8b608 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 26 Jul 2006 08:29:06 -0500 Subject: [PATCH 0178/1619] [DLM] fix broken patches On Wed, Jul 26, 2006 at 10:47:14AM +0100, Steven Whitehouse wrote: > Hi, > > I've applied all the patches you sent, but they don't build: Argh, sorry about that... when I fixed these a long time ago they somehow never got included in the quilt patches. I mistakenly assumed the quilt patches matched the source I had in front of me. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 5faa747c7ca..516f6c9ee4d 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -123,7 +123,7 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) if (root_list || recover_list) { seq_printf(s, "Recovery: root %d recover %d flags %lx " "count %d\n", root_list, recover_list, - res->flags, res->res_recover_locks_count); + res->res_flags, res->res_recover_locks_count); } /* Print the locks attached to this resource */ @@ -277,7 +277,7 @@ static int rsb_open(struct inode *inode, struct file *file) struct seq_file *seq; int ret; - ret = rsb_seq_open(file, &rsb_seq_ops); + ret = seq_open(file, &rsb_seq_ops); if (ret) return ret; @@ -343,7 +343,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) dlm_root, ls, &rsb_fops); - if (!ls->ls_rsb_debug_dentry) + if (!ls->ls_debug_rsb_dentry) return -ENOMEM; memset(name, 0, sizeof(name)); -- GitLab From ae4a382004fc6cf229c51deaf69910410d313e0b Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 26 Jul 2006 15:31:15 -0400 Subject: [PATCH 0179/1619] [DLM] fix i_private > I think you must have an old version of the base kernel as well? > i_private no longer exists in struct inode, so you'll have to use > something else, I have that patch in my stack but didn't send it; for some reason I thought it was already changed in your git tree. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 516f6c9ee4d..8f471d9a9e3 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -301,7 +301,7 @@ static struct file_operations rsb_fops = { static int waiters_open(struct inode *inode, struct file *file) { - file->private_data = inode->i_private; + file->private_data = inode->u.generic_ip; return 0; } -- GitLab From f45b7ddd2bae1dc98e35c3611b55cba6d2a8da9e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 27 Jul 2006 13:53:53 -0400 Subject: [PATCH 0180/1619] [GFS2] Use a bio to read the superblock This means that we don't need to create a special inode just to contain a struct address_space in order to read a single disk block. Instead we read the disk block directly. Its slightly faster, and uses slightly less memory, but the real reason for doing this is that it removes a special case from the glock code. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 3 +- fs/gfs2/glops.c | 22 +++----------- fs/gfs2/ops_fstype.c | 5 ---- fs/gfs2/super.c | 69 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 0381d4cc414..91ac9c9d4a9 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -311,8 +311,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, /* 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) { + glops == &gfs2_rgrp_glops) { gl->gl_aspace = gfs2_aspace_get(sdp); if (!gl->gl_aspace) { error = -ENOMEM; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 3f909a81a07..75d4c50cff4 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -156,18 +156,6 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags) 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 @@ -338,11 +326,12 @@ static void inode_go_unlock(struct gfs2_holder *gh) struct gfs2_glock *gl = gh->gh_gl; struct gfs2_inode *ip = gl->gl_object; - if (ip && test_bit(GLF_DIRTY, &gl->gl_flags)) - gfs2_inode_attr_in(ip); + if (ip) { + if (test_bit(GLF_DIRTY, &gl->gl_flags)) + gfs2_inode_attr_in(ip); - if (ip) gfs2_meta_cache_flush(ip); + } } /** @@ -507,9 +496,6 @@ static int quota_go_demote_ok(struct gfs2_glock *gl) 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 }; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index a86ce67949d..de18923eea7 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -310,11 +310,6 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) 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); /* Get the root inode */ diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f2d287660cc..48fd4cb49c1 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "gfs2.h" #include "lm_interface.h" @@ -157,6 +158,54 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) return 0; } + +static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) +{ + struct page *page = bio->bi_private; + if (bio->bi_size) + return 1; + + if (!error) + SetPageUptodate(page); + unlock_page(page); + return 0; +} + +static struct page *gfs2_read_super(struct super_block *sb, sector_t sector) +{ + struct page *page; + struct bio *bio; + + page = alloc_page(GFP_KERNEL); + if (unlikely(!page)) + return NULL; + + ClearPageUptodate(page); + ClearPageDirty(page); + lock_page(page); + + bio = bio_alloc(GFP_KERNEL, 1); + if (unlikely(!bio)) { + __free_page(page); + return NULL; + } + + bio->bi_sector = sector; + bio->bi_bdev = sb->s_bdev; + bio_add_page(bio, page, PAGE_SIZE, 0); + + bio->bi_end_io = end_bio_io_page; + bio->bi_private = page; + submit_bio(READ | BIO_RW_SYNC, bio); + wait_on_page_locked(page); + bio_put(bio); + if (!PageUptodate(page)) { + __free_page(page); + return NULL; + } + return page; +} + /** * gfs2_read_sb - Read super block * @sdp: The GFS2 superblock @@ -167,23 +216,23 @@ 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) { - struct buffer_head *bh; uint32_t hash_blocks, ind_blocks, leaf_blocks; uint32_t tmp_blocks; unsigned int x; int error; + struct page *page; + char *sb; - error = gfs2_meta_read(gl, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, - DIO_FORCE | DIO_START | DIO_WAIT, &bh); - if (error) { + page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift); + if (!page) { if (!silent) fs_err(sdp, "can't read superblock\n"); - return error; + return -EIO; } - - gfs2_assert(sdp, sizeof(struct gfs2_sb) <= bh->b_size); - gfs2_sb_in(&sdp->sd_sb, bh->b_data); - brelse(bh); + sb = kmap(page); + gfs2_sb_in(&sdp->sd_sb, sb); + kunmap(page); + __free_page(page); error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); if (error) @@ -202,7 +251,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(uint64_t); sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / - sizeof(struct gfs2_quota_change); + sizeof(struct gfs2_quota_change); /* Compute maximum reservation required to add a entry to a directory */ -- GitLab From dd894be8df11ea40a1163b75596ab85d558816c8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 27 Jul 2006 14:29:00 -0400 Subject: [PATCH 0181/1619] [GFS2] Change some allocations to GFP_NOFS Some allocations in rgrp.c should have been GFP_NOFS rather than GFP_KERNEL. Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 65eea0b88bf..4e0357dc838 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -374,7 +374,7 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) if (!length) return -EINVAL; - rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_KERNEL); + rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_NOFS); if (!rgd->rd_bits) return -ENOMEM; @@ -467,7 +467,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) goto fail; } - rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_KERNEL); + rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS); error = -ENOMEM; if (!rgd) goto fail; @@ -1184,14 +1184,13 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, if (!bi->bi_clone) { bi->bi_clone = kmalloc(bi->bi_bh->b_size, - GFP_KERNEL | __GFP_NOFAIL); + GFP_NOFS | __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, 1); - gfs2_setbit(rgd, - bi->bi_bh->b_data + bi->bi_offset, + gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, buf_blk, new_state); } @@ -1469,7 +1468,7 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, new_space = rlist->rl_space + 10; tmp = kcalloc(new_space, sizeof(struct gfs2_rgrpd *), - GFP_KERNEL | __GFP_NOFAIL); + GFP_NOFS | __GFP_NOFAIL); if (rlist->rl_rgd) { memcpy(tmp, rlist->rl_rgd, @@ -1501,7 +1500,7 @@ void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, unsigned int x; rlist->rl_ghs = kcalloc(rlist->rl_rgrps, sizeof(struct gfs2_holder), - GFP_KERNEL | __GFP_NOFAIL); + GFP_NOFS | __GFP_NOFAIL); for (x = 0; x < rlist->rl_rgrps; x++) gfs2_holder_init(rlist->rl_rgd[x]->rd_gl, state, flags, -- GitLab From 2b98a54f796f701604737abd9c2017948e9e010b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 27 Jul 2006 16:37:48 -0400 Subject: [PATCH 0182/1619] [GFS2] Fix bug in super block reading code This gets the argument to submit_bio() correct. Signed-off-by: Steven Whitehouse --- fs/gfs2/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 48fd4cb49c1..3c318a9e8a8 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -167,6 +167,8 @@ static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) if (!error) SetPageUptodate(page); + else + printk(KERN_WARNING "gfs2: error %d reading superblock\n", error); unlock_page(page); return 0; } @@ -196,7 +198,7 @@ static struct page *gfs2_read_super(struct super_block *sb, sector_t sector) bio->bi_end_io = end_bio_io_page; bio->bi_private = page; - submit_bio(READ | BIO_RW_SYNC, bio); + submit_bio(READ_SYNC, bio); wait_on_page_locked(page); bio_put(bio); if (!PageUptodate(page)) { -- GitLab From 5dd9feafb351a8bf304292623cbc63335c34d279 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 28 Jul 2006 14:52:33 -0400 Subject: [PATCH 0183/1619] [GFS2] Fix bug in clear_inode We should have been waiting for lock demotion to finish in clear_inode. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 91ac9c9d4a9..b6edf7c0923 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -771,6 +771,7 @@ void gfs2_glock_inode_squish(struct inode *inode) 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); } -- GitLab From 420b9e5e45d33355471c8d2d593bb0e5d6c77421 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 31 Jul 2006 15:42:17 -0400 Subject: [PATCH 0184/1619] [GFS2] Tidy up in various files Tidy up some files and remove an unused routine in meta_io.h. Also added a bit of extra debugging in meta_io.h. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 20 +++++--------------- fs/gfs2/meta_io.h | 23 ++++------------------- fs/gfs2/ops_file.c | 9 +++------ 3 files changed, 12 insertions(+), 40 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index e76f345517b..9fb340984b2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -277,8 +277,7 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip) if (error) goto out_rindex_relse; - error = gfs2_trans_begin(sdp, RES_RG_BIT + - RES_STATFS + RES_QUOTA, 1); + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); if (error) goto out_rg_gunlock; @@ -522,16 +521,13 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); - out_brelse: +out_brelse: brelse(bh); - - out_end_trans: +out_end_trans: mutex_unlock(&sdp->sd_inum_mutex); gfs2_trans_end(sdp); - - out: +out: gfs2_glock_dq_uninit(&gh); - return error; } @@ -593,8 +589,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_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) @@ -634,10 +629,8 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum, out_ipreserv: gfs2_inplace_release(dip); - out: gfs2_alloc_put(dip); - return error; } @@ -1300,7 +1293,6 @@ int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs) } kfree(p); - return error; } @@ -1346,9 +1338,7 @@ int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) return error; error = __gfs2_setattr_simple(ip, attr); - gfs2_trans_end(GFS2_SB(&ip->i_inode)); - return error; } diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 23c6a596fd9..951814e8627 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -17,35 +17,20 @@ static inline void gfs2_buffer_clear(struct buffer_head *bh) static inline void gfs2_buffer_clear_tail(struct buffer_head *bh, int head) { + BUG_ON(head > bh->b_size); 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, + BUG_ON(from_head < to_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); + 0, from_head - to_head); } struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index d13e04e8a96..145a29fa4ea 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -597,13 +597,11 @@ static int gfs2_open(struct inode *inode, struct file *file) return 0; - fail_gunlock: +fail_gunlock: gfs2_glock_dq_uninit(&i_gh); - - fail: +fail: file->private_data = NULL; kfree(fp); - return error; } @@ -736,9 +734,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); } - out: +out: mutex_unlock(&fp->f_fl_mutex); - return error; } -- GitLab From de9b75d31e81e87685d8cc70052a003c654f1e8e Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 28 Jul 2006 14:00:20 -0500 Subject: [PATCH 0185/1619] [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(-) diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 6adfb2d4fd8..e5b11f0688f 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 007b07a178a..fc341511397 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 -- GitLab From 899bb264507cfed83922bf14cd66a073494601ba Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 1 Aug 2006 15:28:57 -0400 Subject: [PATCH 0186/1619] [GFS2] Fix bug in directory code This was a nasty bug which resulted in corruption of hash tables in the directory code with larger directories. We forgot to increment a pointer in the read/write routines internal to the directory code. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 563b99e419b..76a23c172ee 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -215,6 +215,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, if (error) goto fail; + buf += amount; copied += amount; lblock++; dblock++; @@ -335,6 +336,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, if (error) goto fail; + buf += amount; copied += amount; lblock++; -- GitLab From 59a1cc6bdabf5ed148b48808ad1a418d87f5e6bf Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 4 Aug 2006 15:41:22 -0400 Subject: [PATCH 0187/1619] [GFS2] Fix lock ordering bug in page fault path Mmapped files were able to trigger a lock ordering bug. Private maps do not need to take the glock so early on. Shared maps do unfortunately, however we can get around that by adding a flag into the flags for the struct gfs2_file. This only works because we are taking an exclusive lock at this point, so we know that nobody else can be racing with us. Fixes Red Hat bugzilla: #201196 Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 1 + fs/gfs2/log.c | 4 ++-- fs/gfs2/ops_address.c | 23 +++++++++++++++++++---- fs/gfs2/ops_vm.c | 20 +++++++------------- fs/gfs2/recovery.c | 9 +++------ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 90e0624d806..e98c14f30da 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -279,6 +279,7 @@ static inline struct gfs2_sbd *GFS2_SB(struct inode *inode) enum { GFF_DID_DIRECT_ALLOC = 0, + GFF_EXLOCK = 1, }; struct gfs2_file { diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 60fdc94ccc8..a591fb8fae2 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -256,8 +256,8 @@ static unsigned int current_tail(struct gfs2_sbd *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); + ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, + ai_list); tail = ai->ai_first; } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index fca69f12e4d..bdd4d6b4872 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -237,14 +237,22 @@ static int gfs2_readpage(struct file *file, struct page *page) struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); struct gfs2_holder gh; int error; + int do_unlock = 0; if (likely(file != &gfs2_internal_file_sentinal)) { + if (file) { + struct gfs2_file *gf = file->private_data; + if (test_bit(GFF_EXLOCK, &gf->f_flags)) + goto skip_lock; + } gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); + do_unlock = 1; error = gfs2_glock_nq_m_atime(1, &gh); if (unlikely(error)) goto out_unlock; } +skip_lock: if (gfs2_is_stuffed(ip)) { error = stuffed_readpage(ip, page); unlock_page(page); @@ -262,7 +270,7 @@ out: return error; out_unlock: unlock_page(page); - if (file != &gfs2_internal_file_sentinal) + if (do_unlock) gfs2_holder_uninit(&gh); goto out; } @@ -291,17 +299,24 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, struct gfs2_holder gh; unsigned page_idx; int ret; + int do_unlock = 0; if (likely(file != &gfs2_internal_file_sentinal)) { + if (file) { + struct gfs2_file *gf = file->private_data; + if (test_bit(GFF_EXLOCK, &gf->f_flags)) + goto skip_lock; + } gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh); + do_unlock = 1; ret = gfs2_glock_nq_m_atime(1, &gh); if (ret == GLR_TRYFAILED) goto out_noerror; if (unlikely(ret)) goto out_unlock; } - +skip_lock: if (gfs2_is_stuffed(ip)) { struct pagevec lru_pvec; pagevec_init(&lru_pvec, 0); @@ -326,7 +341,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); } - if (likely(file != &gfs2_internal_file_sentinal)) { + if (do_unlock) { gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); } @@ -344,7 +359,7 @@ out_unlock: unlock_page(page); page_cache_release(page); } - if (likely(file != &gfs2_internal_file_sentinal)) + if (do_unlock) gfs2_holder_uninit(&gh); goto out; } diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index aff66373b7e..875a769444a 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -46,13 +46,7 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, unsigned long address, int *type) { struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); - struct gfs2_holder i_gh; struct page *result; - int error; - - 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); @@ -61,8 +55,6 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, if (result && result != NOPAGE_OOM) pfault_be_greedy(ip); - gfs2_glock_dq_uninit(&i_gh); - return result; } @@ -141,7 +133,9 @@ 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 = GFS2_I(area->vm_file->f_mapping->host); + struct file *file = area->vm_file; + struct gfs2_file *gf = file->private_data; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_holder i_gh; struct page *result = NULL; unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + @@ -156,13 +150,14 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, 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, + error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE, &alloc_required); if (error) goto out; + set_bit(GFF_EXLOCK, &gf->f_flags); result = filemap_nopage(area, address, type); + clear_bit(GFF_EXLOCK, &gf->f_flags); if (!result || result == NOPAGE_OOM) goto out; @@ -177,8 +172,7 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, } pfault_be_greedy(ip); - - out: +out: gfs2_glock_dq_uninit(&i_gh); return result; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 7aabc03e4ab..bbd44a4b1a1 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -153,8 +153,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, if (lh.lh_header.mh_magic != GFS2_MAGIC || lh.lh_header.mh_type != GFS2_METATYPE_LH || - lh.lh_blkno != blk || - lh.lh_hash != hash) + lh.lh_blkno != blk || lh.lh_hash != hash) return 1; *head = lh; @@ -482,11 +481,9 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) /* Acquire a shared hold on the transaction lock */ - error = gfs2_glock_nq_init(sdp->sd_trans_gl, - LM_ST_SHARED, + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, LM_FLAG_NOEXP | LM_FLAG_PRIORITY | - GL_NOCANCEL | GL_NOCACHE, - &t_gh); + GL_NOCANCEL | GL_NOCACHE, &t_gh); if (error) goto fail_gunlock_ji; -- GitLab From 3120ec541eafc6ed19bacb395adf08c5872143bf Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 4 Aug 2006 13:14:50 -0500 Subject: [PATCH 0188/1619] [GFS2] lockproto api prefix Use the gfs2_ prefix on the register/unregister functions for the lock modules. The gfs_ prefix was left from an old idea on how to share these with gfs1. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/lm_interface.h | 9 ++------- fs/gfs2/locking/dlm/main.c | 8 ++++---- fs/gfs2/locking/nolock/main.c | 4 ++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index 9d34bf3df10..1da95a55f76 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -265,16 +265,11 @@ 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); +int gfs2_register_lockproto(struct lm_lockops *proto); -void gfs_unregister_lockproto(struct lm_lockops *proto); +void gfs2_unregister_lockproto(struct lm_lockops *proto); /* * Lock module top interface. GFS calls these functions when mounting or diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 89728c91665..870a1cd99f5 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -20,7 +20,7 @@ static int __init init_lock_dlm(void) { int error; - error = gfs_register_lockproto(&gdlm_ops); + error = gfs2_register_lockproto(&gdlm_ops); if (error) { printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n", error); @@ -29,14 +29,14 @@ static int __init init_lock_dlm(void) error = gdlm_sysfs_init(); if (error) { - gfs_unregister_lockproto(&gdlm_ops); + gfs2_unregister_lockproto(&gdlm_ops); return error; } error = gdlm_plock_init(); if (error) { gdlm_sysfs_exit(); - gfs_unregister_lockproto(&gdlm_ops); + gfs2_unregister_lockproto(&gdlm_ops); return error; } @@ -52,7 +52,7 @@ static void __exit exit_lock_dlm(void) { gdlm_plock_exit(); gdlm_sysfs_exit(); - gfs_unregister_lockproto(&gdlm_ops); + gfs2_unregister_lockproto(&gdlm_ops); } module_init(init_lock_dlm); diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 97ffac5cdef..748aa5d3364 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -233,7 +233,7 @@ static int __init init_nolock(void) { int error; - error = gfs_register_lockproto(&nolock_ops); + error = gfs2_register_lockproto(&nolock_ops); if (error) { printk(KERN_WARNING "lock_nolock: can't register protocol: %d\n", error); @@ -247,7 +247,7 @@ static int __init init_nolock(void) static void __exit exit_nolock(void) { - gfs_unregister_lockproto(&nolock_ops); + gfs2_unregister_lockproto(&nolock_ops); } module_init(init_nolock); -- GitLab From 08eac93a689ca05c7b7413f6d362c7d38b5fd5b1 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 4 Aug 2006 16:19:20 -0500 Subject: [PATCH 0189/1619] [GFS2] match plock result with correct request When the result of a posix lock request is read it needs to be matched up with the correct waiting request. The owner field needs to be used in the comparison since more than one process may be waiting for locks on the same file. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/plock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index e5b11f0688f..1acb2519f43 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -232,7 +232,8 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, spin_lock(&ops_lock); list_for_each_entry(op, &recv_list, list) { if (op->info.fsid == info.fsid && - op->info.number == info.number) { + op->info.number == info.number && + op->info.owner == info.owner) { list_del_init(&op->list); found = 1; op->done = 1; -- GitLab From 2b557f6dc7899a0f6afc0169534346f8fa977a46 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 7 Aug 2006 11:12:30 -0400 Subject: [PATCH 0190/1619] [GFS2] Fix gfs_ prefix in locking.c The previous patch didn't change all the gfs_ to gfs2_ so this is the remainder. Signed-off-by: Steven Whitehouse --- fs/gfs2/locking.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 183192836e9..ded1ef6c81e 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -31,13 +31,13 @@ static struct list_head lmh_list; static struct mutex lmh_lock; /** - * gfs_register_lockproto - Register a low-level locking protocol + * gfs2_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) +int gfs2_register_lockproto(struct lm_lockops *proto) { struct lmh_wrapper *lw; @@ -67,12 +67,12 @@ int gfs_register_lockproto(struct lm_lockops *proto) } /** - * gfs_unregister_lockproto - Unregister a low-level locking protocol + * gfs2_unregister_lockproto - Unregister a low-level locking protocol * @proto: the protocol definition * */ -void gfs_unregister_lockproto(struct lm_lockops *proto) +void gfs2_unregister_lockproto(struct lm_lockops *proto) { struct lmh_wrapper *lw; @@ -117,7 +117,7 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, int try = 0; int error, found; - retry: +retry: mutex_lock(&lmh_lock); found = 0; @@ -151,7 +151,7 @@ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, min_lvb_size, flags, lockstruct, fskobj); if (error) module_put(lw->lw_ops->lm_owner); - out: +out: mutex_unlock(&lmh_lock); return error; } @@ -186,6 +186,6 @@ void __init gfs2_init_lmh(void) INIT_LIST_HEAD(&lmh_list); } -EXPORT_SYMBOL_GPL(gfs_register_lockproto); -EXPORT_SYMBOL_GPL(gfs_unregister_lockproto); +EXPORT_SYMBOL_GPL(gfs2_register_lockproto); +EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto); -- GitLab From cc346d555f2c3eb4a63b2df6bf9c9947f0a92a01 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Tue, 8 Aug 2006 10:34:40 -0400 Subject: [PATCH 0191/1619] [DLM] fix userland unlock This patch fixes the userland DLM unlock code so that it correctly returns the address of the userland lock status block in its completion AST. It fixes bug #201348 Patrick Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 7d38f914c5b..bb2e3515121 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3699,6 +3699,7 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, if (lvb_in && ua->lksb.sb_lvbptr) memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); ua->castparam = ua_tmp->castparam; + ua->user_lksb = ua_tmp->user_lksb; error = set_unlock_args(flags, ua, &args); if (error) -- GitLab From f4387149ec71fed11535b49400bad17d22fdc935 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 8 Aug 2006 13:23:19 -0400 Subject: [PATCH 0192/1619] [GFS2] Fix lack of buffers in writepage bug In some cases we can enter write page without there being buffers attached to the page. In this case the function to add gfs2_bufdata to the buffers fails sliently causing further failures down the stack. This fix ensures that we always add buffers in writepage if they didn't already exist (mmap is one way to trigger this). Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index bdd4d6b4872..45afd050868 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -131,8 +131,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 = GFS2_I(page->mapping->host); - struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); loff_t i_size = i_size_read(inode); pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; @@ -158,6 +158,10 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); if (error) goto out_ignore; + if (!page_has_buffers(page)) { + create_empty_buffers(page, inode->i_sb->s_blocksize, + (1 << BH_Dirty)|(1 << BH_Uptodate)); + } gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1); done_trans = 1; } -- GitLab From 5ff519112af6a6dab0ad7f6b0b0a2dcfff273e5b Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 8 Aug 2006 17:03:30 -0500 Subject: [PATCH 0193/1619] [DLM] print bad length in assertion Print the violating name length in the assertion. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index 48dfc27861f..989b608fd83 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -100,7 +100,8 @@ struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen) { struct dlm_direntry *de; - DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,); + DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN, + printk("namelen = %d\n", namelen);); de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL); if (de) -- GitLab From f6db1b8e724b071d144055b48da3827ce26dba1c Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 8 Aug 2006 17:06:07 -0500 Subject: [PATCH 0194/1619] [DLM] abort recovery more quickly When we abort one recovery to do another, break out of the ping_members() routine more quickly, and wake up the dlm_recoverd thread more quickly instead of waiting for it to time out. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/member.c | 24 +++++++++++++++++++----- fs/dlm/recoverd.c | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/fs/dlm/member.c b/fs/dlm/member.c index cd0c51e724e..ebb33c30f0f 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -162,11 +162,22 @@ static void make_member_array(struct dlm_ls *ls) /* send a status request to all members just to establish comms connections */ -static void ping_members(struct dlm_ls *ls) +static int 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 error = 0; + + list_for_each_entry(memb, &ls->ls_nodes, list) { + error = dlm_recovery_stopped(ls); + if (error) + break; + error = dlm_rcom_status(ls, memb->nodeid); + if (error) + break; + } + if (error) + log_debug(ls, "ping_members aborted %d", error); + return error; } int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) @@ -212,10 +223,13 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) dlm_set_recover_status(ls, DLM_RS_NODES); *neg_out = neg; - ping_members(ls); + error = ping_members(ls); + if (error) + goto out; error = dlm_recover_members_wait(ls); - log_debug(ls, "total members %d", ls->ls_num_nodes); + out: + log_debug(ls, "total members %d error %d", ls->ls_num_nodes, error); return error; } diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 70103533677..eac8e9fa67f 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -275,6 +275,7 @@ void dlm_recoverd_stop(struct dlm_ls *ls) void dlm_recoverd_suspend(struct dlm_ls *ls) { + wake_up(&ls->ls_wait_general); mutex_lock(&ls->ls_recoverd_active); } -- GitLab From 06442440bc442ef79cb060c6e786eaeeabd9044b Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 8 Aug 2006 11:31:30 -0500 Subject: [PATCH 0195/1619] [DLM] break from snprintf loop When the debug buffer has filled up, break from the loop and return the correct number of bytes that have been written. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 8f471d9a9e3..9c3aeddc866 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -310,16 +310,19 @@ static ssize_t waiters_read(struct file *file, char __user *userbuf, { struct dlm_ls *ls = file->private_data; struct dlm_lkb *lkb; - size_t len = DLM_DEBUG_BUF_LEN, pos = 0, rv; + size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv; mutex_lock(&debug_buf_lock); mutex_lock(&ls->ls_waiters_mutex); memset(debug_buf, 0, sizeof(debug_buf)); list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { - pos += snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n", - lkb->lkb_id, lkb->lkb_wait_type, - lkb->lkb_nodeid, lkb->lkb_resource->res_name); + ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n", + lkb->lkb_id, lkb->lkb_wait_type, + lkb->lkb_nodeid, lkb->lkb_resource->res_name); + if (ret >= len - pos) + break; + pos += ret; } mutex_unlock(&ls->ls_waiters_mutex); -- GitLab From faa0f2677287a2e7ae796db8b73618ec43715e94 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 8 Aug 2006 17:08:42 -0500 Subject: [PATCH 0196/1619] [DLM] show nodeid for recovery message To aid debugging, it's useful to be able to see what nodeid the dlm is waiting on for a message reply. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/lockspace.c | 11 +++++++++++ fs/dlm/member.c | 3 ++- fs/dlm/rcom.c | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 7c3c2d27c01..ec7e401133f 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -467,6 +467,7 @@ struct dlm_ls { struct list_head ls_requestqueue;/* queue remote requests */ struct mutex ls_requestqueue_mutex; char *ls_recover_buf; + int ls_recover_nodeid; /* for debugging */ struct list_head ls_recover_list; spinlock_t ls_recover_list_lock; int ls_recover_list_count; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 31ed0fe16a3..7adaad53fc3 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -81,6 +81,11 @@ static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf) return sprintf(buf, "%x\n", status); } +static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->ls_recover_nodeid); +} + struct dlm_attr { struct attribute attr; ssize_t (*show)(struct dlm_ls *, char *); @@ -108,11 +113,17 @@ static struct dlm_attr dlm_attr_recover_status = { .show = dlm_recover_status_show }; +static struct dlm_attr dlm_attr_recover_nodeid = { + .attr = {.name = "recover_nodeid", .mode = S_IRUGO}, + .show = dlm_recover_nodeid_show +}; + static struct attribute *dlm_attrs[] = { &dlm_attr_control.attr, &dlm_attr_event.attr, &dlm_attr_id.attr, &dlm_attr_recover_status.attr, + &dlm_attr_recover_nodeid.attr, NULL, }; diff --git a/fs/dlm/member.c b/fs/dlm/member.c index ebb33c30f0f..a3f7de7f3a8 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -176,7 +176,8 @@ static int ping_members(struct dlm_ls *ls) break; } if (error) - log_debug(ls, "ping_members aborted %d", error); + log_debug(ls, "ping_members aborted %d last nodeid %d", + error, ls->ls_recover_nodeid); return error; } diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 55fbe313340..5573d8590e5 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -97,6 +97,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid) int error = 0; memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + ls->ls_recover_nodeid = nodeid; if (nodeid == dlm_our_nodeid()) { rc = (struct dlm_rcom *) ls->ls_recover_buf; @@ -159,6 +160,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) int error = 0, len = sizeof(struct dlm_rcom); memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + ls->ls_recover_nodeid = nodeid; if (nodeid == dlm_our_nodeid()) { dlm_copy_master_names(ls, last_name, last_len, -- GitLab From 4a99c3d9d6663085e28bc7ac8dae1e985c5a6174 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 9 Aug 2006 11:20:15 -0500 Subject: [PATCH 0197/1619] [DLM] reject replies to old requests When recoveries are aborted by other recoveries we can get replies to status or names requests that we've given up on. This can cause problems if we're making another request and receive an old reply. Add a sequence number to status/names requests and reject replies that don't match. A field already exists for the seq number that's used in other message types. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/rcom.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index ec7e401133f..da750998669 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -468,6 +468,7 @@ struct dlm_ls { struct mutex ls_requestqueue_mutex; char *ls_recover_buf; int ls_recover_nodeid; /* for debugging */ + uint64_t ls_rcom_seq; struct list_head ls_recover_list; spinlock_t ls_recover_list_lock; int ls_recover_list_count; diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 5573d8590e5..64ba4929f90 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -108,6 +108,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid) error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh); if (error) goto out; + rc->rc_id = ++ls->ls_rcom_seq; send_rcom(ls, mh, rc); @@ -140,19 +141,30 @@ static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in) sizeof(struct rcom_config), &rc, &mh); if (error) return; + rc->rc_id = rc_in->rc_id; 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) +static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) { + if (rc_in->rc_id != ls->ls_rcom_seq) { + log_debug(ls, "reject old reply %d got %llx wanted %llx", + rc_in->rc_type, rc_in->rc_id, ls->ls_rcom_seq); + return; + } 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); } +static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + receive_sync_reply(ls, rc_in); +} + int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) { struct dlm_rcom *rc; @@ -173,6 +185,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) if (error) goto out; memcpy(rc->rc_buf, last_name, last_len); + rc->rc_id = ++ls->ls_rcom_seq; send_rcom(ls, mh, rc); @@ -209,6 +222,7 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh); if (error) return; + rc->rc_id = rc_in->rc_id; dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen, nodeid); @@ -217,9 +231,7 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) 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); + receive_sync_reply(ls, rc_in); } int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid) -- GitLab From 8872187780f6104216c67e7b60c11f708b513c38 Mon Sep 17 00:00:00 2001 From: Russell Cattelan Date: Thu, 10 Aug 2006 11:08:40 -0500 Subject: [PATCH 0198/1619] [GFS2] Fix a couple of refcount leaks. recovery.c add a brelse to deal with gfs2_replay_read_block being called twice on the same block. add a dput to drop the ref count on the root inode. This was causing lingering glocks and thus causing a mount failure to hang. Fix a endian conversion macro that was was swizzling 16bits when it should have been swizzling 32. Signed-off-by: Russell Cattelan Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 9 ++++++--- fs/gfs2/ops_fstype.c | 4 ++++ fs/gfs2/recovery.c | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index b6edf7c0923..a5e16e53999 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2167,7 +2167,9 @@ static int dump_glock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); - printk(KERN_INFO "Glock (%u, %llu)\n", gl->gl_name.ln_type, + printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", + gl, + gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); printk(KERN_INFO " gl_flags ="); for (x = 0; x < 32; x++) @@ -2187,8 +2189,9 @@ static int dump_glock(struct gfs2_glock *gl) printk(KERN_INFO " reclaim = %s\n", (list_empty(&gl->gl_reclaim)) ? "no" : "yes"); if (gl->gl_aspace) - printk(KERN_INFO " aspace = %lu\n", - gl->gl_aspace->i_mapping->nrpages); + printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", + gl->gl_aspace, + gl->gl_aspace->i_mapping->nrpages); else printk(KERN_INFO " aspace = no\n"); printk(KERN_INFO " ail = %d\n", atomic_read(&gl->gl_ail_count)); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index de18923eea7..444000968cf 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -279,6 +279,10 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) int error = 0; if (undo) { + if (sb->s_root) { + dput(sb->s_root); + sb->s_root = NULL; + } return 0; } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index bbd44a4b1a1..8fe518cfb3d 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -325,6 +325,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, error = get_log_header(jd, start, &lh); if (!error) { gfs2_replay_incr_blk(sdp, &start); + brelse(bh); continue; } if (error == 1) { @@ -396,7 +397,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) 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_type = cpu_to_be32(GFS2_METATYPE_LH); lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1); lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT); -- GitLab From fcc8abc8d4fcdbddc383091449f3696b411aa8fb Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 10 Aug 2006 13:31:23 -0500 Subject: [PATCH 0199/1619] [DLM] move kmap to after spin_unlock Doing the kmap() while holding the spinlock was causing recursive spinlock problems. It seems the kmap was scheduling, although there was no warning as I'd expect. Patrick, do we need locking around the kmap? Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 7ab40422ab5..23f5ce12080 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -934,11 +934,11 @@ static int send_to_sock(struct nodeinfo *ni) 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); + kmap(e->page); ret = 0; if (len) { -- GitLab From 15d00c0b91ca776b51b5ab04f79ab35b06670d30 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 18 Aug 2006 15:51:09 -0400 Subject: [PATCH 0200/1619] [GFS2] Fix leak of gfs2_bufdata This fixes a memory leak of struct gfs2_bufdata and also some problems in the ordered write handling code. It needs a bit more testing, but I believe that the reference counting of ordered write buffers should now be correct. This is aimed at fixing Red Hat bugzilla: #201028 and #201082 Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 6 +++--- fs/gfs2/meta_io.c | 1 - fs/gfs2/ops_address.c | 8 +++----- fs/gfs2/ops_super.c | 2 -- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index af03bf380f4..04bceb75ff2 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -464,7 +464,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_inode *ip = GFS2_I(mapping->host); tr->tr_touched = 1; - if (!list_empty(&bd->bd_list_tr) && + if (list_empty(&bd->bd_list_tr) && (ip->i_di.di_flags & GFS2_DIF_JDATA)) { tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); @@ -473,7 +473,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) } gfs2_trans_add_gl(bd->bd_gl); gfs2_log_lock(sdp); - if (!list_empty(&le->le_list)) { + if (list_empty(&le->le_list)) { if (ip->i_di.di_flags & GFS2_DIF_JDATA) sdp->sd_log_num_jdata++; sdp->sd_log_num_databuf++; @@ -640,10 +640,10 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) bd_le.le_list); list_del(&bd1->bd_le.le_list); sdp->sd_log_num_databuf--; - bh = bd1->bd_bh; if (bh) { bh->b_private = NULL; + get_bh(bh); gfs2_log_unlock(sdp); wait_on_buffer(bh); brelse(bh); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 42dfd32059b..502864b2419 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -464,7 +464,6 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, lops_init_le(&bd->bd_le, &gfs2_buf_lops); } else { lops_init_le(&bd->bd_le, &gfs2_databuf_lops); - get_bh(bh); } bh->b_private = bd; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 45afd050868..4c59cb11099 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -581,10 +581,8 @@ static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) if (bd) { bd->bd_bh = NULL; bh->b_private = NULL; - gfs2_log_unlock(sdp); - brelse(bh); - } else - gfs2_log_unlock(sdp); + } + gfs2_log_unlock(sdp); lock_buffer(bh); clear_buffer_dirty(bh); @@ -598,7 +596,7 @@ static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) static void gfs2_invalidatepage(struct page *page, unsigned long offset) { - struct gfs2_sbd *sdp = page->mapping->host->i_sb->s_fs_info; + struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); struct buffer_head *head, *bh, *next; unsigned int curr_off = 0; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 730c7228f6a..2e392c994ab 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -216,8 +216,6 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf) 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; -- GitLab From a345da3e8f28ff69e1b14df78f7ddc6e7b78b726 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 18 Aug 2006 11:54:25 -0500 Subject: [PATCH 0201/1619] [DLM] dump rsb and locks on assert Introduce new function dlm_dump_rsb() to call within assertions instead of dlm_print_rsb(). The new function dumps info about all locks on the rsb in addition to rsb details. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 40 +++++++++++++++++++++++++++++++--------- fs/dlm/lock.h | 1 + fs/dlm/recover.c | 4 ++-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index bb2e3515121..712438513cc 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -171,6 +171,28 @@ void dlm_print_rsb(struct dlm_rsb *r) r->res_recover_locks_count, r->res_name); } +void dlm_dump_rsb(struct dlm_rsb *r) +{ + struct dlm_lkb *lkb; + + dlm_print_rsb(r); + + printk(KERN_ERR "rsb: root_list empty %d recover_list empty %d\n", + list_empty(&r->res_root_list), list_empty(&r->res_recover_list)); + printk(KERN_ERR "rsb lookup list\n"); + list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) + dlm_print_lkb(lkb); + printk(KERN_ERR "rsb grant queue:\n"); + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) + dlm_print_lkb(lkb); + printk(KERN_ERR "rsb convert queue:\n"); + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) + dlm_print_lkb(lkb); + printk(KERN_ERR "rsb wait queue:\n"); + list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) + dlm_print_lkb(lkb); +} + /* Threads cannot use the lockspace while it's being recovered */ static inline void lock_recovery(struct dlm_ls *ls) @@ -478,7 +500,7 @@ 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);); + DLM_ASSERT(!rv, dlm_dump_rsb(r);); } static void kill_rsb(struct kref *kref) @@ -488,12 +510,12 @@ static void kill_rsb(struct kref *kref) /* 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),); + DLM_ASSERT(list_empty(&r->res_lookup), dlm_dump_rsb(r);); + DLM_ASSERT(list_empty(&r->res_grantqueue), dlm_dump_rsb(r);); + DLM_ASSERT(list_empty(&r->res_convertqueue), dlm_dump_rsb(r);); + DLM_ASSERT(list_empty(&r->res_waitqueue), dlm_dump_rsb(r);); + DLM_ASSERT(list_empty(&r->res_root_list), dlm_dump_rsb(r);); + DLM_ASSERT(list_empty(&r->res_recover_list), dlm_dump_rsb(r);); } /* Attaching/detaching lkb's from rsb's is for rsb reference counting. @@ -1336,7 +1358,7 @@ 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);); + DLM_ASSERT(is_master(r), dlm_dump_rsb(r);); high = grant_pending_convert(r, high); high = grant_pending_wait(r, high); @@ -1431,7 +1453,7 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb) return 0; } - DLM_ASSERT(r->res_nodeid == -1, dlm_print_rsb(r);); + DLM_ASSERT(r->res_nodeid == -1, dlm_dump_rsb(r);); dir_nodeid = dlm_dir_nodeid(r); diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 8d2660f0ab1..0843a3073ec 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -14,6 +14,7 @@ #define __LOCK_DOT_H__ void dlm_print_rsb(struct dlm_rsb *r); +void dlm_dump_rsb(struct dlm_rsb *r); void dlm_print_lkb(struct dlm_lkb *lkb); int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery); int dlm_modes_compat(int mode1, int mode2); diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index 1a86dfc8034..528a2a0fa32 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -490,7 +490,7 @@ static int recover_locks(struct dlm_rsb *r) if (all_queues_empty(r)) goto out; - DLM_ASSERT(!r->res_recover_locks_count, dlm_print_rsb(r);); + DLM_ASSERT(!r->res_recover_locks_count, dlm_dump_rsb(r);); error = recover_locks_queue(r, &r->res_grantqueue); if (error) @@ -557,7 +557,7 @@ int dlm_recover_locks(struct dlm_ls *ls) void dlm_recovered_lock(struct dlm_rsb *r) { - DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_print_rsb(r);); + DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_dump_rsb(r);); r->res_recover_locks_count--; if (!r->res_recover_locks_count) { -- GitLab From 08867605e1d5f575685aa2b5bf575aba3d996758 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 22 Aug 2006 11:03:57 -0400 Subject: [PATCH 0202/1619] [GFS2] Fix to list_del in lops.c A list_del should have been a list_del_init in lops.c which was resulting in incorrect status returns from list_empty(). Signed-off-by: Steven Whitheouse --- fs/gfs2/lops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 04bceb75ff2..82dfc96c4f5 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -638,7 +638,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) gfs2_log_lock(sdp); bd1 = list_entry(started.next, struct gfs2_bufdata, bd_le.le_list); - list_del(&bd1->bd_le.le_list); + list_del_init(&bd1->bd_le.le_list); sdp->sd_log_num_databuf--; bh = bd1->bd_bh; if (bh) { -- GitLab From b8e1aabf218a2037d9d6a3256c33fc6ef96ac44c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 22 Aug 2006 16:25:50 -0400 Subject: [PATCH 0203/1619] [GFS2] Another list_del bug Another case where list_del should be list_del_init. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 2 +- fs/gfs2/rgrp.c | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 82dfc96c4f5..08de8b7fb31 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -737,7 +737,7 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) while (!list_empty(head)) { bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); - list_del(&bd->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); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 4e0357dc838..84fcc1bfaf1 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -857,8 +857,7 @@ static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp) 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; + for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg; x++, rgd = gfs2_rgrpd_get_next(rgd)) /* Do Nothing */; @@ -909,9 +908,8 @@ static int get_local_rgrp(struct gfs2_inode *ip) 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); + 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)) @@ -934,8 +932,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) begin = rgd = forward_rgrp_get(sdp); for (;;) { - error = gfs2_glock_nq_init(rgd->rd_gl, - LM_ST_EXCLUSIVE, flags, + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, &al->al_rgd_gh); switch (error) { case 0: -- GitLab From 10948eb4eddea6750a3b27f77bec423d844e6726 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Wed, 23 Aug 2006 09:49:31 +0100 Subject: [PATCH 0204/1619] [DLM] preserve lksb address in user conversions This patch fixes bz#203444 where the LKSB was lost during userland conversion operations Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 712438513cc..7ffbe8090de 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3683,6 +3683,7 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, ua->castaddr = ua_tmp->castaddr; ua->bastparam = ua_tmp->bastparam; ua->bastaddr = ua_tmp->bastaddr; + ua->user_lksb = ua_tmp->user_lksb; ua->old_mode = lkb->lkb_grmode; error = set_lock_args(mode, &ua->lksb, flags, 0, 0, FAKE_USER_AST, ua, -- GitLab From c059f70e357af1adcfc1a9294e44cdd945adb841 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Wed, 23 Aug 2006 10:24:03 +0100 Subject: [PATCH 0205/1619] [DLM] down conversion clearing flags Oh, and here's (hopefully) the last of these ua_tmp patches. I think I've caught all the paths now. Sorry it didn't make the last one. Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 7ffbe8090de..6dcd475826c 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3765,6 +3765,7 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, ua = (struct dlm_user_args *)lkb->lkb_astparam; ua->castparam = ua_tmp->castparam; + ua->user_lksb = ua_tmp->user_lksb; error = set_unlock_args(flags, ua, &args); if (error) -- GitLab From 32f105a123804c7882d447f013aeb3530b4d63c0 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 23 Aug 2006 16:07:31 -0400 Subject: [PATCH 0206/1619] [DLM] down conversion clearing flags The down-conversion optimization was resulting in the lkb flags being cleared because the stub message reply had no flags value set. Copy the current flags into the stub message so they'll be copied back into the lkb as part of processing the fake reply. Also add an assertion to catch this error more directly if it exists elsewhere. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/ast.c | 1 + fs/dlm/dlm_internal.h | 2 ++ fs/dlm/lock.c | 9 ++++----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index a211330cbc4..f91d39cb1e0 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -38,6 +38,7 @@ void dlm_add_ast(struct dlm_lkb *lkb, int type) dlm_user_add_ast(lkb, type); return; } + DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb);); spin_lock(&ast_queue_lock); if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index da750998669..1e5cd67e1b7 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -91,6 +91,8 @@ struct dlm_mhandle; } \ } +#define DLM_FAKE_USER_AST ERR_PTR(-EINVAL) + struct dlm_direntry { struct list_head list; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 6dcd475826c..67247f0b508 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -86,8 +86,6 @@ 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); -#define FAKE_USER_AST (void*)0xff00ff00 - /* * Lock compatibilty matrix - thanks Steve * UN = Unlocked state. Not really a state, used as a flag @@ -2195,6 +2193,7 @@ static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) if (!error && down_conversion(lkb)) { remove_from_waiters(lkb); r->res_ls->ls_stub_ms.m_result = 0; + r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags; __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms); } @@ -3615,7 +3614,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, lock and that lkb_astparam is the dlm_user_args structure. */ error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid, - FAKE_USER_AST, ua, FAKE_USER_AST, &args); + DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args); lkb->lkb_flags |= DLM_IFL_USER; ua->old_mode = DLM_LOCK_IV; @@ -3686,8 +3685,8 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, ua->user_lksb = ua_tmp->user_lksb; ua->old_mode = lkb->lkb_grmode; - error = set_lock_args(mode, &ua->lksb, flags, 0, 0, FAKE_USER_AST, ua, - FAKE_USER_AST, &args); + error = set_lock_args(mode, &ua->lksb, flags, 0, 0, DLM_FAKE_USER_AST, + ua, DLM_FAKE_USER_AST, &args); if (error) goto out_put; -- GitLab From f5888750aad219bec42f3f28354eb230d1a47b89 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 23 Aug 2006 12:50:54 -0500 Subject: [PATCH 0207/1619] [DLM] sequence number missing in not_ready reply When a status reply is sent for a lockspace that doesn't yet exist, the message sequence number from the sender was not being copied into the reply causing the sender to ignore the reply. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/rcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 64ba4929f90..518239a8b1e 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -388,6 +388,7 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) rc->rc_header.h_cmd = DLM_RCOM; rc->rc_type = DLM_RCOM_STATUS_REPLY; + rc->rc_id = rc_in->rc_id; rc->rc_result = -ESRCH; dlm_rcom_out(rc); -- GitLab From 233e515f4062f99569c24f00ad7429a860b23db4 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 23 Aug 2006 16:05:44 -0500 Subject: [PATCH 0208/1619] [DLM] recover_locks not clearing NEW_MASTER flag When there are no locks on a resource, the recover_locks() function fails to clear the NEW_MASTER flag by going directly to out, missing the line that clears the flag. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/recover.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index 528a2a0fa32..a5e6d184872 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -473,22 +473,11 @@ static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head) 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 0; - return 1; -} - 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_dump_rsb(r);); -- GitLab From 166afccd71fbb7bd758ab9fc770eef4924081077 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 24 Aug 2006 15:59:40 -0400 Subject: [PATCH 0209/1619] [GFS2] Tidy up error handling in gfs2_releasepage() This should clarify the logic in gfs2_releasepage() relating to error handling as well as making the response to errors a bit more graceful. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 4c59cb11099..48720421c79 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -683,6 +683,10 @@ static void stuck_releasepage(struct buffer_head *bh) struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; struct gfs2_bufdata *bd = bh->b_private; struct gfs2_glock *gl; +static unsigned limit = 0; + + if (limit++ > 3) + return; fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", @@ -736,28 +740,24 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; struct buffer_head *bh, *head; struct gfs2_bufdata *bd; - unsigned long t; + unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ; 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; + if (!atomic_read(&aspace->i_writecount)) + return 0; + + if (time_after_eq(jiffies, t)) { + stuck_releasepage(bh); + /* should we withdraw here? */ + return 0; } - return 0; + yield(); } gfs2_assert_warn(sdp, !buffer_pinned(bh)); @@ -773,8 +773,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) } bh = bh->b_this_page; - } - while (bh != head); + } while (bh != head); out: return try_to_free_buffers(page); -- GitLab From a2242db0906445491d9ac50bfa756b0de0a25d45 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 24 Aug 2006 17:03:05 -0400 Subject: [PATCH 0210/1619] [GFS2] Speed up scanning of glocks I noticed the gfs2_scand seemed to be taking a lot of CPU, so in order to cut that down a bit, here is a patch. Firstly the type of a glock is a constant during its lifetime, so that its possible to check this without needing locking. I've moved the (common) case of testing for an inode glock outside of the glmutex lock. Also there was a mutex left over from when the glock cache was master of the inode cache. That isn't required any more so I've removed that too. There is probably scope for further speed ups in the future in this area. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 24 +++++------------------- fs/gfs2/incore.h | 1 - fs/gfs2/ops_fstype.c | 1 - 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a5e16e53999..005788fb361 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -150,12 +150,9 @@ static void kill_glock(struct kref *kref) 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; - mutex_lock(&sdp->sd_invalidate_inodes_mutex); - write_lock(&bucket->hb_lock); if (kref_put(&gl->gl_ref, kill_glock)) { list_del_init(&gl->gl_list); @@ -166,8 +163,7 @@ int gfs2_glock_put(struct gfs2_glock *gl) goto out; } write_unlock(&bucket->hb_lock); - out: - mutex_unlock(&sdp->sd_invalidate_inodes_mutex); +out: return rv; } @@ -1964,19 +1960,18 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, static void scan_glock(struct gfs2_glock *gl) { + if (gl->gl_ops == &gfs2_inode_glops) + goto out; + if (gfs2_glmutex_trylock(gl)) { - if (gl->gl_ops == &gfs2_inode_glops) - goto out; if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) goto out_schedule; -out: gfs2_glmutex_unlock(gl); } - +out: gfs2_glock_put(gl); - return; out_schedule: @@ -2070,16 +2065,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) 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() */ - - mutex_lock(&sdp->sd_invalidate_inodes_mutex); invalidate_inodes(sdp->sd_vfs); - mutex_unlock(&sdp->sd_invalidate_inodes_mutex); msleep(10); } } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e98c14f30da..78d3cb511eb 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -507,7 +507,6 @@ struct gfs2_sbd { struct gfs2_holder sd_live_gh; struct gfs2_glock *sd_rename_gl; struct gfs2_glock *sd_trans_gl; - struct mutex sd_invalidate_inodes_mutex; /* Inode Stuff */ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 444000968cf..c66067c84bc 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -63,7 +63,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_reclaim_list); spin_lock_init(&sdp->sd_reclaim_lock); init_waitqueue_head(&sdp->sd_reclaim_wq); - mutex_init(&sdp->sd_invalidate_inodes_mutex); mutex_init(&sdp->sd_inum_mutex); spin_lock_init(&sdp->sd_statfs_spin); -- GitLab From 5dc39fe621ead2fa2a0439a686be4df185861eae Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 24 Aug 2006 14:47:17 -0500 Subject: [PATCH 0211/1619] [GFS2] Fix journal off-by-one error log_refund() incorrectly assumed that if a transaction had been touched, it always committed buffers to the incore log. Thus, when you got around to flushing the log, you would need one more block than you committed, to account for the header. So it automatically set reserved to 1, which had the effect of making sdp->sd_log_blks_reserved one greater when you got to gfs2_log_flush(). However, if you don't actually commit anything to the incore log between flushes, you don't need the header, because you aren't writing anything out. With this patch, log_refund() only increments reservered to account for the header if something has been committed since the last flush. Signed-off-by: Benjamin E. Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index a591fb8fae2..af728cb3b32 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -509,7 +509,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) { - unsigned int reserved = 1; + unsigned int reserved = 0; unsigned int old; gfs2_log_lock(sdp); @@ -524,6 +524,8 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) if (sdp->sd_log_commited_revoke) reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, sizeof(uint64_t)); + if (reserved) + reserved++; old = sdp->sd_log_blks_free; sdp->sd_log_blks_free += tr->tr_reserved - -- GitLab From 5f88f1ea16a2fb5f125505053d1bfb7901a88c64 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 24 Aug 2006 14:47:20 -0500 Subject: [PATCH 0212/1619] [DLM] add new lockspace to list ealier When a new lockspace was being created, the recoverd thread was being started for it before the lockspace was added to the global list of lockspaces. The new thread was looking up the lockspace in the global list and sometimes not finding it due to the race with the original thread adding it to the list. We need to add the lockspace to the global list before starting the thread instead of after, and if the new thread can't find the lockspace for some reason, it should return an error. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lockspace.c | 13 +++++++------ fs/dlm/recoverd.c | 4 ++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 7adaad53fc3..ff83f80e43e 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -488,16 +488,17 @@ static int new_lockspace(char *name, int namelen, void **lockspace, down_write(&ls->ls_in_recovery); + spin_lock(&lslist_lock); + list_add(&ls->ls_list, &lslist); + spin_unlock(&lslist_lock); + + /* needs to find ls in lslist */ 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); @@ -519,11 +520,11 @@ static int new_lockspace(char *name, int namelen, void **lockspace, kobject_unregister(&ls->ls_kobj); out_del: dlm_delete_debug_file(ls); + dlm_recoverd_stop(ls); + out_rcomfree: 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); diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index eac8e9fa67f..362e3eff4dc 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -234,6 +234,10 @@ static int dlm_recoverd(void *arg) struct dlm_ls *ls; ls = dlm_find_lockspace_local(arg); + if (!ls) { + log_print("dlm_recoverd: no lockspace %p", arg); + return -1; + } while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); -- GitLab From 8638460540749ddb1beca9e9a68d655a6fe6df65 Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Fri, 25 Aug 2006 11:13:37 -0500 Subject: [PATCH 0213/1619] [GFS2] Allow mounting of gfs2 and gfs2meta at the same time This patch allows the simultaneous mounting of gfs2meta and gfs2 filesystems. A restriction however is that a gfs2meta fs may only be mounted if its corresponding gfs2 filesystem is also mounted. Also, a gfs2 filesystem cannot be unmounted before its gfs2meta filesystem. Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 6 ++ fs/gfs2/incore.h | 2 + fs/gfs2/ops_fstype.c | 147 ++++++++++++++++++++++++++++++++++++++++++- fs/gfs2/ops_super.c | 3 + 4 files changed, 155 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 005788fb361..ef713dbff60 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1165,7 +1165,13 @@ static void add_to_queue(struct gfs2_holder *gh) existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner); if (existing) { print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); + printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid); + printk(KERN_INFO "lock type : %d lock state : %d\n", + existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state); print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid); + printk(KERN_INFO "lock type : %d lock state : %d\n", + gl->gl_name.ln_type, gl->gl_state); BUG(); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 78d3cb511eb..77f0903d2f3 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -472,6 +472,7 @@ enum { struct gfs2_sbd { struct super_block *sd_vfs; + struct super_block *sd_vfs_meta; struct kobject sd_kobj; unsigned long sd_flags; /* SDF_... */ struct gfs2_sb sd_sb; @@ -652,6 +653,7 @@ struct gfs2_sbd { /* Debugging crud */ unsigned long sd_last_warning; + struct vfsmount *sd_gfs2mnt; }; #endif /* __INCORE_DOT_H__ */ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c66067c84bc..e5a91ead250 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include "gfs2.h" @@ -813,7 +815,138 @@ static int fill_super(struct super_block *sb, void *data, int silent) static int gfs2_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, fill_super, mnt); + struct super_block *sb; + struct gfs2_sbd *sdp; + int error = get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); + if (error) + goto out; + sb = mnt->mnt_sb; + sdp = (struct gfs2_sbd*)sb->s_fs_info; + sdp->sd_gfs2mnt = mnt; +out: + return error; +} + +static int fill_super_meta(struct super_block *sb, struct super_block *new, + void *data, int silent) +{ + struct gfs2_sbd *sdp = sb->s_fs_info; + struct inode *inode; + int error = 0; + + new->s_fs_info = sdp; + sdp->sd_vfs_meta = sb; + + init_vfs(new, SDF_NOATIME); + + /* Get the master inode */ + inode = igrab(sdp->sd_master_dir); + + new->s_root = d_alloc_root(inode); + if (!new->s_root) { + fs_err(sdp, "can't get root dentry\n"); + error = -ENOMEM; + iput(inode); + } + new->s_root->d_op = &gfs2_dops; + + return error; +} +static int set_bdev_super(struct super_block *s, void *data) +{ + s->s_bdev = data; + s->s_dev = s->s_bdev->bd_dev; + return 0; +} + +static int test_bdev_super(struct super_block *s, void *data) +{ + return (void *)s->s_bdev == data; +} + +static struct super_block* get_gfs2_sb(const char *dev_name) +{ + struct kstat stat; + struct nameidata nd; + struct file_system_type *fstype; + struct super_block *sb = NULL, *s; + struct list_head *l; + int error; + + error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); + if (error) { + printk(KERN_WARNING "GFS2: path_lookup on %s returned error\n", + dev_name); + goto out; + } + error = vfs_getattr(nd.mnt, nd.dentry, &stat); + + fstype = get_fs_type("gfs2"); + list_for_each(l, &fstype->fs_supers) { + s = list_entry(l, struct super_block, s_instances); + if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) || + (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) { + sb = s; + goto free_nd; + } + } + + printk(KERN_WARNING "GFS2: Unrecognized block device or " + "mount point %s", dev_name); + +free_nd: + path_release(&nd); +out: + return sb; +} + +static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +{ + int error = 0; + struct super_block *sb = NULL, *new; + struct gfs2_sbd *sdp; + char *gfs2mnt = NULL; + + sb = get_gfs2_sb(dev_name); + if (!sb) { + printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); + error = -ENOENT; + goto error; + } + sdp = (struct gfs2_sbd*) sb->s_fs_info; + if (sdp->sd_vfs_meta) { + printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n"); + error = -EBUSY; + goto error; + } + mutex_lock(&sb->s_bdev->bd_mount_mutex); + new = sget(fs_type, test_bdev_super, set_bdev_super, sb->s_bdev); + mutex_unlock(&sb->s_bdev->bd_mount_mutex); + if (IS_ERR(new)) { + error = PTR_ERR(new); + goto error; + } + module_put(fs_type->owner); + new->s_flags = flags; + strlcpy(new->s_id, sb->s_id, sizeof(new->s_id)); + sb_set_blocksize(new, sb->s_blocksize); + error = fill_super_meta(sb, new, data, flags & MS_SILENT ? 1 : 0); + if (error) { + up_write(&new->s_umount); + deactivate_super(new); + goto error; + } + + new->s_flags |= MS_ACTIVE; + + /* Grab a reference to the gfs2 mount point */ + atomic_inc(&sdp->sd_gfs2mnt->mnt_count); + return simple_set_mnt(mnt, new); +error: + if (gfs2mnt) + kfree(gfs2mnt); + return error; } static void gfs2_kill_sb(struct super_block *sb) @@ -821,6 +954,14 @@ static void gfs2_kill_sb(struct super_block *sb) kill_block_super(sb); } +static void gfs2_kill_sb_meta(struct super_block *sb) +{ + struct gfs2_sbd *sdp = sb->s_fs_info; + generic_shutdown_super(sb); + sdp->sd_vfs_meta = NULL; + atomic_dec(&sdp->sd_gfs2mnt->mnt_count); +} + struct file_system_type gfs2_fs_type = { .name = "gfs2", .fs_flags = FS_REQUIRES_DEV, @@ -832,8 +973,8 @@ struct file_system_type gfs2_fs_type = { struct file_system_type gfs2meta_fs_type = { .name = "gfs2meta", .fs_flags = FS_REQUIRES_DEV, - .get_sb = gfs2_get_sb, - .kill_sb = gfs2_kill_sb, + .get_sb = gfs2_get_sb_meta, + .kill_sb = gfs2_kill_sb_meta, .owner = THIS_MODULE, }; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 2e392c994ab..18ed18c729e 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -78,6 +78,9 @@ static void gfs2_put_super(struct super_block *sb) if (!sdp) return; + if (!strncmp(sb->s_type->name, "gfs2meta", 8)) + return; /* meta fs. don't do nothin' */ + /* Unfreeze the filesystem, if we need to */ mutex_lock(&sdp->sd_freeze_lock); -- GitLab From 8fb4b536e7b9dbaf7a6b8204e887b92a14e4352c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Aug 2006 09:30:00 -0400 Subject: [PATCH 0214/1619] [GFS2] Make glock operations const For all the usual reasons of enforcing correctness and potentially reducing code size, this patch makes the glock operations const. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 30 +++++++++++++++--------------- fs/gfs2/glock.h | 6 +++--- fs/gfs2/glops.c | 18 +++++++++--------- fs/gfs2/glops.h | 18 +++++++++--------- fs/gfs2/incore.h | 4 ++-- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index ef713dbff60..709e6e0914f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -253,7 +253,7 @@ static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, */ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, - struct gfs2_glock_operations *glops, int create, + const struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp) { struct lm_lockname name; @@ -480,7 +480,7 @@ 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; + const struct gfs2_glock_operations *glops = gl->gl_ops; if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { if (list_empty(&gl->gl_holders)) { @@ -535,7 +535,7 @@ static int rq_promote(struct gfs2_holder *gh) static int rq_demote(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_glock_operations *glops = gl->gl_ops; + const struct gfs2_glock_operations *glops = gl->gl_ops; if (!list_empty(&gl->gl_holders)) return 1; @@ -805,7 +805,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) 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; + const 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; @@ -915,7 +915,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) 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; + const 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); @@ -960,7 +960,7 @@ void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags) 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; + const struct gfs2_glock_operations *glops = gl->gl_ops; struct gfs2_holder *gh = gl->gl_req_gh; clear_bit(GLF_PREFETCH, &gl->gl_flags); @@ -1010,7 +1010,7 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) void gfs2_glock_drop_th(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_glock_operations *glops = gl->gl_ops; + const struct gfs2_glock_operations *glops = gl->gl_ops; unsigned int ret; gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); @@ -1081,7 +1081,7 @@ 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; + const struct gfs2_glock_operations *glops = gl->gl_ops; if (test_bit(HIF_ABORTED, &gh->gh_iflags)) return -EIO; @@ -1294,7 +1294,7 @@ int gfs2_glock_wait(struct gfs2_holder *gh) void gfs2_glock_dq(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_glock_operations *glops = gl->gl_ops; + const struct gfs2_glock_operations *glops = gl->gl_ops; if (gh->gh_flags & GL_SYNC) set_bit(GLF_SYNC, &gl->gl_flags); @@ -1339,7 +1339,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh) static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags) { - struct gfs2_glock_operations *glops = gl->gl_ops; + const struct gfs2_glock_operations *glops = gl->gl_ops; spin_lock(&gl->gl_spin); @@ -1365,7 +1365,7 @@ static void greedy_work(void *data) struct greedy *gr = data; struct gfs2_holder *gh = &gr->gr_gh; struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_glock_operations *glops = gl->gl_ops; + const struct gfs2_glock_operations *glops = gl->gl_ops; clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); @@ -1447,8 +1447,8 @@ 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) + const struct gfs2_glock_operations *glops, + unsigned int state, int flags, struct gfs2_holder *gh) { struct gfs2_glock *gl; int error; @@ -1645,7 +1645,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, + const struct gfs2_glock_operations *glops, unsigned int state, int flags) { struct gfs2_glock *gl; @@ -1827,7 +1827,7 @@ void gfs2_iopen_go_callback(struct gfs2_glock *io_gl, unsigned int state) static int demote_ok(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_glock_operations *glops = gl->gl_ops; + const struct gfs2_glock_operations *glops = gl->gl_ops; int demote = 1; if (test_bit(GLF_STICKY, &gl->gl_flags)) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index fdf58db44ae..12bdbfee4dd 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -75,7 +75,7 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) } int gfs2_glock_get(struct gfs2_sbd *sdp, - uint64_t number, struct gfs2_glock_operations *glops, + uint64_t number, const 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); @@ -97,7 +97,7 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time); 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, + uint64_t number, const 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); @@ -105,7 +105,7 @@ 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, + const struct gfs2_glock_operations *glops, unsigned int state, int flags); void gfs2_glock_inode_squish(struct inode *inode); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 75d4c50cff4..0c92c52fc92 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -493,13 +493,13 @@ static int quota_go_demote_ok(struct gfs2_glock *gl) return !atomic_read(&gl->gl_lvb_count); } -struct gfs2_glock_operations gfs2_meta_glops = { +const struct gfs2_glock_operations gfs2_meta_glops = { .go_xmote_th = gfs2_glock_xmote_th, .go_drop_th = gfs2_glock_drop_th, .go_type = LM_TYPE_META }; -struct gfs2_glock_operations gfs2_inode_glops = { +const 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, @@ -512,7 +512,7 @@ struct gfs2_glock_operations gfs2_inode_glops = { .go_type = LM_TYPE_INODE }; -struct gfs2_glock_operations gfs2_rgrp_glops = { +const 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, @@ -523,40 +523,40 @@ struct gfs2_glock_operations gfs2_rgrp_glops = { .go_type = LM_TYPE_RGRP }; -struct gfs2_glock_operations gfs2_trans_glops = { +const 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 = { +const 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 = { +const 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 = { +const 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 = { +const 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 = { +const 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 index 5c1e9491024..9409f0a7b47 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h @@ -10,14 +10,14 @@ #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; +extern const struct gfs2_glock_operations gfs2_meta_glops; +extern const struct gfs2_glock_operations gfs2_inode_glops; +extern const struct gfs2_glock_operations gfs2_rgrp_glops; +extern const struct gfs2_glock_operations gfs2_trans_glops; +extern const struct gfs2_glock_operations gfs2_iopen_glops; +extern const struct gfs2_glock_operations gfs2_flock_glops; +extern const struct gfs2_glock_operations gfs2_nondisk_glops; +extern const struct gfs2_glock_operations gfs2_quota_glops; +extern const struct gfs2_glock_operations gfs2_journal_glops; #endif /* __GLOPS_DOT_H__ */ diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 77f0903d2f3..38098ac292a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -130,7 +130,7 @@ struct gfs2_glock_operations { 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; + const int go_type; }; enum { @@ -189,7 +189,7 @@ struct gfs2_glock { struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */ struct list_head gl_waiters3; /* HIF_PROMOTE */ - struct gfs2_glock_operations *gl_ops; + const struct gfs2_glock_operations *gl_ops; struct gfs2_holder *gl_req_gh; gfs2_glop_bh_t gl_req_bh; -- GitLab From 5e2b0613ed9f9641937dd5948051631249447c57 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Aug 2006 09:38:30 -0400 Subject: [PATCH 0215/1619] [GFS2] Remove unused code from glock layer Remove the unused sync feature from glocks. This is currently done by calling the required functions to sync pages/blocks directly so this code isn't needed. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 8 -------- fs/gfs2/glock.h | 1 - fs/gfs2/glops.c | 2 -- fs/gfs2/incore.h | 1 - 4 files changed, 12 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 709e6e0914f..c3dde856082 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1296,9 +1296,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh) struct gfs2_glock *gl = gh->gh_gl; const struct gfs2_glock_operations *glops = gl->gl_ops; - 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); @@ -1313,11 +1310,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh) 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); diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 12bdbfee4dd..75fad634ced 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -24,7 +24,6 @@ #define GL_SKIP 0x00000100 #define GL_ATIME 0x00000200 #define GL_NOCACHE 0x00000400 -#define GL_SYNC 0x00000800 #define GL_NOCANCEL 0x00001000 #define GL_AOP 0x00004000 #define GL_DUMP 0x00008000 diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 0c92c52fc92..1a30fa9bec7 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -137,7 +137,6 @@ static void meta_go_sync(struct gfs2_glock *gl, int flags) gfs2_ail_empty_gl(gl); } - clear_bit(GLF_SYNC, &gl->gl_flags); } /** @@ -236,7 +235,6 @@ static void inode_go_sync(struct gfs2_glock *gl, int flags) gfs2_ail_empty_gl(gl); } - clear_bit(GLF_SYNC, &gl->gl_flags); } /** diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 38098ac292a..362c2422d50 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -167,7 +167,6 @@ enum { GLF_LOCK = 1, GLF_STICKY = 2, GLF_PREFETCH = 3, - GLF_SYNC = 4, GLF_DIRTY = 5, GLF_SKIP_WAITERS2 = 6, GLF_GREEDY = 7, -- GitLab From ec45d9f583b3663f90a7c5c559fd13e6e4c56ad5 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Aug 2006 10:36:52 -0400 Subject: [PATCH 0216/1619] [GFS2] Use slab properly with glocks We can take advantage of the slab allocator to ensure that all the list heads and the spinlock (plus one or two other fields) are initialised by slab to speed up allocation of glocks. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 39 ++++++++++++--------------------------- fs/gfs2/main.c | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index c3dde856082..4a2e90dc1d0 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -278,31 +278,22 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, if (!gl) return -ENOMEM; - memset(gl, 0, sizeof(struct gfs2_glock)); - - INIT_LIST_HEAD(&gl->gl_list); + gl->gl_flags = 0; gl->gl_name = name; kref_init(&gl->gl_ref); - - spin_lock_init(&gl->gl_spin); - gl->gl_state = LM_ST_UNLOCKED; gl->gl_owner = NULL; gl->gl_ip = 0; - 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_req_gh = NULL; + gl->gl_req_bh = NULL; + gl->gl_vn = 0; + gl->gl_stamp = jiffies; + gl->gl_object = NULL; gl->gl_bucket = bucket; - INIT_LIST_HEAD(&gl->gl_reclaim); - gl->gl_sbd = sdp; - + gl->gl_aspace = NULL; 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. */ @@ -334,13 +325,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, return 0; - fail_aspace: +fail_aspace: if (gl->gl_aspace) gfs2_aspace_put(gl->gl_aspace); - - fail: +fail: kmem_cache_free(gfs2_glock_cachep, gl); - return error; } @@ -495,9 +484,7 @@ static int rq_promote(struct gfs2_holder *gh) gfs2_reclaim_glock(sdp); } - glops->go_xmote_th(gl, gh->gh_state, - gh->gh_flags); - + glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags); spin_lock(&gl->gl_spin); } return 1; @@ -935,8 +922,7 @@ void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags) gfs2_glock_hold(gl); gl->gl_req_bh = xmote_bh; - lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, - lck_flags); + 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; @@ -1019,8 +1005,7 @@ void gfs2_glock_drop_th(struct gfs2_glock *gl) if (gl->gl_state == LM_ST_EXCLUSIVE) { if (glops->go_sync) - glops->go_sync(gl, - DIO_METADATA | DIO_DATA | DIO_RELEASE); + glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE); } gfs2_glock_hold(gl); diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c112943ee8c..dccc4f6f503 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "gfs2.h" #include "lm_interface.h" @@ -35,6 +36,25 @@ 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) +{ + struct gfs2_glock *gl = foo; + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + INIT_LIST_HEAD(&gl->gl_list); + spin_lock_init(&gl->gl_spin); + 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_lvb = NULL; + atomic_set(&gl->gl_lvb_count, 0); + INIT_LIST_HEAD(&gl->gl_reclaim); + INIT_LIST_HEAD(&gl->gl_ail_list); + atomic_set(&gl->gl_ail_count, 0); + } +} + /** * init_gfs2_fs - Register GFS2 as a filesystem * @@ -55,7 +75,8 @@ static int __init init_gfs2_fs(void) gfs2_glock_cachep = kmem_cache_create("gfs2_glock", sizeof(struct gfs2_glock), - 0, 0, NULL, NULL); + 0, 0, + gfs2_init_glock_once, NULL); if (!gfs2_glock_cachep) goto fail; -- GitLab From d6a53727683bbf993c01ab49b45e0eac17e23df1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Aug 2006 11:16:23 -0400 Subject: [PATCH 0217/1619] [GFS2] Use const on glock lookup key Use const for the glock name which is being used as a lookup key in the glock hash table. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 4a2e90dc1d0..679cb836ed0 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -83,7 +83,7 @@ static inline int relaxed_state_ok(unsigned int actual, unsigned requested, * Returns: The number of the corresponding hash bucket */ -static unsigned int gl_hash(struct lm_lockname *name) +static unsigned int gl_hash(const struct lm_lockname *name) { unsigned int h; @@ -200,7 +200,7 @@ static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head) */ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, - struct lm_lockname *name) + const struct lm_lockname *name) { struct gfs2_glock *gl; @@ -227,7 +227,7 @@ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, */ static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, - struct lm_lockname *name) + const struct lm_lockname *name) { struct gfs2_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(name)]; struct gfs2_glock *gl; -- GitLab From 899be4d3b7e00bf364d84c1c8cfe8bbbd1e3507b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Aug 2006 12:50:28 -0400 Subject: [PATCH 0218/1619] [GFS2] Add superblock into key for glock lookups This adds the superblock as a key for glock lookups. Since the glocks are already stored in a per-superblock table, this has no effect at the moment. Later on this will change though. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 679cb836ed0..b8ccb27906e 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -200,6 +200,7 @@ static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head) */ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, + const struct gfs2_sbd *sdp, const struct lm_lockname *name) { struct gfs2_glock *gl; @@ -209,6 +210,8 @@ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, continue; if (!lm_name_equal(&gl->gl_name, name)) continue; + if (gl->gl_sbd != sdp) + continue; kref_get(&gl->gl_ref); @@ -233,7 +236,7 @@ static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, struct gfs2_glock *gl; read_lock(&bucket->hb_lock); - gl = search_bucket(bucket, name); + gl = search_bucket(bucket, sdp, name); read_unlock(&bucket->hb_lock); return gl; @@ -266,7 +269,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, bucket = &sdp->sd_gl_hash[gl_hash(&name)]; read_lock(&bucket->hb_lock); - gl = search_bucket(bucket, &name); + gl = search_bucket(bucket, sdp, &name); read_unlock(&bucket->hb_lock); if (gl || !create) { @@ -311,7 +314,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, goto fail_aspace; write_lock(&bucket->hb_lock); - tmp = search_bucket(bucket, &name); + tmp = search_bucket(bucket, sdp, &name); if (tmp) { write_unlock(&bucket->hb_lock); glock_free(gl); -- GitLab From 623d93555c8884768db65ffc11509c93e50dd4db Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 31 Aug 2006 12:14:44 -0400 Subject: [PATCH 0219/1619] [GFS2] Fix releasepage bug (fixes direct i/o writes) This patch fixes three main bugs. Firstly the direct i/o get_block was returning the wrong return code in certain cases. Secondly, the GFS2's releasepage function was not dealing with cases when clean, ordered buffers were found still queued on a transaction (which can happen depending on the ordering of journal flushes). Thirdly, the journaling code itself needed altering to take account of the after effects of removing the clean ordered buffers from the transactions before a journal flush. The releasepage bug did also show up under "normal" buffered i/o as well, so its not just a fix for direct i/o. In fact its not normally used in the direct i/o path at all, except when flushing existing buffers after performing a direct i/o write, but that was the code path that led us to spot this. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 11 +++++++++++ fs/gfs2/ops_address.c | 33 +++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 08de8b7fb31..0ec38b39909 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -592,6 +592,17 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) gfs2_log_lock(sdp); if (n++ > num) break; + } else if (!bd1->bd_bh) { + total_dbuf--; + sdp->sd_log_num_databuf--; + list_del_init(&bd1->bd_le.le_list); + if (bd1 == bd2) { + bd2 = NULL; + bd2 = list_prepare_entry(bd2, + &sdp->sd_log_le_databuf, + bd_le.le_list); + } + kmem_cache_free(gfs2_bufdata_cachep, bd1); } } gfs2_log_unlock(sdp); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 48720421c79..0de7a952363 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -118,6 +118,25 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, return error; } +static int get_block_direct(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + int new = 0; + u64 dblock; + int error, boundary; + + error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); + if (error) + return error; + + if (dblock) { + map_bh(bh_result, inode->i_sb, dblock); + if (boundary) + set_buffer_boundary(bh_result); + } + + return 0; +} /** * gfs2_writepage - Write complete page * @page: Page to write @@ -661,7 +680,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, rv = blockdev_direct_IO_own_locking(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, - gfs2_get_block, NULL); + get_block_direct, NULL); out: gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); @@ -724,7 +743,7 @@ static unsigned limit = 0; } /** - * gfs2_aspace_releasepage - free the metadata associated with a page + * gfs2_releasepage - free the metadata associated with a page * @page: the page that's being released * @gfp_mask: passed from Linux VFS, ignored by us * @@ -761,16 +780,22 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) } gfs2_assert_warn(sdp, !buffer_pinned(bh)); + gfs2_assert_warn(sdp, !buffer_dirty(bh)); + gfs2_log_lock(sdp); 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); + bd->bd_bh = NULL; + if (!list_empty(&bd->bd_le.le_list)) + bd = NULL; bh->b_private = NULL; } + gfs2_log_unlock(sdp); + if (bd) + kmem_cache_free(gfs2_bufdata_cachep, bd); bh = bh->b_this_page; } while (bh != head); -- GitLab From c6e6f0ba8fc1dea99c7bd020916f24d533b62697 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 30 Aug 2006 10:50:18 -0500 Subject: [PATCH 0220/1619] [DLM] force removal of user lockspace Check if the FORCEFREE flag has been provided from user space. If so, set the force option to dlm_release_lockspace() so that any remaining locks will be freed. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/user.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 494d00ac014..c37e93e4f2d 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -325,7 +325,7 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) { dlm_lockspace_t *lockspace; struct dlm_ls *ls; - int error; + int error, force = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -341,6 +341,9 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) } kfree(ls->ls_device.name); + if (params->flags & DLM_USER_LSFLG_FORCEFREE) + force = 2; + lockspace = ls->ls_local_handle; /* dlm_release_lockspace waits for references to go to zero, @@ -348,8 +351,8 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) before the release will procede */ dlm_put_lockspace(ls); - error = dlm_release_lockspace(lockspace, 0); -out: + error = dlm_release_lockspace(lockspace, force); + out: return error; } -- GitLab From e9fc2aa091ab8fa46e60d4c9d06a89305c441652 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 1 Sep 2006 11:05:15 -0400 Subject: [PATCH 0221/1619] [GFS2] Update copyright, tidy up incore.h As per comments from Jan Engelhardt this updates the copyright message to say "version" in full rather than "v.2". Also incore.h has been updated to remove forward structure declarations which are not required. The gfs2_quota_lvb structure has now had endianess annotations added to it. Also quota.c has been updated so that we now store the lvb data locally in endian independant format to avoid needing a structure in host endianess too. As a result the endianess conversions are done as required at various points and thus the conversion routines in lvb.[ch] are no longer required. I've moved the one remaining constant in lvb.h thats used into lm.h and removed the unused lvb.[ch]. I have not changed the HIF_ constants. That is left to a later patch which I hope will unify the gh_flags and gh_iflags fields of the struct gfs2_holder. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 2 +- fs/gfs2/acl.c | 2 +- fs/gfs2/acl.h | 2 +- fs/gfs2/bmap.c | 2 +- fs/gfs2/bmap.h | 2 +- fs/gfs2/daemon.c | 2 +- fs/gfs2/daemon.h | 2 +- fs/gfs2/dir.c | 2 +- fs/gfs2/dir.h | 2 +- fs/gfs2/eaops.c | 2 +- fs/gfs2/eaops.h | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/eattr.h | 2 +- fs/gfs2/format.h | 2 +- fs/gfs2/gfs2.h | 2 +- fs/gfs2/glock.c | 2 +- fs/gfs2/glock.h | 2 +- fs/gfs2/glops.c | 2 +- fs/gfs2/glops.h | 2 +- fs/gfs2/incore.h | 28 +++++------------- fs/gfs2/inode.c | 2 +- fs/gfs2/inode.h | 2 +- fs/gfs2/lm.c | 3 +- fs/gfs2/lm.h | 4 ++- fs/gfs2/lm_interface.h | 2 +- fs/gfs2/locking.c | 2 +- fs/gfs2/locking/dlm/lock.c | 2 +- fs/gfs2/locking/dlm/lock_dlm.h | 2 +- fs/gfs2/locking/dlm/main.c | 2 +- fs/gfs2/locking/dlm/mount.c | 2 +- fs/gfs2/locking/dlm/plock.c | 2 +- fs/gfs2/locking/dlm/sysfs.c | 2 +- fs/gfs2/locking/dlm/thread.c | 2 +- fs/gfs2/locking/nolock/main.c | 2 +- fs/gfs2/log.c | 2 +- fs/gfs2/log.h | 2 +- fs/gfs2/lops.c | 2 +- fs/gfs2/lops.h | 2 +- fs/gfs2/lvb.c | 45 ---------------------------- fs/gfs2/lvb.h | 19 ------------ fs/gfs2/main.c | 2 +- fs/gfs2/meta_io.c | 2 +- fs/gfs2/meta_io.h | 2 +- fs/gfs2/mount.c | 2 +- fs/gfs2/mount.h | 2 +- fs/gfs2/ondisk.c | 2 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/ops_address.h | 2 +- fs/gfs2/ops_dentry.c | 2 +- fs/gfs2/ops_dentry.h | 2 +- fs/gfs2/ops_export.c | 2 +- fs/gfs2/ops_export.h | 2 +- fs/gfs2/ops_file.c | 2 +- fs/gfs2/ops_file.h | 2 +- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/ops_fstype.h | 2 +- fs/gfs2/ops_inode.c | 2 +- fs/gfs2/ops_inode.h | 2 +- fs/gfs2/ops_super.c | 2 +- fs/gfs2/ops_super.h | 2 +- fs/gfs2/ops_vm.c | 2 +- fs/gfs2/ops_vm.h | 2 +- fs/gfs2/quota.c | 54 +++++++++++++++++----------------- fs/gfs2/quota.h | 2 +- fs/gfs2/recovery.c | 2 +- fs/gfs2/recovery.h | 2 +- fs/gfs2/rgrp.c | 2 +- fs/gfs2/rgrp.h | 2 +- fs/gfs2/super.c | 2 +- fs/gfs2/super.h | 2 +- fs/gfs2/sys.c | 2 +- fs/gfs2/sys.h | 2 +- fs/gfs2/trans.c | 2 +- fs/gfs2/trans.h | 2 +- fs/gfs2/util.c | 2 +- fs/gfs2/util.h | 2 +- 76 files changed, 109 insertions(+), 184 deletions(-) delete mode 100644 fs/gfs2/lvb.c delete mode 100644 fs/gfs2/lvb.h diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index b92852b6662..e3f1ada643a 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o 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 \ + glops.o inode.o lm.o log.o lops.o locking.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 quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 39931784150..60c98c0314a 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index 067105786ea..5856ba76468 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __ACL_DOT_H__ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index d20d41e1c02..913c0e5490e 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 1a265412f7e..ab0157c5ed0 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __BMAP_DOT_H__ diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index 1453605c8f3..a2a07c41845 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h index aa93eb6f668..801007120fb 100644 --- a/fs/gfs2/daemon.h +++ b/fs/gfs2/daemon.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __DAEMON_DOT_H__ diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 76a23c172ee..7b8a38eaa41 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ /* diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 173403095eb..366a5571648 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __DIR_DOT_H__ diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 3ace242f2b1..3b8749c2273 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 3dece17e311..1c27700ee8b 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __EAOPS_DOT_H__ diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 96736932260..9081822ce80 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index ae199692e51..7b0291f99fd 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __EATTR_DOT_H__ diff --git a/fs/gfs2/format.h b/fs/gfs2/format.h index 239f0c3553f..9acbf457ee5 100644 --- a/fs/gfs2/format.h +++ b/fs/gfs2/format.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __FORMAT_DOT_H__ diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h index 6edbd551a4c..3bb11c0f8b5 100644 --- a/fs/gfs2/gfs2.h +++ b/fs/gfs2/gfs2.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __GFS2_DOT_H__ diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index b8ccb27906e..989f4f78f9b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 75fad634ced..07a8d02a234 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __GLOCK_DOT_H__ diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 1a30fa9bec7..8e1d8ee68e2 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h index 9409f0a7b47..ba943e47366 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __GLOPS_DOT_H__ diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 362c2422d50..06f5ec6ebf7 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __INCORE_DOT_H__ @@ -22,24 +22,12 @@ struct gfs2_log_operations; struct gfs2_log_element; -struct gfs2_bitmap; -struct gfs2_rgrpd; -struct gfs2_bufdata; -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_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; @@ -215,8 +203,8 @@ struct gfs2_glock { struct gfs2_alloc { /* Quota stuff */ - struct gfs2_quota_data *al_qd[4]; - struct gfs2_holder al_qd_ghs[4]; + struct gfs2_quota_data *al_qd[2*MAXQUOTAS]; + struct gfs2_holder al_qd_ghs[2*MAXQUOTAS]; unsigned int al_qd_num; u32 al_requested; /* Filled in by caller of gfs2_inplace_reserve() */ @@ -305,11 +293,11 @@ enum { }; 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 */ + __be32 qb_magic; + u32 __pad; + __be64 qb_limit; /* Hard limit of # blocks to alloc */ + __be64 qb_warn; /* Warn user when alloc is above this # */ + __be64 qb_value; /* Current # blocks allocated */ }; struct gfs2_quota_data { diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9fb340984b2..decb0cf8569 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 8bb8b559bce..32015d89f24 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __INODE_DOT_H__ diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index f45c0ffd1c3..1a9e75da19d 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include @@ -22,7 +22,6 @@ #include "lm.h" #include "super.h" #include "util.h" -#include "lvb.h" /** * gfs2_lm_mount - mount a locking protocol diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h index e821101d19c..15839aaa4ca 100644 --- a/fs/gfs2/lm.h +++ b/fs/gfs2/lm.h @@ -4,12 +4,14 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __LM_DOT_H__ #define __LM_DOT_H__ +#define GFS2_MIN_LVB_SIZE 32 + 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); diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index 1da95a55f76..e1e89d92a8d 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __LM_INTERFACE_DOT_H__ diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index ded1ef6c81e..11c4068105c 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index f769eac1a34..2d81d90db09 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include "lock_dlm.h" diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 530c2f54258..94106349853 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef LOCK_DLM_DOT_H diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 870a1cd99f5..2194b1d5b5e 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 3caeafc02a1..f279385774b 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include "lock_dlm.h" diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 1acb2519f43..263636b390f 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -3,7 +3,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index 0d8bd0806db..82bef017f94 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 489235b2edb..0b4be102e17 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include "lock_dlm.h" diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 748aa5d3364..95a29914730 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index af728cb3b32..45ea3ec6f77 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 8cfd0f1d29f..80764e388bb 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __LOG_DOT_H__ diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 0ec38b39909..e2c2582c8f6 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 8a1029d3d38..2e3365c2b10 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __LOPS_DOT_H__ diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c deleted file mode 100644 index e88e9cce14e..00000000000 --- a/fs/gfs2/lvb.c +++ /dev/null @@ -1,45 +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 "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); - -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); -} - - diff --git a/fs/gfs2/lvb.h b/fs/gfs2/lvb.h deleted file mode 100644 index 1b1a8b75219..00000000000 --- a/fs/gfs2/lvb.h +++ /dev/null @@ -1,19 +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 __LVB_DOT_H__ -#define __LVB_DOT_H__ - -#define GFS2_MIN_LVB_SIZE 32 - -void gfs2_quota_lvb_in(struct gfs2_quota_lvb *qb, char *lvb); -void gfs2_quota_lvb_out(struct gfs2_quota_lvb *qb, char *lvb); - -#endif /* __LVB_DOT_H__ */ - diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index dccc4f6f503..b46f400705a 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 502864b2419..03850b64c07 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 951814e8627..4ddc936aae1 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __DIO_DOT_H__ diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 0d4b230785a..b66027827aa 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h index 2eb14722144..8a21897b63e 100644 --- a/fs/gfs2/mount.h +++ b/fs/gfs2/mount.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __MOUNT_DOT_H__ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 39c7f0345fc..03881f9870f 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 0de7a952363..21ae9e4f0f6 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index dfc3dda6de1..6c07aa2bd98 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_ADDRESS_DOT_H__ diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index fd55979ec42..a1ba1ec8eef 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h index 1b6e75c0a4a..e7b05e5c62e 100644 --- a/fs/gfs2/ops_dentry.h +++ b/fs/gfs2/ops_dentry.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_DENTRY_DOT_H__ diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 6354f4799e6..c94cbc8b6ef 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h index 09fc077657d..d52c2d93010 100644 --- a/fs/gfs2/ops_export.h +++ b/fs/gfs2/ops_export.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_EXPORT_DOT_H__ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 145a29fa4ea..07a0c861ac4 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index 46302b51393..064e52c3066 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_FILE_DOT_H__ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index e5a91ead250..46f910e29bf 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h index 622f5760d6b..b85ecce3ca6 100644 --- a/fs/gfs2/ops_fstype.h +++ b/fs/gfs2/ops_fstype.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_FSTYPE_DOT_H__ diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 8fb7c5c9a7c..1786a485acc 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index 930aaae9137..6f4b54783d2 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_INODE_DOT_H__ diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 18ed18c729e..6ced7124037 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h index a15ccc27611..cbc4f73e9a9 100644 --- a/fs/gfs2/ops_super.h +++ b/fs/gfs2/ops_super.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_SUPER_DOT_H__ diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 875a769444a..451f48d62e5 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h index 077cffcd408..d5ba4b9c50f 100644 --- a/fs/gfs2/ops_vm.h +++ b/fs/gfs2/ops_vm.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __OPS_VM_DOT_H__ diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 3ca65c37c35..be87983a20a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ /* @@ -52,7 +52,6 @@ #include "glock.h" #include "glops.h" #include "log.h" -#include "lvb.h" #include "meta_io.h" #include "quota.h" #include "rgrp.h" @@ -586,7 +585,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, struct page *page; void *kaddr; __be64 *ptr; - u64 value; + s64 value; int err = -EIO; page = grab_cache_page(mapping, index); @@ -627,7 +626,8 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, kaddr = kmap_atomic(page, KM_USER0); ptr = (__be64 *)(kaddr + offset); - value = *ptr = cpu_to_be64(be64_to_cpu(*ptr) + change); + value = (s64)be64_to_cpu(*ptr) + change; + *ptr = cpu_to_be64(value); flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); err = 0; @@ -761,6 +761,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, char buf[sizeof(struct gfs2_quota)]; struct file_ra_state ra_state; int error; + struct gfs2_quota_lvb *qlvb; file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping); restart: @@ -768,9 +769,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, if (error) return error; - gfs2_quota_lvb_in(&qd->qd_qb, qd->qd_gl->gl_lvb); + qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; - if (force_refresh || qd->qd_qb.qb_magic != GFS2_MAGIC) { + if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { loff_t pos; gfs2_glock_dq_uninit(q_gh); error = gfs2_glock_nq_init(qd->qd_gl, @@ -779,9 +780,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, if (error) return error; - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_SHARED, 0, - &i_gh); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); if (error) goto fail; @@ -794,15 +793,15 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, 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); + qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; + qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); + qlvb->__pad = 0; + qlvb->qb_limit = cpu_to_be64(q.qu_limit); + qlvb->qb_warn = cpu_to_be64(q.qu_warn); + qlvb->qb_value = cpu_to_be64(q.qu_value); + qd->qd_qb = *qlvb; if (gfs2_glock_is_blocking(qd->qd_gl)) { gfs2_glock_dq_uninit(q_gh); @@ -877,13 +876,14 @@ static int need_sync(struct gfs2_quota_data *qd) if (value < 0) do_sync = 0; - else if (qd->qd_qb.qb_value >= (int64_t)qd->qd_qb.qb_limit) + else if ((s64)be64_to_cpu(qd->qd_qb.qb_value) >= + (s64)be64_to_cpu(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) + value += (s64)be64_to_cpu(qd->qd_qb.qb_value); + if (value < (int64_t)be64_to_cpu(qd->qd_qb.qb_limit)) do_sync = 0; } @@ -959,17 +959,17 @@ int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags)))) continue; - value = qd->qd_qb.qb_value; + value = (s64)be64_to_cpu(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) { + if (be64_to_cpu(qd->qd_qb.qb_limit) && (int64_t)be64_to_cpu(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 && + } else if (be64_to_cpu(qd->qd_qb.qb_warn) && + (int64_t)be64_to_cpu(qd->qd_qb.qb_warn) < value && time_after_eq(jiffies, qd->qd_last_warn + gfs2_tune_get(sdp, gt_quota_warn_period) * HZ)) { @@ -1088,9 +1088,9 @@ int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, 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; + q->qu_limit = be64_to_cpu(qd->qd_qb.qb_limit); + q->qu_warn = be64_to_cpu(qd->qd_qb.qb_warn); + q->qu_value = be64_to_cpu(qd->qd_qb.qb_value); spin_lock(&sdp->sd_quota_spin); q->qu_value += qd->qd_change; diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index af05492f964..6702a56d49b 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __QUOTA_DOT_H__ diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 8fe518cfb3d..acafe4b4d6f 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index ac0f1d6ce45..bed1a7857f6 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __RECOVERY_DOT_H__ diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 84fcc1bfaf1..62d0a84df98 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 14600944d18..f94761bf346 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __RGRP_DOT_H__ diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 3c318a9e8a8..2cf2802fc92 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index df249523040..4a6ce958274 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __SUPER_DOT_H__ diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 3c4cb455890..3ffa88506c4 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h index c46a700e801..f8c01b50bfb 100644 --- a/fs/gfs2/sys.h +++ b/fs/gfs2/sys.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __SYS_DOT_H__ diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 05e0b72d56f..8e18e634cbe 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index fbef3f5a99e..9e3ce84f610 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __TRANS_DOT_H__ diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 39e67b1ec70..2852431764c 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #include diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 8216d28bd81..60b370365ee 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -4,7 +4,7 @@ * * 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. + * of the GNU General Public License version 2. */ #ifndef __UTIL_DOT_H__ -- GitLab From 5029996547a9f3988459e11955c13259495308ef Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 09:49:55 -0400 Subject: [PATCH 0222/1619] [GFS2] Tidy up locking code As per Jan Engelhardt's second email, this removes some unused code, and fixes up indenting in various places. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 53 +++++++++--------------------------- fs/gfs2/glock.h | 6 ++-- fs/gfs2/lm.c | 62 ++++++++++++------------------------------ fs/gfs2/lm.h | 25 ++++++++--------- fs/gfs2/lm_interface.h | 2 -- fs/gfs2/locking.c | 10 ++----- fs/gfs2/main.c | 2 -- 7 files changed, 47 insertions(+), 113 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 989f4f78f9b..fac271f390b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -300,8 +300,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, /* 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) { + if (glops == &gfs2_inode_glops || glops == &gfs2_rgrp_glops) { gl->gl_aspace = gfs2_aspace_get(sdp); if (!gl->gl_aspace) { error = -ENOMEM; @@ -820,13 +819,11 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) 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; 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); @@ -842,7 +839,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) spin_unlock(&gl->gl_spin); if (ret & LM_OUT_CANCELED) - handle_callback(gl, LM_ST_UNLOCKED); /* Lame */ + handle_callback(gl, LM_ST_UNLOCKED); } else if (ret & LM_OUT_CANCELED) { spin_lock(&gl->gl_spin); @@ -916,11 +913,8 @@ void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags) 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); - } + if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync) + glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE); gfs2_glock_hold(gl); gl->gl_req_bh = xmote_bh; @@ -1006,10 +1000,8 @@ void gfs2_glock_drop_th(struct gfs2_glock *gl) 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); - } + if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync) + glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE); gfs2_glock_hold(gl); gl->gl_req_bh = drop_bh; @@ -1041,9 +1033,8 @@ static void do_cancels(struct gfs2_holder *gh) 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))) { + 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); @@ -1323,10 +1314,8 @@ static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, 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) || + 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); @@ -1690,19 +1679,6 @@ 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); - - 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); -} -#endif /* 0 */ - static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, unsigned int state) { @@ -1813,8 +1789,7 @@ static int demote_ok(struct gfs2_glock *gl) 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 + + 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); @@ -1872,8 +1847,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) if (gfs2_glmutex_trylock(gl)) { if (queue_empty(gl, &gl->gl_holders) && - gl->gl_state != LM_ST_UNLOCKED && - demote_ok(gl)) + gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) handle_callback(gl, LM_ST_UNLOCKED); gfs2_glmutex_unlock(gl); } @@ -2036,8 +2010,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) cont = 0; for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - if (examine_bucket(clear_glock, sdp, - &sdp->sd_gl_hash[x])) + if (examine_bucket(clear_glock, sdp, &sdp->sd_gl_hash[x])) cont = 1; if (!wait || !cont) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 07a8d02a234..1a90a1983be 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -51,17 +51,17 @@ static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl) { - return (gl->gl_state == LM_ST_EXCLUSIVE); + 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); + 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); + return gl->gl_state == LM_ST_SHARED; } static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 1a9e75da19d..fb918c7de65 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -124,10 +124,8 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) 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 + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = sdp->sd_lockstruct.ls_ops->lm_get_lock( sdp->sd_lockstruct.ls_lockspace, name, lockp); return error; @@ -143,12 +141,9 @@ 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, + int ret = 0; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state, req_state, flags); return ret; } @@ -156,10 +151,8 @@ unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, lm_lock_t *lock, 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 + int ret = 0; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state); return ret; } @@ -172,10 +165,8 @@ 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) { - int error; - if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = -EIO; - else + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); return error; } @@ -186,50 +177,33 @@ 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) { - int error; - if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = -EIO; - else + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = sdp->sd_lockstruct.ls_ops->lm_plock_get( - sdp->sd_lockstruct.ls_lockspace, - name, file, fl); + 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 + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = sdp->sd_lockstruct.ls_ops->lm_plock( - sdp->sd_lockstruct.ls_lockspace, - name, file, cmd, fl); + 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 + int error = -EIO; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = sdp->sd_lockstruct.ls_ops->lm_punlock( - sdp->sd_lockstruct.ls_lockspace, - name, file, fl); + sdp->sd_lockstruct.ls_lockspace, name, file, fl); return error; } diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h index 15839aaa4ca..dbef88852ef 100644 --- a/fs/gfs2/lm.h +++ b/fs/gfs2/lm.h @@ -16,9 +16,9 @@ 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); + __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, @@ -28,16 +28,13 @@ 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); -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); +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 index e1e89d92a8d..0bf4c276e0f 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -260,8 +260,6 @@ struct lm_lockstruct { int ls_flags; }; -void __init gfs2_init_lmh(void); - /* * Lock module bottom interface. A lock module makes itself available to GFS * with these functions. diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 11c4068105c..fce2001e5e2 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -27,8 +27,8 @@ struct lmh_wrapper { /* 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 mutex lmh_lock; +static LIST_HEAD(lmh_list); +static DEFINE_MUTEX(lmh_lock); /** * gfs2_register_lockproto - Register a low-level locking protocol @@ -180,12 +180,6 @@ void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct) mutex_unlock(&lmh_lock); } -void __init gfs2_init_lmh(void) -{ - mutex_init(&lmh_lock); - INIT_LIST_HEAD(&lmh_list); -} - EXPORT_SYMBOL_GPL(gfs2_register_lockproto); EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto); diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index b46f400705a..143fda727a9 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -65,8 +65,6 @@ static int __init init_gfs2_fs(void) { int error; - gfs2_init_lmh(); - error = gfs2_sys_init(); if (error) return error; -- GitLab From 75d3b817a0b48425da921052955cc58f20bbab52 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 11:41:31 -0400 Subject: [PATCH 0223/1619] [GFS2] Tidy up bmap/inode code As per Jan Engelhardt's third set of comments, this make various code style changes and moves the structures from format.h into super.c, which was the only place that format.h was actually used. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 16 +++++++--------- fs/gfs2/format.h | 21 --------------------- fs/gfs2/glops.c | 12 +++++------- fs/gfs2/inode.c | 47 +++++++++++++++++++++-------------------------- fs/gfs2/super.c | 9 ++++++++- 5 files changed, 41 insertions(+), 64 deletions(-) delete mode 100644 fs/gfs2/format.h diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 913c0e5490e..b75a2f93dad 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -94,7 +94,7 @@ static 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_is_jdata(ip)) + 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); @@ -369,7 +369,7 @@ static inline u64 *metapointer(struct buffer_head *bh, int *boundary, u64 *ptr; *boundary = 0; ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height]; - if (ptr + 1 == (u64*)(bh->b_data + bh->b_size)) + if (ptr + 1 == (u64 *)(bh->b_data + bh->b_size)) *boundary = 1; return ptr; } @@ -456,7 +456,7 @@ static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) goto out; - bsize = (gfs2_is_dir(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) { @@ -554,7 +554,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp); *extlen = 1; - if (bh && !IS_ERR(bh) && *dblock && !*new) { + if (bh != NULL && !IS_ERR(bh) && *dblock != 0 && *new == 0) { u64 tmp_dblock; int tmp_new; unsigned int nptrs; @@ -565,7 +565,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock); if (*dblock + *extlen != tmp_dblock) break; - (*extlen)++; + ++*extlen; } } bmap_unlock(inode, create); @@ -612,10 +612,8 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, 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; + top = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0]; + bottom = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs; } else { error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh); if (error) diff --git a/fs/gfs2/format.h b/fs/gfs2/format.h deleted file mode 100644 index 9acbf457ee5..00000000000 --- a/fs/gfs2/format.h +++ /dev/null @@ -1,21 +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 __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/glops.c b/fs/gfs2/glops.c index 8e1d8ee68e2..d3e7b082a91 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -234,7 +234,6 @@ static void inode_go_sync(struct gfs2_glock *gl, int flags) if (flags & DIO_RELEASE) gfs2_ail_empty_gl(gl); } - } /** @@ -324,12 +323,11 @@ static void inode_go_unlock(struct gfs2_holder *gh) struct gfs2_glock *gl = gh->gh_gl; struct gfs2_inode *ip = gl->gl_object; - if (ip) { - if (test_bit(GLF_DIRTY, &gl->gl_flags)) - gfs2_inode_attr_in(ip); - - gfs2_meta_cache_flush(ip); - } + if (ip == NULL) + return; + if (test_bit(GLF_DIRTY, &gl->gl_flags)) + gfs2_inode_attr_in(ip); + gfs2_meta_cache_flush(ip); } /** diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index decb0cf8569..1aaaaa1cc8c 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -97,15 +97,15 @@ 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; 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; - 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; + (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; + 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) @@ -1213,31 +1213,26 @@ fail: * * Returns: 1 if A > B * -1 if A < B - * 0 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; + const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a; + const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b; + const struct lm_lockname *a = &gh_a->gh_gl->gl_name; + const struct lm_lockname *b = &gh_b->gh_gl->gl_name; 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 1; + if (a->ln_number < b->ln_number) + return -1; + if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE) + return 1; + if (gh_a->gh_state == LM_ST_SHARED && (gh_b->gh_flags & GL_ATIME)) + return 1; - return ret; + return 0; } /** diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 2cf2802fc92..e93066f930c 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -21,7 +21,6 @@ #include "incore.h" #include "bmap.h" #include "dir.h" -#include "format.h" #include "glock.h" #include "glops.h" #include "inode.h" @@ -34,6 +33,14 @@ #include "trans.h" #include "util.h" +static const uint32_t gfs2_old_fs_formats[] = { + 0 +}; + +static const uint32_t gfs2_old_multihost_formats[] = { + 0 +}; + /** * gfs2_tune_init - Fill a gfs2_tune structure with default values * @gt: tune -- GitLab From a91ea69ffd3f8a0b7139bfd44042ab384461e631 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 12:04:26 -0400 Subject: [PATCH 0224/1619] [GFS2] Align all labels against LH side This makes everything consistent. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 14 +++---- fs/gfs2/bmap.c | 39 +++++++------------ fs/gfs2/dir.c | 18 +++------ fs/gfs2/eattr.c | 62 +++++++++++------------------- fs/gfs2/glock.c | 3 +- fs/gfs2/lm.c | 2 +- fs/gfs2/locking/dlm/lock.c | 2 +- fs/gfs2/locking/dlm/mount.c | 10 ++--- fs/gfs2/locking/dlm/thread.c | 2 +- fs/gfs2/meta_io.c | 2 +- fs/gfs2/mount.c | 4 +- fs/gfs2/ops_dentry.c | 16 +++----- fs/gfs2/ops_file.c | 3 +- fs/gfs2/ops_fstype.c | 73 +++++++++++------------------------- fs/gfs2/ops_inode.c | 26 +++---------- fs/gfs2/ops_vm.c | 12 ++---- fs/gfs2/quota.c | 49 ++++++++++-------------- fs/gfs2/super.c | 27 +++++-------- fs/gfs2/sys.c | 10 ++--- 19 files changed, 129 insertions(+), 245 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 60c98c0314a..d846b5ad1d8 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -65,9 +65,8 @@ int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, error = 0; } - out: +out: posix_acl_release(acl); - return error; } @@ -132,18 +131,16 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, error = PTR_ERR(*acl); } - out_kfree: +out_kfree: if (error || !data) kfree(er.er_data); else { *data = er.er_data; *len = er.er_data_len; } - - out: +out: if (error || el == &el_this) brelse(el->el_bh); - return error; } @@ -270,7 +267,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) } else munge_mode(ip, mode); - out: +out: posix_acl_release(acl); kfree(er.er_data); return error; @@ -303,11 +300,10 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) error = gfs2_ea_acl_chmod(ip, &el, attr, data); } - out: +out: posix_acl_release(acl); brelse(el.el_bh); kfree(data); - return error; } diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index b75a2f93dad..bb597839c0c 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -170,12 +170,10 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) gfs2_dinode_out(&ip->i_di, dibh->b_data); - out_brelse: +out_brelse: brelse(dibh); - - out: +out: up_write(&ip->i_rw_mutex); - return error; } @@ -642,9 +640,8 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, break; } - out: +out: brelse(bh); - return error; } @@ -788,15 +785,12 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, gfs2_trans_end(sdp); - out_rg_gunlock: +out_rg_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); - - out_rlist: +out_rlist: gfs2_rlist_free(&rlist); - - out: +out: gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh); - return error; } @@ -868,18 +862,14 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); - out_end_trans: +out_end_trans: gfs2_trans_end(sdp); - - out_ipres: +out_ipres: gfs2_inplace_release(ip); - - out_gunlock_q: +out_gunlock_q: gfs2_quota_unlock(ip); - - out: +out: gfs2_alloc_put(ip); - return error; } @@ -998,9 +988,8 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size) brelse(dibh); - out: +out: gfs2_trans_end(sdp); - return error; } @@ -1035,7 +1024,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, uint64_t size) gfs2_quota_unhold(ip); - out: +out: gfs2_alloc_put(ip); return error; } @@ -1070,11 +1059,9 @@ static int trunc_end(struct gfs2_inode *ip) gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); - out: +out: up_write(&ip->i_rw_mutex); - gfs2_trans_end(sdp); - return error; } diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 7b8a38eaa41..59d0cbcaecf 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1134,9 +1134,8 @@ static int dir_double_exhash(struct gfs2_inode *dip) return error; - fail: +fail: kfree(buf); - return error; } @@ -1890,23 +1889,18 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); - out_end_trans: +out_end_trans: gfs2_trans_end(sdp); - - out_rg_gunlock: +out_rg_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); - - out_rlist: +out_rlist: gfs2_rlist_free(&rlist); gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh); - - out_qs: +out_qs: gfs2_quota_unhold(dip); - - out: +out: gfs2_alloc_put(dip); kfree(ht); - return error; } diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 9081822ce80..5a56e656862 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -107,7 +107,7 @@ static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, return error; - fail: +fail: gfs2_consist_inode(ip); return -EIO; } @@ -152,9 +152,8 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) if (error) break; } - out: +out: brelse(bh); - return error; } @@ -319,9 +318,8 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, gfs2_trans_end(sdp); - out_gunlock: +out_gunlock: gfs2_glock_dq_uninit(&rg_gh); - return error; } @@ -348,12 +346,10 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, gfs2_glock_dq_uninit(&al->al_ri_gh); - out_quota: +out_quota: gfs2_quota_unhold(ip); - - out_alloc: +out_alloc: gfs2_alloc_put(ip); - return error; } @@ -506,9 +502,8 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, brelse(bh[x]); } - out: +out: kfree(bh); - return error; } @@ -747,18 +742,14 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, brelse(dibh); } - out_end_trans: +out_end_trans: gfs2_trans_end(GFS2_SB(&ip->i_inode)); - - out_ipres: +out_ipres: gfs2_inplace_release(ip); - - out_gunlock_q: +out_gunlock_q: gfs2_quota_unlock(ip); - - out: +out: gfs2_alloc_put(ip); - return error; } @@ -884,9 +875,8 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); - out: +out: gfs2_trans_end(GFS2_SB(&ip->i_inode)); - return error; } @@ -1025,9 +1015,8 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (private) ea_set_remove_stuffed(ip, (struct gfs2_ea_location *)private); - out: +out: brelse(indbh); - return error; } @@ -1285,15 +1274,13 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, brelse(bh[x]); } - out: +out: kfree(bh); - return error; - fail: +fail: gfs2_trans_end(sdp); kfree(bh); - return error; } @@ -1442,15 +1429,12 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) gfs2_trans_end(sdp); - out_gunlock: +out_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); - - out_rlist_free: +out_rlist_free: gfs2_rlist_free(&rlist); - - out: +out: brelse(indbh); - return error; } @@ -1494,9 +1478,8 @@ static int ea_dealloc_block(struct gfs2_inode *ip) gfs2_trans_end(sdp); - out_gunlock: +out_gunlock: gfs2_glock_dq_uninit(&al->al_rgd_gh); - return error; } @@ -1534,15 +1517,12 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip) error = ea_dealloc_block(ip); - out_rindex: +out_rindex: gfs2_glock_dq_uninit(&al->al_ri_gh); - - out_quota: +out_quota: gfs2_quota_unhold(ip); - - out_alloc: +out_alloc: gfs2_alloc_put(ip); - return error; } diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index fac271f390b..1c916fedc04 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2179,9 +2179,8 @@ static int dump_glock(struct gfs2_glock *gl) error = 0; - out: +out: spin_unlock(&gl->gl_spin); - return error; } diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index fb918c7de65..e60f95cae6c 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -76,7 +76,7 @@ int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) sdp->sd_args.ar_localcaching = 1; } - out: +out: return error; } diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 2d81d90db09..1f15b6e8b2c 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -437,7 +437,7 @@ static int hold_null_lock(struct gdlm_lock *lp) gdlm_delete_lp(lpn); lpn = NULL; } - out: +out: lp->hold_null = lpn; return error; } diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index f279385774b..82ac00af84a 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -164,13 +164,13 @@ static int gdlm_mount(char *table_name, char *host_data, lockstruct->ls_lvb_size = GDLM_LVB_SIZE; return 0; - out_kobj: +out_kobj: gdlm_kobject_release(ls); - out_thread: +out_thread: gdlm_release_threads(ls); - out_free: +out_free: kfree(ls); - out: +out: return error; } @@ -194,7 +194,7 @@ static void gdlm_unmount(lm_lockspace_t *lockspace) rv = gdlm_release_all_locks(ls); if (rv) log_info("gdlm_unmount: %d stray locks freed", rv); - out: +out: kfree(ls); } diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 0b4be102e17..a782246d666 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -206,7 +206,7 @@ static void process_complete(struct gdlm_lock *lp) if (lp->lksb.sb_flags & DLM_SBF_DEMOTED) set_bit(LFL_NOCACHE, &lp->flags); - out: +out: /* * This is an internal lock_dlm lock */ diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 03850b64c07..3f6da00e2f5 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -756,7 +756,7 @@ void gfs2_meta_ra(struct gfs2_glock *gl, uint64_t dblock, uint32_t extlen) break; } - out: +out: brelse(first_bh); } diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index b66027827aa..257c4a179dc 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -203,11 +203,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) return error; - need_value: +need_value: fs_info(sdp, "need value for option %s\n", o); return -EINVAL; - cant_remount: +cant_remount: fs_info(sdp, "can't remount with option %s\n", o); return -EINVAL; } diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index a1ba1ec8eef..fa6ceffc7d8 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -81,31 +81,27 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) goto fail_gunlock; } - valid_gunlock: +valid_gunlock: gfs2_glock_dq_uninit(&d_gh); - - valid: +valid: dput(parent); return 1; - invalid_gunlock: +invalid_gunlock: gfs2_glock_dq_uninit(&d_gh); - - invalid: +invalid: if (inode && S_ISDIR(inode->i_mode)) { if (have_submounts(dentry)) goto valid; shrink_dcache_parent(dentry); } d_drop(dentry); - dput(parent); return 0; - fail_gunlock: +fail_gunlock: gfs2_glock_dq_uninit(&d_gh); - - fail: +fail: dput(parent); return 0; } diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 07a0c861ac4..53ce7816dc1 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -345,9 +345,8 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) file->f_pos = offset; - out: +out: kfree(fdb); - return error; } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 46f910e29bf..d39314d5dd0 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -173,9 +173,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent) snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto); snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table); - out: +out: kfree(sb); - return error; } @@ -246,22 +245,17 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, 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; } @@ -451,25 +445,20 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) return 0; - fail_recoverd: +fail_recoverd: kthread_stop(sdp->sd_recoverd_process); - - fail_jinode_gh: +fail_jinode_gh: if (!sdp->sd_args.ar_spectator) gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); - - fail_journal_gh: +fail_journal_gh: if (!sdp->sd_args.ar_spectator) gfs2_glock_dq_uninit(&sdp->sd_journal_gh); - - fail_jindex: +fail_jindex: gfs2_jindex_free(sdp); if (jindex) gfs2_glock_dq_uninit(&ji_gh); - - fail: +fail: iput(sdp->sd_jindex); - return error; } @@ -534,14 +523,11 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) fail_qinode: iput(sdp->sd_quota_inode); - fail_rindex: gfs2_clear_rgrpd(sdp); iput(sdp->sd_rindex); - fail_statfs: iput(sdp->sd_statfs_inode); - fail_inum: iput(sdp->sd_inum_inode); fail_journal: @@ -628,27 +614,19 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) return 0; - fail_qc_gh: +fail_qc_gh: gfs2_glock_dq_uninit(&sdp->sd_qc_gh); - - fail_ut_gh: - +fail_ut_gh: gfs2_glock_dq_uninit(&sdp->sd_sc_gh); - - fail_ir_gh: +fail_ir_gh: gfs2_glock_dq_uninit(&sdp->sd_ir_gh); - - fail_qc_i: +fail_qc_i: iput(sdp->sd_qc_inode); - - fail_ut_i: - +fail_ut_i: iput(sdp->sd_sc_inode); - - fail_ir_i: +fail_ir_i: iput(sdp->sd_ir_inode); - - fail: +fail: if (pn) iput(pn); return error; @@ -781,34 +759,26 @@ static int fill_super(struct super_block *sb, void *data, int silent) return 0; - fail_threads: +fail_threads: init_threads(sdp, UNDO); - - fail_per_node: +fail_per_node: init_per_node(sdp, UNDO); - - fail_inodes: +fail_inodes: init_inodes(sdp, UNDO); - - fail_sb: +fail_sb: init_sb(sdp, 0, UNDO); - - fail_locking: +fail_locking: init_locking(sdp, &mount_gh, UNDO); - - fail_lm: +fail_lm: gfs2_gl_hash_clear(sdp, WAIT); gfs2_lm_unmount(sdp); while (invalidate_inodes(sb)) yield(); - - fail_sys: +fail_sys: gfs2_sys_fs_del(sdp); - - fail: +fail: vfree(sdp); sb->s_fs_info = NULL; - return error; } @@ -852,6 +822,7 @@ static int fill_super_meta(struct super_block *sb, struct super_block *new, return error; } + static int set_bdev_super(struct super_block *s, void *data) { s->s_bdev = data; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 1786a485acc..bd9b9957f70 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -228,32 +228,25 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, 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; } @@ -491,13 +484,11 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) gfs2_trans_end(sdp); - out_gunlock: +out_gunlock: gfs2_glock_dq_m(2, ghs); - - out: +out: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); - return error; } @@ -966,15 +957,12 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid); } - out_end_trans: +out_end_trans: gfs2_trans_end(sdp); - - out_gunlock_q: +out_gunlock_q: gfs2_quota_unlock(ip); - - out_alloc: +out_alloc: gfs2_alloc_put(ip); - return error; } @@ -1017,12 +1005,10 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) else error = gfs2_setattr_simple(ip, attr); - out: +out: gfs2_glock_dq_uninit(&i_gh); - if (!error) mark_inode_dirty(inode); - return error; } diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 451f48d62e5..32ec8574ac8 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -115,18 +115,14 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) gfs2_assert_warn(sdp, al->al_alloced); - out_trans: +out_trans: gfs2_trans_end(sdp); - - out_ipres: +out_ipres: gfs2_inplace_release(ip); - - out_gunlock_q: +out_gunlock_q: gfs2_quota_unlock(ip); - - out: +out: gfs2_alloc_put(ip); - return error; } diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index be87983a20a..572b92eac36 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -105,7 +105,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, uint32_t id, return 0; - fail: +fail: kfree(qd); return error; } @@ -199,7 +199,7 @@ static int slot_get(struct gfs2_quota_data *qd) goto fail; - found: +found: for (b = 0; b < 8; b++) if (!(byte & (1 << b))) break; @@ -214,7 +214,7 @@ static int slot_get(struct gfs2_quota_data *qd) return 0; - fail: +fail: qd->qd_slot_count--; spin_unlock(&sdp->sd_quota_spin); return -ENOSPC; @@ -283,10 +283,9 @@ static int bh_get(struct gfs2_quota_data *qd) return 0; - fail_brelse: +fail_brelse: brelse(bh); - - fail: +fail: qd->qd_bh_count--; mutex_unlock(&sdp->sd_quota_mutex); return error; @@ -425,10 +424,9 @@ static int qdsb_get(struct gfs2_sbd *sdp, int user, uint32_t id, int create, return 0; - fail_slot: +fail_slot: slot_put(*qdp); - - fail: +fail: qd_put(*qdp); return error; } @@ -482,10 +480,9 @@ int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) qd++; } - out: +out: if (error) gfs2_quota_unhold(ip); - return error; } @@ -728,26 +725,21 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) error = 0; - out_end_trans: +out_end_trans: gfs2_trans_end(sdp); - - out_ipres: +out_ipres: if (nalloc) gfs2_inplace_release(ip); - - out_alloc: +out_alloc: if (nalloc) gfs2_alloc_put(ip); - - out_gunlock: +out_gunlock: gfs2_glock_dq_uninit(&i_gh); - - out: +out: while (qx--) gfs2_glock_dq_uninit(&ghs[qx]); kfree(ghs); gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); - return error; } @@ -764,7 +756,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_quota_lvb *qlvb; file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping); - restart: +restart: error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); if (error) return error; @@ -812,12 +804,10 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, return 0; - fail_gunlock: +fail_gunlock: gfs2_glock_dq_uninit(&i_gh); - - fail: +fail: gfs2_glock_dq_uninit(q_gh); - return error; } @@ -919,7 +909,7 @@ void gfs2_quota_unlock(struct gfs2_inode *ip) qd_unlock(qda[x]); } - out: +out: gfs2_quota_unhold(ip); } @@ -1098,9 +1088,8 @@ int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, gfs2_glock_dq_uninit(&q_gh); - out: +out: qd_put(qd); - return error; } #endif /* 0 */ @@ -1202,7 +1191,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) return 0; - fail: +fail: gfs2_quota_cleanup(sdp); return error; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index e93066f930c..520266c2044 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -535,7 +535,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) error = gfs2_quota_init(sdp); if (error) - goto fail_unlinked; + goto fail; set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); @@ -543,9 +543,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) return 0; - fail_unlinked: - - fail: +fail: t_gh.gh_flags |= GL_NOCACHE; gfs2_glock_dq_uninit(&t_gh); @@ -625,12 +623,10 @@ int gfs2_statfs_init(struct gfs2_sbd *sdp) brelse(l_bh); } - out_m_bh: +out_m_bh: brelse(m_bh); - - out: +out: gfs2_glock_dq_uninit(&gh); - return 0; } @@ -715,15 +711,12 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) gfs2_trans_end(sdp); - out_bh2: +out_bh2: brelse(l_bh); - - out_bh: +out_bh: brelse(m_bh); - - out: +out: gfs2_glock_dq_uninit(&gh); - return error; } @@ -853,9 +846,8 @@ int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) gfs2_glock_dq_uninit(&ri_gh); - out: +out: kfree(gha); - return error; } @@ -924,7 +916,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, if (error) gfs2_glock_dq_uninit(t_gh); - out: +out: while (!list_empty(&list)) { lfcc = list_entry(list.next, struct lfcc, list); list_del(&lfcc->list); @@ -932,7 +924,6 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, kfree(lfcc); } gfs2_glock_dq_uninit(&ji_gh); - return error; } diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 3ffa88506c4..79199738c38 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -543,15 +543,15 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) return 0; - fail_args: +fail_args: sysfs_remove_group(&sdp->sd_kobj, &args_group); - fail_counters: +fail_counters: sysfs_remove_group(&sdp->sd_kobj, &counters_group); - fail_lockstruct: +fail_lockstruct: sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group); - fail_reg: +fail_reg: kobject_unregister(&sdp->sd_kobj); - fail: +fail: return error; } -- GitLab From cd915493fce912f1bd838ee1250737ecf33b8fae Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 12:49:07 -0400 Subject: [PATCH 0225/1619] [GFS2] Change all types to uX style This makes all fixed size types have consistent names. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 60 ++++++++-------- fs/gfs2/bmap.h | 4 +- fs/gfs2/dir.c | 124 ++++++++++++++++----------------- fs/gfs2/dir.h | 8 +-- fs/gfs2/eattr.c | 56 +++++++-------- fs/gfs2/eattr.h | 6 +- fs/gfs2/glock.c | 8 +-- fs/gfs2/glock.h | 6 +- fs/gfs2/incore.h | 72 +++++++++---------- fs/gfs2/inode.c | 20 +++--- fs/gfs2/lm_interface.h | 2 +- fs/gfs2/locking/dlm/lock.c | 8 +-- fs/gfs2/locking/dlm/lock_dlm.h | 14 ++-- fs/gfs2/locking/dlm/thread.c | 2 +- fs/gfs2/log.c | 18 ++--- fs/gfs2/lops.c | 18 ++--- fs/gfs2/meta_io.c | 18 ++--- fs/gfs2/meta_io.h | 10 +-- fs/gfs2/ops_address.c | 8 +-- fs/gfs2/ops_export.c | 12 ++-- fs/gfs2/ops_file.c | 10 +-- fs/gfs2/ops_inode.c | 12 ++-- fs/gfs2/ops_vm.c | 4 +- fs/gfs2/quota.c | 50 ++++++------- fs/gfs2/quota.h | 14 ++-- fs/gfs2/recovery.c | 16 ++--- fs/gfs2/recovery.h | 4 +- fs/gfs2/rgrp.c | 72 +++++++++---------- fs/gfs2/rgrp.h | 10 +-- fs/gfs2/super.c | 28 ++++---- fs/gfs2/super.h | 2 +- fs/gfs2/sys.c | 4 +- fs/gfs2/trans.c | 6 +- fs/gfs2/trans.h | 4 +- fs/gfs2/util.c | 2 +- fs/gfs2/util.h | 14 ++-- 36 files changed, 363 insertions(+), 363 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index bb597839c0c..a97ad74d880 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -38,8 +38,8 @@ struct metapath { }; 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, + struct buffer_head *bh, u64 *top, + u64 *bottom, unsigned int height, void *data); struct strip_mine { @@ -58,7 +58,7 @@ struct strip_mine { */ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, - uint64_t block, struct page *page) + u64 block, struct page *page) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *inode = &ip->i_inode; @@ -121,7 +121,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) { struct buffer_head *bh, *dibh; - uint64_t block = 0; + u64 block = 0; int isdir = gfs2_is_dir(ip); int error; @@ -161,7 +161,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); if (ip->i_di.di_size) { - *(uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)) = + *(u64 *)(dibh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block); ip->i_di.di_blocks++; } @@ -190,10 +190,10 @@ out: * Returns: the height the tree should be */ -static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size) +static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - uint64_t *arr; + u64 *arr; unsigned int max, height; if (ip->i_di.di_size > size) @@ -336,11 +336,11 @@ static int build_height(struct inode *inode, unsigned height) * */ -static void find_metapath(struct gfs2_inode *ip, uint64_t block, +static void find_metapath(struct gfs2_inode *ip, u64 block, struct metapath *mp) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - uint64_t b = block; + u64 b = block; unsigned int i; for (i = ip->i_di.di_height; i--;) @@ -390,10 +390,10 @@ static inline u64 *metapointer(struct buffer_head *bh, int *boundary, static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, unsigned int height, struct metapath *mp, int create, - int *new, uint64_t *block) + int *new, u64 *block) { int boundary; - uint64_t *ptr = metapointer(bh, &boundary, height, mp); + u64 *ptr = metapointer(bh, &boundary, height, mp); if (*ptr) { *block = be64_to_cpu(*ptr); @@ -594,13 +594,13 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi 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, + u64 block, int first, block_call_t bc, void *data) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *bh = NULL; - uint64_t *top, *bottom; - uint64_t bn; + u64 *top, *bottom; + u64 bn; int error; int mh_size = sizeof(struct gfs2_meta_header); @@ -617,10 +617,10 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, if (error) return error; - top = (uint64_t *)(bh->b_data + mh_size) + + top = (u64 *)(bh->b_data + mh_size) + ((first) ? mp->mp_list[height] : 0); - bottom = (uint64_t *)(bh->b_data + mh_size) + sdp->sd_inptrs; + bottom = (u64 *)(bh->b_data + mh_size) + sdp->sd_inptrs; } error = bc(ip, dibh, bh, top, bottom, height, data); @@ -659,15 +659,15 @@ out: */ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, - struct buffer_head *bh, uint64_t *top, uint64_t *bottom, + struct buffer_head *bh, u64 *top, u64 *bottom, unsigned int height, void *data) { 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; - uint64_t *p; + u64 bn, bstart; + u32 blen; + u64 *p; unsigned int rg_blocks = 0; int metadata; unsigned int revokes = 0; @@ -804,7 +804,7 @@ out: * Returns: errno */ -static int do_grow(struct gfs2_inode *ip, uint64_t size) +static int do_grow(struct gfs2_inode *ip, u64 size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; @@ -949,7 +949,7 @@ unlock: return err; } -static int trunc_start(struct gfs2_inode *ip, uint64_t size) +static int trunc_start(struct gfs2_inode *ip, u64 size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; @@ -974,7 +974,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size) error = 1; } else { - if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) + if (size & (u64)(sdp->sd_sb.sb_bsize - 1)) error = gfs2_block_truncate_page(ip->i_inode.i_mapping); if (!error) { @@ -993,10 +993,10 @@ out: return error; } -static int trunc_dealloc(struct gfs2_inode *ip, uint64_t size) +static int trunc_dealloc(struct gfs2_inode *ip, u64 size) { unsigned int height = ip->i_di.di_height; - uint64_t lblock; + u64 lblock; struct metapath mp; int error; @@ -1076,7 +1076,7 @@ out: * Returns: errno */ -static int do_shrink(struct gfs2_inode *ip, uint64_t size) +static int do_shrink(struct gfs2_inode *ip, u64 size) { int error; @@ -1104,7 +1104,7 @@ static int do_shrink(struct gfs2_inode *ip, uint64_t size) * Returns: errno */ -int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size) +int gfs2_truncatei(struct gfs2_inode *ip, u64 size) { int error; @@ -1172,12 +1172,12 @@ void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, * Returns: errno */ -int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, +int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, unsigned int len, int *alloc_required) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - uint64_t lblock, lblock_stop, dblock; - uint32_t extlen; + u64 lblock, lblock_stop, dblock; + u32 extlen; int new = 0; int error = 0; diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index ab0157c5ed0..cb3b624fea3 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -14,14 +14,14 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); -int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size); +int gfs2_truncatei(struct gfs2_inode *ip, u64 size); 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, +int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, unsigned int len, int *alloc_required); #endif /* __BMAP_DOT_H__ */ diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 59d0cbcaecf..2023dc4ea30 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -78,15 +78,15 @@ #define IS_LEAF 1 /* Hashed (leaf) directory */ #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ -#define gfs2_disk_hash2offset(h) (((uint64_t)(h)) >> 1) -#define gfs2_dir_offset2hash(p) ((uint32_t)(((uint64_t)(p)) << 1)) +#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) +#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) typedef int (*leaf_call_t) (struct gfs2_inode *dip, - uint32_t index, uint32_t len, uint64_t leaf_no, + u32 index, u32 len, u64 leaf_no, void *data); -int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, +int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) { struct buffer_head *bh; @@ -99,7 +99,7 @@ int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, return 0; } -static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, uint64_t block, +static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) { struct buffer_head *bh; @@ -151,12 +151,12 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, * Returns: The number of bytes correctly written or error code */ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, - uint64_t offset, unsigned int size) + u64 offset, unsigned int size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; - uint64_t lblock, dblock; - uint32_t extlen = 0; + u64 lblock, dblock; + u32 extlen = 0; unsigned int o; int copied = 0; int error = 0; @@ -271,11 +271,11 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, * Returns: The amount of data actually copied or the error */ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, - uint64_t offset, unsigned int size) + u64 offset, unsigned int size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - uint64_t lblock, dblock; - uint32_t extlen = 0; + u64 lblock, dblock; + u32 extlen = 0; unsigned int o; int copied = 0; int error = 0; @@ -581,7 +581,7 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, { struct gfs2_dirent *tmp, *cur; char *bh_end; - uint16_t cur_rec_len; + u16 cur_rec_len; cur = *dent; bh_end = bh->b_data + bh->b_size; @@ -630,7 +630,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) { - uint16_t cur_rec_len, prev_rec_len; + u16 cur_rec_len, prev_rec_len; if (!cur->de_inum.no_addr) { gfs2_consist_inode(dip); @@ -698,7 +698,7 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, return gfs2_init_dirent(inode, dent, name, bh); } -static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, +static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, struct buffer_head **bhp) { int error; @@ -721,16 +721,16 @@ static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, * Returns: 0 on success, error code otherwise */ -static int get_leaf_nr(struct gfs2_inode *dip, uint32_t index, - uint64_t *leaf_out) +static int get_leaf_nr(struct gfs2_inode *dip, u32 index, + u64 *leaf_out) { - uint64_t leaf_no; + u64 leaf_no; int error; error = gfs2_dir_read_data(dip, (char *)&leaf_no, - index * sizeof(uint64_t), - sizeof(uint64_t)); - if (error != sizeof(uint64_t)) + index * sizeof(u64), + sizeof(u64)); + if (error != sizeof(u64)) return (error < 0) ? error : -EIO; *leaf_out = be64_to_cpu(leaf_no); @@ -738,10 +738,10 @@ static int get_leaf_nr(struct gfs2_inode *dip, uint32_t index, return 0; } -static int get_first_leaf(struct gfs2_inode *dip, uint32_t index, +static int get_first_leaf(struct gfs2_inode *dip, u32 index, struct buffer_head **bh_out) { - uint64_t leaf_no; + u64 leaf_no; int error; error = get_leaf_nr(dip, index, &leaf_no); @@ -847,8 +847,8 @@ static int dir_make_exhash(struct inode *inode) struct buffer_head *bh, *dibh; struct gfs2_leaf *leaf; int y; - uint32_t x; - uint64_t *lp, bn; + u32 x; + u64 *lp, bn; int error; error = gfs2_meta_inode_buffer(dip, &dibh); @@ -904,7 +904,7 @@ static int dir_make_exhash(struct inode *inode) gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - lp = (uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)); + lp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode)); for (x = sdp->sd_hash_ptrs; x--; lp++) *lp = cpu_to_be64(bn); @@ -939,9 +939,9 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) struct buffer_head *nbh, *obh, *dibh; struct gfs2_leaf *nleaf, *oleaf; struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new; - uint32_t start, len, half_len, divider; - uint64_t bn, *lp, leaf_no; - uint32_t index; + u32 start, len, half_len, divider; + u64 bn, *lp, leaf_no; + u32 index; int x, moved = 0; int error; @@ -985,14 +985,14 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) /* Change the pointers. Don't bother distinguishing stuffed from non-stuffed. This code is complicated enough already. */ - lp = kmalloc(half_len * sizeof(uint64_t), GFP_NOFS | __GFP_NOFAIL); + lp = kmalloc(half_len * sizeof(u64), GFP_NOFS | __GFP_NOFAIL); /* Change the pointers */ for (x = 0; x < half_len; x++) lp[x] = cpu_to_be64(bn); - error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), - half_len * sizeof(uint64_t)); - if (error != half_len * sizeof(uint64_t)) { + error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64), + half_len * sizeof(u64)); + if (error != half_len * sizeof(u64)) { if (error >= 0) error = -EIO; goto fail_lpfree; @@ -1077,15 +1077,15 @@ static int dir_double_exhash(struct gfs2_inode *dip) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *dibh; - uint32_t hsize; - uint64_t *buf; - uint64_t *from, *to; - uint64_t block; + u32 hsize; + u64 *buf; + u64 *from, *to; + u64 block; int x; int error = 0; hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + if (hsize * sizeof(u64) != dip->i_di.di_size) { gfs2_consist_inode(dip); return -EIO; } @@ -1105,7 +1105,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) } from = buf; - to = (uint64_t *)((char *)buf + sdp->sd_hash_bsize); + to = (u64 *)((char *)buf + sdp->sd_hash_bsize); for (x = sdp->sd_hash_ptrs; x--; from++) { *to++ = *from; /* No endianess worries */ @@ -1153,7 +1153,7 @@ fail: static int compare_dents(const void *a, const void *b) { struct gfs2_dirent *dent_a, *dent_b; - uint32_t hash_a, hash_b; + u32 hash_a, hash_b; int ret = 0; dent_a = *(struct gfs2_dirent **)a; @@ -1201,14 +1201,14 @@ static int compare_dents(const void *a, const void *b) * Returns: errno, >0 on exception from filldir */ -static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, +static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, void *opaque, gfs2_filldir_t filldir, - const struct gfs2_dirent **darr, uint32_t entries, + const struct gfs2_dirent **darr, u32 entries, int *copied) { const struct gfs2_dirent *dent, *dent_next; struct gfs2_inum inum; - uint64_t off, off_next; + u64 off, off_next; unsigned int x, y; int run = 0; int error = 0; @@ -1346,21 +1346,21 @@ out: * Returns: errno */ -static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, +static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, gfs2_filldir_t filldir) { 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; - uint64_t *lp; + u32 hsize, len = 0; + u32 ht_offset, lp_offset, ht_offset_cur = -1; + u32 hash, index; + u64 *lp; int copied = 0; int error = 0; unsigned depth = 0; hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + if (hsize * sizeof(u64) != dip->i_di.di_size) { gfs2_consist_inode(dip); return -EIO; } @@ -1378,7 +1378,7 @@ static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, - ht_offset * sizeof(uint64_t), + ht_offset * sizeof(u64), sdp->sd_hash_bsize); if (error != sdp->sd_hash_bsize) { if (error >= 0) @@ -1405,7 +1405,7 @@ out: return error; } -int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque, +int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, gfs2_filldir_t filldir) { struct gfs2_inode *dip = GFS2_I(inode); @@ -1725,15 +1725,15 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); 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; + u32 hsize, len; + u32 ht_offset, lp_offset, ht_offset_cur = -1; + u32 index = 0; + u64 *lp; + u64 leaf_no; int error = 0; hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + if (hsize * sizeof(u64) != dip->i_di.di_size) { gfs2_consist_inode(dip); return -EIO; } @@ -1748,7 +1748,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, - ht_offset * sizeof(uint64_t), + ht_offset * sizeof(u64), sdp->sd_hash_bsize); if (error != sdp->sd_hash_bsize) { if (error >= 0) @@ -1798,17 +1798,17 @@ out: * Returns: errno */ -static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, - uint64_t leaf_no, void *data) +static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, + u64 leaf_no, void *data) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_leaf *tmp_leaf; struct gfs2_rgrp_list rlist; struct buffer_head *bh, *dibh; - uint64_t blk, nblk; + u64 blk, nblk; unsigned int rg_blocks = 0, l_blocks = 0; char *ht; - unsigned int x, size = len * sizeof(uint64_t); + unsigned int x, size = len * sizeof(u64); int error; memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); @@ -1874,7 +1874,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, dip->i_di.di_blocks--; } - error = gfs2_dir_write_data(dip, ht, index * sizeof(uint64_t), size); + error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size); if (error != size) { if (error >= 0) error = -EIO; diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 366a5571648..f1f83faa36e 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -24,7 +24,7 @@ typedef int (*gfs2_filldir_t) (void *opaque, const char *name, unsigned int length, - uint64_t offset, + u64 offset, struct gfs2_inum *inum, unsigned int type); int gfs2_dir_search(struct inode *dir, const struct qstr *filename, @@ -32,7 +32,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *filename, 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 inode *inode, uint64_t * offset, void *opaque, +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); @@ -41,10 +41,10 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); int gfs2_diradd_alloc_required(struct inode *dir, const struct qstr *filename); -int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, +int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp); -static inline uint32_t gfs2_disk_hash(const char *data, int len) +static inline u32 gfs2_disk_hash(const char *data, int len) { return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF; } diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 5a56e656862..f6b5e306a6c 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -115,7 +115,7 @@ fail: static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) { struct buffer_head *bh, *eabh; - uint64_t *eablk, *end; + u64 *eablk, *end; int error; error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, @@ -133,11 +133,11 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) goto out; } - eablk = (uint64_t *)(bh->b_data + sizeof(struct gfs2_meta_header)); + eablk = (u64 *)(bh->b_data + sizeof(struct gfs2_meta_header)); end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs; for (; eablk < end; eablk++) { - uint64_t bn; + u64 bn; if (!*eablk) break; @@ -235,8 +235,8 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, struct gfs2_rgrpd *rgd; struct gfs2_holder rg_gh; struct buffer_head *dibh; - uint64_t *dataptrs, bn = 0; - uint64_t bstart = 0; + u64 *dataptrs, bn = 0; + u64 bstart = 0; unsigned int blen = 0; unsigned int blks = 0; unsigned int x; @@ -296,7 +296,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, gfs2_free_meta(ip, bstart, blen); if (prev && !leave) { - uint32_t len; + u32 len; len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); prev->ea_rec_len = cpu_to_be32(len); @@ -459,7 +459,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); - uint64_t *dataptrs = GFS2_EA2DATAPTRS(ea); + u64 *dataptrs = GFS2_EA2DATAPTRS(ea); unsigned int x; int error = 0; @@ -601,7 +601,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_ea_header *ea; - uint64_t block; + u64 block; block = gfs2_alloc_meta(ip); @@ -649,7 +649,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, ea->ea_num_ptrs = 0; memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len); } else { - uint64_t *dataptr = GFS2_EA2DATAPTRS(ea); + u64 *dataptr = GFS2_EA2DATAPTRS(ea); const char *data = er->er_data; unsigned int data_len = er->er_data_len; unsigned int copy; @@ -658,7 +658,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, 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; + u64 block; int mh_size = sizeof(struct gfs2_meta_header); block = gfs2_alloc_meta(ip); @@ -676,7 +676,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, memset(bh->b_data + mh_size + copy, 0, sdp->sd_jbsize - copy); - *dataptr++ = cpu_to_be64((uint64_t)bh->b_blocknr); + *dataptr++ = cpu_to_be64((u64)bh->b_blocknr); data += copy; data_len -= copy; @@ -792,10 +792,10 @@ static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) { - uint32_t ea_size = GFS2_EA_SIZE(ea); + u32 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; + u32 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); @@ -812,7 +812,7 @@ static void ea_set_remove_stuffed(struct gfs2_inode *ip, { struct gfs2_ea_header *ea = el->el_ea; struct gfs2_ea_header *prev = el->el_prev; - uint32_t len; + u32 len; gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); @@ -953,12 +953,12 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *indbh, *newbh; - uint64_t *eablk; + u64 *eablk; int error; int mh_size = sizeof(struct gfs2_meta_header); if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { - uint64_t *end; + u64 *end; error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_START | DIO_WAIT, &indbh); @@ -970,7 +970,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, goto out; } - eablk = (uint64_t *)(indbh->b_data + mh_size); + eablk = (u64 *)(indbh->b_data + mh_size); end = eablk + sdp->sd_inptrs; for (; eablk < end; eablk++) @@ -984,7 +984,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, gfs2_trans_add_bh(ip->i_gl, indbh, 1); } else { - uint64_t blk; + u64 blk; blk = gfs2_alloc_meta(ip); @@ -993,7 +993,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, 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 = (u64 *)(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; @@ -1006,7 +1006,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (error) goto out; - *eablk = cpu_to_be64((uint64_t)newbh->b_blocknr); + *eablk = cpu_to_be64((u64)newbh->b_blocknr); error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er); brelse(newbh); if (error) @@ -1140,7 +1140,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); if (prev) { - uint32_t len; + u32 len; len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); prev->ea_rec_len = cpu_to_be32(len); @@ -1225,7 +1225,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); - uint64_t *dataptrs = GFS2_EA2DATAPTRS(ea); + u64 *dataptrs = GFS2_EA2DATAPTRS(ea); unsigned int x; int error; @@ -1325,9 +1325,9 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrp_list rlist; struct buffer_head *indbh, *dibh; - uint64_t *eablk, *end; + u64 *eablk, *end; unsigned int rg_blocks = 0; - uint64_t bstart = 0; + u64 bstart = 0; unsigned int blen = 0; unsigned int blks = 0; unsigned int x; @@ -1345,11 +1345,11 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) goto out; } - eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs2_meta_header)); + eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); end = eablk + sdp->sd_inptrs; for (; eablk < end; eablk++) { - uint64_t bn; + u64 bn; if (!*eablk) break; @@ -1390,12 +1390,12 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) gfs2_trans_add_bh(ip->i_gl, indbh, 1); - eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs2_meta_header)); + eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); bstart = 0; blen = 0; for (; eablk < end; eablk++) { - uint64_t bn; + u64 bn; if (!*eablk) break; diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index 7b0291f99fd..85c70c335c5 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -16,7 +16,7 @@ #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) + (sizeof(u64) * (ea)->ea_num_ptrs)), 8) #define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) #define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) @@ -26,13 +26,13 @@ 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_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8) + sizeof(u64) * 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) #define GFS2_EA2DATAPTRS(ea) \ -((uint64_t *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8))) +((u64 *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8))) #define GFS2_EA2NEXT(ea) \ ((struct gfs2_ea_header *)((char *)(ea) + GFS2_EA_REC_LEN(ea))) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 1c916fedc04..f2edc8b7612 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -87,7 +87,7 @@ static unsigned int gl_hash(const struct lm_lockname *name) { unsigned int h; - h = jhash(&name->ln_number, sizeof(uint64_t), 0); + h = jhash(&name->ln_number, sizeof(u64), 0); h = jhash(&name->ln_type, sizeof(unsigned int), h); h &= GFS2_GL_HASH_MASK; @@ -255,7 +255,7 @@ static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, * Returns: errno */ -int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, +int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp) { @@ -1415,7 +1415,7 @@ void gfs2_glock_dq_uninit(struct gfs2_holder *gh) * Returns: errno */ -int gfs2_glock_nq_num(struct gfs2_sbd *sdp, uint64_t number, +int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, unsigned int state, int flags, struct gfs2_holder *gh) { @@ -1613,7 +1613,7 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) * Returns: errno */ -void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, uint64_t number, +void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, unsigned int state, int flags) { diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 1a90a1983be..4762cdb04f6 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -74,7 +74,7 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) } int gfs2_glock_get(struct gfs2_sbd *sdp, - uint64_t number, const struct gfs2_glock_operations *glops, + u64 number, const 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); @@ -96,14 +96,14 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time); void gfs2_glock_dq_uninit(struct gfs2_holder *gh); int gfs2_glock_nq_num(struct gfs2_sbd *sdp, - uint64_t number, const struct gfs2_glock_operations *glops, + u64 number, const 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, +void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, unsigned int state, int flags); void gfs2_glock_inode_squish(struct inode *inode); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 06f5ec6ebf7..407afd18fa2 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -60,9 +60,9 @@ struct gfs2_log_element { struct gfs2_bitmap { struct buffer_head *bi_bh; char *bi_clone; - uint32_t bi_offset; - uint32_t bi_start; - uint32_t bi_len; + u32 bi_offset; + u32 bi_start; + u32 bi_len; }; struct gfs2_rgrpd { @@ -72,14 +72,14 @@ struct gfs2_rgrpd { struct gfs2_glock *rd_gl; /* Glock for this rgrp */ struct gfs2_rindex rd_ri; struct gfs2_rgrp rd_rg; - uint64_t rd_rg_vn; + u64 rd_rg_vn; struct gfs2_bitmap *rd_bits; unsigned int rd_bh_count; struct mutex rd_mutex; - uint32_t rd_free_clone; + u32 rd_free_clone; struct gfs2_log_element rd_le; - uint32_t rd_last_alloc_data; - uint32_t rd_last_alloc_meta; + u32 rd_last_alloc_data; + u32 rd_last_alloc_meta; struct gfs2_sbd *rd_sbd; }; @@ -185,7 +185,7 @@ struct gfs2_glock { char *gl_lvb; atomic_t gl_lvb_count; - uint64_t gl_vn; + u64 gl_vn; unsigned long gl_stamp; void *gl_object; @@ -232,14 +232,14 @@ struct gfs2_inode { unsigned long i_flags; /* GIF_... */ - uint64_t i_vn; + u64 i_vn; 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; - uint64_t i_last_rg_alloc; + u64 i_last_rg_alloc; spinlock_t i_spin; struct rw_semaphore i_rw_mutex; @@ -277,12 +277,12 @@ struct gfs2_file { struct gfs2_revoke { struct gfs2_log_element rv_le; - uint64_t rv_blkno; + u64 rv_blkno; }; struct gfs2_revoke_replay { struct list_head rr_list; - uint64_t rr_blkno; + u64 rr_blkno; unsigned int rr_where; }; @@ -304,11 +304,11 @@ struct gfs2_quota_data { struct list_head qd_list; unsigned int qd_count; - uint32_t qd_id; + u32 qd_id; unsigned long qd_flags; /* QDF_... */ - int64_t qd_change; - int64_t qd_change_sync; + s64 qd_change; + s64 qd_change_sync; unsigned int qd_slot; unsigned int qd_slot_count; @@ -320,7 +320,7 @@ struct gfs2_quota_data { struct gfs2_glock *qd_gl; struct gfs2_quota_lvb qd_qb; - uint64_t qd_sync_gen; + u64 qd_sync_gen; unsigned long qd_last_warn; unsigned long qd_last_touched; }; @@ -358,7 +358,7 @@ struct gfs2_ail { struct list_head ai_ail1_list; struct list_head ai_ail2_list; - uint64_t ai_sync_gen; + u64 ai_sync_gen; }; struct gfs2_jdesc { @@ -466,20 +466,20 @@ struct gfs2_sbd { /* 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_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]; + u32 sd_fsb2bb; + u32 sd_fsb2bb_shift; + u32 sd_diptrs; /* Number of pointers in a dinode */ + u32 sd_inptrs; /* Number of pointers in a indirect block */ + u32 sd_jbsize; /* Size of a journaled data block */ + u32 sd_hash_bsize; /* sizeof(exhash block) */ + u32 sd_hash_bsize_shift; + u32 sd_hash_ptrs; /* Number of pointers in a hash block */ + u32 sd_qc_per_block; + u32 sd_max_dirres; /* Max blocks needed to add a directory entry */ + u32 sd_max_height; /* Max height of a file's metadata tree */ + u64 sd_heightsize[GFS2_MAX_META_HEIGHT]; + u32 sd_max_jheight; /* Max height of journaled file's meta tree */ + u64 sd_jheightsize[GFS2_MAX_META_HEIGHT]; struct gfs2_args sd_args; /* Mount arguments */ struct gfs2_tune sd_tune; /* Filesystem tuning structure */ @@ -522,7 +522,7 @@ struct gfs2_sbd { /* Resource group stuff */ - uint64_t sd_rindex_vn; + u64 sd_rindex_vn; spinlock_t sd_rindex_spin; struct mutex sd_rindex_mutex; struct list_head sd_rindex_list; @@ -567,7 +567,7 @@ struct gfs2_sbd { unsigned int sd_quota_chunks; unsigned char **sd_quota_bitmap; - uint64_t sd_quota_sync_gen; + u64 sd_quota_sync_gen; unsigned long sd_quota_sync_time; /* Log stuff */ @@ -595,7 +595,7 @@ struct gfs2_sbd { unsigned int sd_log_blks_free; struct mutex sd_log_reserve_mutex; - uint64_t sd_log_sequence; + u64 sd_log_sequence; unsigned int sd_log_head; unsigned int sd_log_tail; int sd_log_idle; @@ -605,11 +605,11 @@ struct gfs2_sbd { struct list_head sd_log_flush_list; unsigned int sd_log_flush_head; - uint64_t sd_log_flush_wrapped; + u64 sd_log_flush_wrapped; struct list_head sd_ail1_list; struct list_head sd_ail2_list; - uint64_t sd_ail_sync_gen; + u64 sd_ail_sync_gen; /* Replay stuff */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 1aaaaa1cc8c..f683a400b00 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -311,7 +311,7 @@ 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; + u32 nlink; int error; BUG_ON(ip->i_di.di_nlink != ip->i_inode.i_nlink); @@ -428,7 +428,7 @@ out: return inode; } -static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) +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; @@ -469,7 +469,7 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) return 1; } -static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) +static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino) { struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode); @@ -495,13 +495,13 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) if (!ir.ir_length) { struct buffer_head *m_bh; - uint64_t x, y; + u64 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 = *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)); x = y = be64_to_cpu(x); ir.ir_start = x; ir.ir_length = GFS2_INUM_QUANTUM; @@ -510,7 +510,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) gfs2_consist_inode(m_ip); x = cpu_to_be64(x); gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); - *(uint64_t *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x; + *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x; brelse(m_bh); } @@ -531,7 +531,7 @@ out: return error; } -static int pick_formal_ino(struct gfs2_sbd *sdp, uint64_t *inum) +static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum) { int error; @@ -577,9 +577,9 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, return error; } - if (dip->i_di.di_entries == (uint32_t)-1) + if (dip->i_di.di_entries == (u32)-1) return -EFBIG; - if (S_ISDIR(mode) && dip->i_di.di_nlink == (uint32_t)-1) + if (S_ISDIR(mode) && dip->i_di.di_nlink == (u32)-1) return -EMLINK; return 0; @@ -1131,7 +1131,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 = gl->gl_object; - int64_t curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum); + s64 curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum); unsigned int state; int flags; int error; diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index 0bf4c276e0f..e2dfc3da4da 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -160,7 +160,7 @@ typedef void (*lm_callback_t) (lm_fsdata_t *fsdata, unsigned int type, struct lm_lockname { - uint64_t ln_number; + u64 ln_number; unsigned int ln_type; }; diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index 1f15b6e8b2c..dceea419b94 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -61,7 +61,7 @@ void gdlm_queue_delayed(struct gdlm_lock *lp) /* convert gfs lock-state to dlm lock-mode */ -static int16_t make_mode(int16_t lmstate) +static s16 make_mode(s16 lmstate) { switch (lmstate) { case LM_ST_UNLOCKED: @@ -79,7 +79,7 @@ static int16_t make_mode(int16_t lmstate) /* convert dlm lock-mode to gfs lock-state */ -int16_t gdlm_make_lmstate(int16_t dlmmode) +s16 gdlm_make_lmstate(s16 dlmmode) { switch (dlmmode) { case DLM_LOCK_IV: @@ -101,14 +101,14 @@ int16_t gdlm_make_lmstate(int16_t dlmmode) static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state) { - int16_t cur = make_mode(cur_state); + s16 cur = make_mode(cur_state); if (lp->cur != DLM_LOCK_IV) gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur); } static inline unsigned int make_flags(struct gdlm_lock *lp, unsigned int gfs_flags, - int16_t cur, int16_t req) + s16 cur, s16 req) { unsigned int lkf = 0; diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 94106349853..c7b6e370258 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -56,7 +56,7 @@ enum { }; struct gdlm_ls { - uint32_t id; + u32 id; int jid; int first; int first_done; @@ -77,7 +77,7 @@ struct gdlm_ls { struct list_head delayed; struct list_head submit; struct list_head all_locks; - uint32_t all_locks_count; + u32 all_locks_count; wait_queue_head_t wait_control; struct task_struct *thread1; struct task_struct *thread2; @@ -109,10 +109,10 @@ struct gdlm_lock { char *lvb; struct dlm_lksb lksb; - int16_t cur; - int16_t req; - int16_t prev_req; - uint32_t lkf; /* dlm flags DLM_LKF_ */ + s16 cur; + s16 req; + s16 prev_req; + u32 lkf; /* dlm flags DLM_LKF_ */ unsigned long flags; /* lock_dlm flags LFL_ */ int bast_mode; /* protected by async_lock */ @@ -158,7 +158,7 @@ void gdlm_release_threads(struct gdlm_ls *); /* lock.c */ -int16_t gdlm_make_lmstate(int16_t); +s16 gdlm_make_lmstate(s16); void gdlm_queue_delayed(struct gdlm_lock *); void gdlm_submit_delayed(struct gdlm_ls *); int gdlm_release_all_locks(struct gdlm_ls *); diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index a782246d666..d4895ec242f 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -48,7 +48,7 @@ static void process_complete(struct gdlm_lock *lp) { struct gdlm_ls *ls = lp->ls; struct lm_async_cb acb; - int16_t prev_mode = lp->cur; + s16 prev_mode = lp->cur; memset(&acb, 0, sizeof(acb)); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 45ea3ec6f77..57138901287 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -62,7 +62,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) { struct list_head *head = &sdp->sd_ail1_list; - uint64_t sync_gen; + u64 sync_gen; struct list_head *first, *tmp; struct gfs2_ail *first_ai, *ai; @@ -205,10 +205,10 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) up_read(&sdp->sd_log_flush_lock); } -static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) +static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) { int new = 0; - uint64_t dbn; + u64 dbn; int error; int bdy; @@ -287,7 +287,7 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) { - uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); + u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); struct gfs2_log_buf *lb; struct buffer_head *bh; @@ -317,7 +317,7 @@ 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) { - uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); + u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); struct gfs2_log_buf *lb; struct buffer_head *bh; @@ -361,13 +361,13 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) * Returns: the initialized log buffer descriptor */ -static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) +static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) { - uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); + u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); struct buffer_head *bh; struct gfs2_log_header *lh; unsigned int tail; - uint32_t hash; + u32 hash; /* printk(KERN_INFO "log write header start (flags=%08x, pull=%d)\n", flags, pull); */ @@ -523,7 +523,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) reserved += sdp->sd_log_commited_buf; if (sdp->sd_log_commited_revoke) reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, - sizeof(uint64_t)); + sizeof(u64)); if (reserved) reserved++; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index e2c2582c8f6..456d6ad1049 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -202,7 +202,7 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, 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; + u64 blkno; int error = 0; if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA) @@ -294,7 +294,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) ld->ld_header.mh_format = cpu_to_be32(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))); + sizeof(u64))); 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)); @@ -305,7 +305,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) list_del_init(&rv->rv_le.le_list); sdp->sd_log_num_revoke--; - if (offset + sizeof(uint64_t) > sdp->sd_sb.sb_bsize) { + if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { set_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); @@ -320,7 +320,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno); kfree(rv); - offset += sizeof(uint64_t); + offset += sizeof(u64); } gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); @@ -349,7 +349,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, unsigned int revokes = be32_to_cpu(ld->ld_data1); struct buffer_head *bh; unsigned int offset; - uint64_t blkno; + u64 blkno; int first = 1; int error; @@ -366,7 +366,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, if (!first) gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LB); - while (offset + sizeof(uint64_t) <= sdp->sd_sb.sb_bsize) { + while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) { blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); error = gfs2_revoke_add(sdp, blkno, start); @@ -377,7 +377,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, if (!--revokes) break; - offset += sizeof(uint64_t); + offset += sizeof(u64); } brelse(bh); @@ -677,8 +677,8 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, 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; - uint64_t esc; + u64 blkno; + u64 esc; int error = 0; if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 3f6da00e2f5..5b10379c20e 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -213,7 +213,7 @@ void gfs2_ail_empty_gl(struct gfs2_glock *gl) struct list_head *head = &gl->gl_ail_list; struct gfs2_bufdata *bd; struct buffer_head *bh; - uint64_t blkno; + u64 blkno; int error; blocks = atomic_read(&gl->gl_ail_count); @@ -303,7 +303,7 @@ void gfs2_meta_sync(struct gfs2_glock *gl, int flags) */ static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace, - uint64_t blkno, int create) + u64 blkno, int create) { struct page *page; struct buffer_head *bh; @@ -366,7 +366,7 @@ static void meta_prep_new(struct buffer_head *bh) * Returns: The buffer */ -struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t blkno) +struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) { struct buffer_head *bh; bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); @@ -384,7 +384,7 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t blkno) * Returns: errno */ -int gfs2_meta_read(struct gfs2_glock *gl, uint64_t blkno, int flags, +int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp) { int error; @@ -549,7 +549,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) +void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *aspace = ip->i_gl->gl_aspace; @@ -573,7 +573,7 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) if (bd) { gfs2_log_lock(sdp); if (bd->bd_ail) { - uint64_t blkno = bh->b_blocknr; + u64 blkno = bh->b_blocknr; bd->bd_ail = NULL; list_del(&bd->bd_ail_st_list); list_del(&bd->bd_ail_gl_list); @@ -637,7 +637,7 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) * Returns: errno */ -int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, +int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, int new, struct buffer_head **bhp) { struct buffer_head *bh, **bh_slot = ip->i_cache + height; @@ -711,12 +711,12 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, * */ -void gfs2_meta_ra(struct gfs2_glock *gl, uint64_t dblock, uint32_t extlen) +void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 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) >> + u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; int error; diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 4ddc936aae1..9a9acc94029 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -44,8 +44,8 @@ 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, +struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); +int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp); int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags); @@ -55,10 +55,10 @@ 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); -void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); +void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 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 gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, int new, struct buffer_head **bhp); static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, @@ -67,7 +67,7 @@ static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, 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_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); #endif /* __DIO_DOT_H__ */ diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 21ae9e4f0f6..ae9c46e7539 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -66,7 +66,7 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { int new = create; - uint64_t dblock; + u64 dblock; int error; int boundary; @@ -100,7 +100,7 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { int new = 0; - uint64_t dblock; + u64 dblock; int error; int boundary; @@ -510,10 +510,10 @@ static int gfs2_commit_write(struct file *file, struct page *page, gfs2_trans_add_bh(ip->i_gl, dibh, 1); if (gfs2_is_stuffed(ip)) { - uint64_t file_size; + u64 file_size; void *kaddr; - file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; + file_size = ((u64)page->index << PAGE_CACHE_SHIFT) + to; kaddr = kmap_atomic(page, KM_USER0); memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index c94cbc8b6ef..cf826893dd5 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -46,15 +46,15 @@ static struct dentry *gfs2_decode_fh(struct super_block *sb, switch (fh_type) { case 10: - parent.no_formal_ino = ((uint64_t)be32_to_cpu(fh[4])) << 32; + parent.no_formal_ino = ((u64)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 = ((u64)be32_to_cpu(fh[6])) << 32; parent.no_addr |= be32_to_cpu(fh[7]); fh_obj.imode = be32_to_cpu(fh[8]); case 4: - this->no_formal_ino = ((uint64_t)be32_to_cpu(fh[0])) << 32; + this->no_formal_ino = ((u64)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 = ((u64)be32_to_cpu(fh[2])) << 32; this->no_addr |= be32_to_cpu(fh[3]); break; default: @@ -118,7 +118,7 @@ struct get_name_filldir { }; static int get_name_filldir(void *opaque, const char *name, unsigned int length, - uint64_t offset, struct gfs2_inum *inum, + u64 offset, struct gfs2_inum *inum, unsigned int type) { struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque; @@ -140,7 +140,7 @@ static int gfs2_get_name(struct dentry *parent, char *name, struct gfs2_inode *dip, *ip; struct get_name_filldir gnfd; struct gfs2_holder gh; - uint64_t offset = 0; + u64 offset = 0; int error; if (!dir) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 53ce7816dc1..f5ddd496d3e 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -47,7 +47,7 @@ struct filldir_bad_entry { char *fbe_name; unsigned int fbe_length; - uint64_t fbe_offset; + u64 fbe_offset; struct gfs2_inum fbe_inum; unsigned int fbe_type; }; @@ -161,7 +161,7 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) */ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, - uint64_t offset, struct gfs2_inum *inum, + u64 offset, struct gfs2_inum *inum, unsigned int type) { struct filldir_reg *fdr = (struct filldir_reg *)opaque; @@ -200,7 +200,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) struct gfs2_inode *dip = GFS2_I(dir); struct filldir_reg fdr; struct gfs2_holder d_gh; - uint64_t offset = file->f_pos; + u64 offset = file->f_pos; int error; fdr.fdr_sbd = GFS2_SB(dir); @@ -239,7 +239,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) */ static int filldir_bad_func(void *opaque, const char *name, unsigned int length, - uint64_t offset, struct gfs2_inum *inum, + u64 offset, struct gfs2_inum *inum, unsigned int type) { struct filldir_bad *fdb = (struct filldir_bad *)opaque; @@ -293,7 +293,7 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) unsigned int entries, size; struct filldir_bad *fdb; struct gfs2_holder d_gh; - uint64_t offset = file->f_pos; + u64 offset = file->f_pos; unsigned int x; struct filldir_bad_entry *fbe; int error; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index bd9b9957f70..c680f050e17 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -172,7 +172,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (!dip->i_di.di_nlink) goto out_gunlock; error = -EFBIG; - if (dip->i_di.di_entries == (uint32_t)-1) + if (dip->i_di.di_entries == (u32)-1) goto out_gunlock; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) @@ -181,7 +181,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (!ip->i_di.di_nlink) goto out_gunlock; error = -EMLINK; - if (ip->i_di.di_nlink == (uint32_t)-1) + if (ip->i_di.di_nlink == (u32)-1) goto out_gunlock; alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); @@ -509,7 +509,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, struct gfs2_holder ghs[2]; struct inode *inode; struct buffer_head *dibh; - uint32_t major = 0, minor = 0; + u32 major = 0, minor = 0; int error; switch (mode & S_IFMT) { @@ -670,12 +670,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = -EINVAL; goto out_gunlock; } - if (ndip->i_di.di_entries == (uint32_t)-1) { + if (ndip->i_di.di_entries == (u32)-1) { error = -EFBIG; goto out_gunlock; } if (S_ISDIR(ip->i_di.di_mode) && - ndip->i_di.di_nlink == (uint32_t)-1) { + ndip->i_di.di_nlink == (u32)-1) { error = -EMLINK; goto out_gunlock; } @@ -911,7 +911,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *dibh; - uint32_t ouid, ogid, nuid, ngid; + u32 ouid, ogid, nuid, ngid; int error; ouid = ip->i_di.di_uid; diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 32ec8574ac8..3b346314412 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -62,7 +62,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); unsigned long index = page->index; - uint64_t lblock = index << (PAGE_CACHE_SHIFT - + u64 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; @@ -101,7 +101,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) } for (x = 0; x < blocks; ) { - uint64_t dblock; + u64 dblock; unsigned int extlen; int new = 1; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 572b92eac36..f5830befc30 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -65,17 +65,17 @@ #define QUOTA_USER 1 #define QUOTA_GROUP 0 -static uint64_t qd2offset(struct gfs2_quota_data *qd) +static u64 qd2offset(struct gfs2_quota_data *qd) { - uint64_t offset; + u64 offset; - offset = 2 * (uint64_t)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags); + offset = 2 * (u64)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, +static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, struct gfs2_quota_data **qdp) { struct gfs2_quota_data *qd; @@ -91,7 +91,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, uint32_t id, set_bit(QDF_USER, &qd->qd_flags); qd->qd_slot = -1; - error = gfs2_glock_get(sdp, 2 * (uint64_t)id + !user, + error = gfs2_glock_get(sdp, 2 * (u64)id + !user, &gfs2_quota_glops, CREATE, &qd->qd_gl); if (error) goto fail; @@ -110,7 +110,7 @@ fail: return error; } -static int qd_get(struct gfs2_sbd *sdp, int user, uint32_t id, int create, +static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, struct gfs2_quota_data **qdp) { struct gfs2_quota_data *qd = NULL, *new_qd = NULL; @@ -248,7 +248,7 @@ static int bh_get(struct gfs2_quota_data *qd) struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); unsigned int block, offset; - uint64_t dblock; + u64 dblock; int new = 0; struct buffer_head *bh; int error; @@ -405,7 +405,7 @@ static void qd_unlock(struct gfs2_quota_data *qd) qd_put(qd); } -static int qdsb_get(struct gfs2_sbd *sdp, int user, uint32_t id, int create, +static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create, struct gfs2_quota_data **qdp) { int error; @@ -438,7 +438,7 @@ static void qdsb_put(struct gfs2_quota_data *qd) qd_put(qd); } -int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) +int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; @@ -523,12 +523,12 @@ static int sort_qd(const void *a, const void *b) return ret; } -static void do_qc(struct gfs2_quota_data *qd, int64_t change) +static void do_qc(struct gfs2_quota_data *qd, s64 change) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); struct gfs2_quota_change *qc = qd->qd_bh_qc; - int64_t x; + s64 x; mutex_lock(&sdp->sd_quota_mutex); gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1); @@ -571,7 +571,7 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) * 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) + s64 change, struct gfs2_quota_data *qd) { struct inode *inode = &ip->i_inode; struct address_space *mapping = inode->i_mapping; @@ -811,7 +811,7 @@ fail: return error; } -int gfs2_quota_lock(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) +int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; @@ -848,7 +848,7 @@ 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; + s64 value; unsigned int num, den; int do_sync = 1; @@ -873,7 +873,7 @@ static int need_sync(struct gfs2_quota_data *qd) value *= gfs2_jindex_size(sdp) * num; do_div(value, den); value += (s64)be64_to_cpu(qd->qd_qb.qb_value); - if (value < (int64_t)be64_to_cpu(qd->qd_qb.qb_limit)) + if (value < (s64)be64_to_cpu(qd->qd_qb.qb_limit)) do_sync = 0; } @@ -927,12 +927,12 @@ static int print_message(struct gfs2_quota_data *qd, char *type) return 0; } -int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) +int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_quota_data *qd; - int64_t value; + s64 value; unsigned int x; int error = 0; @@ -954,12 +954,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) value += qd->qd_change; spin_unlock(&sdp->sd_quota_spin); - if (be64_to_cpu(qd->qd_qb.qb_limit) && (int64_t)be64_to_cpu(qd->qd_qb.qb_limit) < value) { + if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { print_message(qd, "exceeded"); error = -EDQUOT; break; } else if (be64_to_cpu(qd->qd_qb.qb_warn) && - (int64_t)be64_to_cpu(qd->qd_qb.qb_warn) < value && + (s64)be64_to_cpu(qd->qd_qb.qb_warn) < value && time_after_eq(jiffies, qd->qd_last_warn + gfs2_tune_get(sdp, gt_quota_warn_period) * HZ)) { @@ -971,8 +971,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) return error; } -void gfs2_quota_change(struct gfs2_inode *ip, int64_t change, - uint32_t uid, uint32_t gid) +void gfs2_quota_change(struct gfs2_inode *ip, s64 change, + u32 uid, u32 gid) { struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_quota_data *qd; @@ -1038,7 +1038,7 @@ int gfs2_quota_sync(struct gfs2_sbd *sdp) return error; } -int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, uint32_t id) +int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) { struct gfs2_quota_data *qd; struct gfs2_holder q_gh; @@ -1058,7 +1058,7 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, uint32_t id) } #if 0 -int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, +int gfs2_quota_read(struct gfs2_sbd *sdp, int user, u32 id, struct gfs2_quota *q) { struct gfs2_quota_data *qd; @@ -1100,8 +1100,8 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) 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; + u64 dblock; + u32 extlen = 0; int error; if (!ip->i_di.di_size || diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 6702a56d49b..d93c61c9936 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -10,20 +10,20 @@ #ifndef __QUOTA_DOT_H__ #define __QUOTA_DOT_H__ -#define NO_QUOTA_CHANGE ((uint32_t)-1) +#define NO_QUOTA_CHANGE ((u32)-1) -int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid); +int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid); void gfs2_quota_unhold(struct gfs2_inode *ip); -int gfs2_quota_lock(struct gfs2_inode *ip, uint32_t uid, uint32_t gid); +int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 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_check(struct gfs2_inode *ip, u32 uid, u32 gid); +void gfs2_quota_change(struct gfs2_inode *ip, s64 change, + u32 uid, u32 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_refresh(struct gfs2_sbd *sdp, int user, u32 id); int gfs2_quota_init(struct gfs2_sbd *sdp); void gfs2_quota_scan(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index acafe4b4d6f..ab55191926c 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -35,8 +35,8 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, 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; + u64 dblock; + u32 extlen; int error; error = gfs2_extent_map(&ip->i_inode, blk, &new, &dblock, &extlen); @@ -53,7 +53,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, return error; } -int gfs2_revoke_add(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where) +int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) { struct list_head *head = &sdp->sd_revoke_list; struct gfs2_revoke_replay *rr; @@ -82,7 +82,7 @@ int gfs2_revoke_add(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where) return 1; } -int gfs2_revoke_check(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where) +int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) { struct gfs2_revoke_replay *rr; int wrap, a, b, revoke; @@ -137,7 +137,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, { struct buffer_head *bh; struct gfs2_log_header lh; - uint32_t hash; + u32 hash; int error; error = gfs2_replay_read_block(jd, blk, &bh); @@ -249,7 +249,7 @@ static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head) 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; + u32 blk_1, blk_2, blk_m; int error; blk_1 = 0; @@ -370,9 +370,9 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); unsigned int lblock; int new = 0; - uint64_t dblock; + u64 dblock; struct gfs2_log_header *lh; - uint32_t hash; + u32 hash; struct buffer_head *bh; int error; int boundary; diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index bed1a7857f6..1b35516b759 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -19,8 +19,8 @@ static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) 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); +int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where); +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, diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 62d0a84df98..af49c8b82ff 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -60,7 +60,7 @@ static const char valid_change[16] = { */ static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, uint32_t block, + unsigned int buflen, u32 block, unsigned char new_state) { unsigned char *byte, *end, cur_state; @@ -90,7 +90,7 @@ static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, */ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, uint32_t block) + unsigned int buflen, u32 block) { unsigned char *byte, *end, cur_state; unsigned int bit; @@ -122,12 +122,12 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * Return: the block number (bitmap buffer scope) that was found */ -static uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, uint32_t goal, +static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, + unsigned int buflen, u32 goal, unsigned char old_state) { unsigned char *byte, *end, alloc; - uint32_t blk = goal; + u32 blk = goal; unsigned int bit; byte = buffer + (goal / GFS2_NBBY); @@ -169,7 +169,7 @@ static uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * Returns: The number of bits */ -static uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, +static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, unsigned int buflen, unsigned char state) { unsigned char *byte = buffer; @@ -177,7 +177,7 @@ static uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, unsigned char state1 = state << 2; unsigned char state2 = state << 4; unsigned char state3 = state << 6; - uint32_t count = 0; + u32 count = 0; for (; byte < end; byte++) { if (((*byte) & 0x03) == state) @@ -204,11 +204,11 @@ 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; + u32 length = rgd->rd_ri.ri_length; + u32 count[4], tmp; int buf, x; - memset(count, 0, 4 * sizeof(uint32_t)); + memset(count, 0, 4 * sizeof(u32)); /* Count # blocks in each of 4 possible allocation states */ for (buf = 0; buf < length; buf++) { @@ -253,10 +253,10 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) } -static inline int rgrp_contains_block(struct gfs2_rindex *ri, uint64_t block) +static inline int rgrp_contains_block(struct gfs2_rindex *ri, u64 block) { - uint64_t first = ri->ri_data0; - uint64_t last = first + ri->ri_data; + u64 first = ri->ri_data0; + u64 last = first + ri->ri_data; return !!(first <= block && block < last); } @@ -268,7 +268,7 @@ static inline int rgrp_contains_block(struct gfs2_rindex *ri, uint64_t block) * Returns: The resource group, or NULL if not found */ -struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk) +struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk) { struct gfs2_rgrpd *rgd; @@ -367,8 +367,8 @@ 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; + u32 length = rgd->rd_ri.ri_length; /* # blocks in hdr & bitmap */ + u32 bytes_left, bytes; int x; if (!length) @@ -444,7 +444,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) struct gfs2_rgrpd *rgd; char buf[sizeof(struct gfs2_rindex)]; struct file_ra_state ra_state; - uint64_t junk = ip->i_di.di_size; + u64 junk = ip->i_di.di_size; int error; if (do_div(junk, sizeof(struct gfs2_rindex))) { @@ -741,7 +741,7 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) */ static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp, - uint64_t rglast) + u64 rglast) { struct gfs2_rgrpd *rgd = NULL; @@ -1037,10 +1037,10 @@ void gfs2_inplace_release(struct gfs2_inode *ip) * Returns: The block type (GFS2_BLKST_*) */ -unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block) +unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) { struct gfs2_bitmap *bi = NULL; - uint32_t length, rgrp_block, buf_block; + u32 length, rgrp_block, buf_block; unsigned int buf; unsigned char type; @@ -1083,12 +1083,12 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block) * Returns: the block number allocated */ -static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, +static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 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; + u32 length = rgd->rd_ri.ri_length; + u32 blk = 0; unsigned int buf, x; /* Find bitmap block that contains bits for goal block */ @@ -1148,12 +1148,12 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, * 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) +static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, + u32 blen, unsigned char new_state) { struct gfs2_rgrpd *rgd; struct gfs2_bitmap *bi = NULL; - uint32_t length, rgrp_blk, buf_blk; + u32 length, rgrp_blk, buf_blk; unsigned int buf; rgd = gfs2_blk2rgrpd(sdp, bstart); @@ -1206,8 +1206,8 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) 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; - uint64_t block; + u32 goal, blk; + u64 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; @@ -1250,8 +1250,8 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) 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; - uint64_t block; + u32 goal, blk; + u64 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; @@ -1332,7 +1332,7 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) * */ -void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) +void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd; @@ -1349,7 +1349,7 @@ void gfs2_free_data(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, + gfs2_quota_change(ip, -(s64)blen, ip->i_di.di_uid, ip->i_di.di_gid); } @@ -1361,7 +1361,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_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd; @@ -1378,7 +1378,7 @@ 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, -(s64)blen, ip->i_di.di_uid, ip->i_di.di_gid); gfs2_meta_wipe(ip, bstart, blen); } @@ -1397,7 +1397,7 @@ void gfs2_unlink_di(struct inode *inode) gfs2_trans_add_rg(rgd); } -static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) +static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno) { struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_rgrpd *tmp_rgd; @@ -1440,7 +1440,7 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) */ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, - uint64_t block) + u64 block) { struct gfs2_rgrpd *rgd; struct gfs2_rgrpd **tmp; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index f94761bf346..3d6ae37e85d 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -12,7 +12,7 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); -struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk); +struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk); struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); @@ -35,14 +35,14 @@ 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); +unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block); 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); +void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); +void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); void gfs2_unlink_di(struct inode *inode); @@ -54,7 +54,7 @@ struct gfs2_rgrp_list { }; void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, - uint64_t block); + u64 block); void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, int flags); void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 520266c2044..f1d07d987c7 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -33,11 +33,11 @@ #include "trans.h" #include "util.h" -static const uint32_t gfs2_old_fs_formats[] = { +static const u32 gfs2_old_fs_formats[] = { 0 }; -static const uint32_t gfs2_old_multihost_formats[] = { +static const u32 gfs2_old_multihost_formats[] = { 0 }; @@ -225,8 +225,8 @@ static struct page *gfs2_read_super(struct super_block *sb, sector_t sector) int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) { - uint32_t hash_blocks, ind_blocks, leaf_blocks; - uint32_t tmp_blocks; + u32 hash_blocks, ind_blocks, leaf_blocks; + u32 tmp_blocks; unsigned int x; int error; struct page *page; @@ -251,20 +251,20 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) 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); + sizeof(struct gfs2_dinode)) / sizeof(u64); sdp->sd_inptrs = (sdp->sd_sb.sb_bsize - - sizeof(struct gfs2_meta_header)) / sizeof(uint64_t); + sizeof(struct gfs2_meta_header)) / sizeof(u64); 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_hash_ptrs = sdp->sd_hash_bsize / sizeof(u64); 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_ROUND_UP(sizeof(uint64_t) * (1 << GFS2_DIR_MAX_DEPTH), + hash_blocks = DIV_ROUND_UP(sizeof(u64) * (1 << GFS2_DIR_MAX_DEPTH), sdp->sd_jbsize); ind_blocks = 0; @@ -281,8 +281,8 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) 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; + u64 space, d; + u32 m; space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs; d = space; @@ -299,8 +299,8 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) 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; + u64 space, d; + u32 m; space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs; d = space; @@ -630,8 +630,8 @@ out: return 0; } -void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, - int64_t dinodes) +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; diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 4a6ce958274..b073300a93e 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -40,7 +40,7 @@ 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); + 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); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 79199738c38..8aefda22f98 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -138,7 +138,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { - uint32_t id; + u32 id; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -152,7 +152,7 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { - uint32_t id; + u32 id; if (!capable(CAP_SYS_ADMIN)) return -EACCES; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 8e18e634cbe..acf840160d5 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -46,7 +46,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, tr->tr_reserved += 6 + blocks; if (revokes) tr->tr_reserved += gfs2_struct2blk(sdp, revokes, - sizeof(uint64_t)); + sizeof(u64)); INIT_LIST_HEAD(&tr->tr_list_buf); gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &tr->tr_t_gh); @@ -142,7 +142,7 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) lops_add(sdp, &bd->bd_le); } -void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, uint64_t blkno) +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno) { struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke), GFP_NOFS | __GFP_NOFAIL); @@ -151,7 +151,7 @@ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, uint64_t blkno) lops_add(sdp, &rv->rv_le); } -void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, uint64_t blkno) +void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) { struct gfs2_revoke *rv; int found = 0; diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 9e3ce84f610..6550d3d1826 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -27,8 +27,8 @@ 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, 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_revoke(struct gfs2_sbd *sdp, u64 blkno); +void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno); void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); #endif /* __TRANS_DOT_H__ */ diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 2852431764c..d72eb8addc7 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -171,7 +171,7 @@ int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, */ int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, - uint16_t type, uint16_t t, const char *function, + u16 type, u16 t, const char *function, char *file, unsigned int line) { int me; diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 60b370365ee..204fdb81e34 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -82,7 +82,7 @@ static inline int gfs2_meta_check_i(struct gfs2_sbd *sdp, char *file, unsigned int line) { struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; - uint32_t magic = mh->mh_magic; + u32 magic = mh->mh_magic; magic = be32_to_cpu(magic); if (unlikely(magic != GFS2_MAGIC)) return gfs2_meta_check_ii(sdp, bh, "magic number", function, @@ -95,19 +95,19 @@ 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, + u16 type, u16 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, + u16 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 = be32_to_cpu(mh->mh_type); + u32 magic = mh->mh_magic; + u16 t = be32_to_cpu(mh->mh_type); magic = be32_to_cpu(magic); if (unlikely(magic != GFS2_MAGIC)) return gfs2_meta_check_ii(sdp, bh, "magic number", function, @@ -121,8 +121,8 @@ static inline int gfs2_metatype_check_i(struct gfs2_sbd *sdp, #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) +static inline void gfs2_metatype_set(struct buffer_head *bh, u16 type, + u16 format) { struct gfs2_meta_header *mh; mh = (struct gfs2_meta_header *)bh->b_data; -- GitLab From c26687113aea9a11c6f23ddf668f1fe43eca4ce7 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 13:55:48 -0400 Subject: [PATCH 0226/1619] [GFS2] Remove a cast, tidy gfs2_inode_attr_in The remains of the changes for Jan Engelhardt's third email. Remove a cast and tidy up gfs2_inode_attr_in. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 2 +- fs/gfs2/inode.c | 27 ++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index a97ad74d880..0f9567fe5c8 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -344,7 +344,7 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, unsigned int i; for (i = ip->i_di.di_height; i--;) - mp->mp_list[i] = (__u16)do_div(b, sdp->sd_inptrs); + mp->mp_list[i] = do_div(b, sdp->sd_inptrs); } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f683a400b00..0d010f0654d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -47,40 +47,41 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) { struct inode *inode = &ip->i_inode; + struct gfs2_dinode *di = &ip->i_di; inode->i_ino = ip->i_num.no_addr; - switch (ip->i_di.di_mode & S_IFMT) { + switch (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); + inode->i_rdev = MKDEV(di->di_major, 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_mode = di->di_mode; + 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; + 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_blksize = PAGE_SIZE; - inode->i_blocks = ip->i_di.di_blocks << + inode->i_blocks = di->di_blocks << (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); - if (ip->i_di.di_flags & GFS2_DIF_IMMUTABLE) + if (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) + if (di->di_flags & GFS2_DIF_APPENDONLY) inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; -- GitLab From 82ffa51637f9239aaddd3151fb0d41c657f760db Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 14:47:06 -0400 Subject: [PATCH 0227/1619] [GFS2] More style changes As per Jan Engelhardt's fourth email, this is the first part of the change set with a few minor style points. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 9 ++++----- fs/gfs2/meta_io.c | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 456d6ad1049..5898d6d3c1f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -118,7 +118,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) unsigned n; __be64 *ptr; - offset += (sizeof(__be64) - 1); + offset += sizeof(__be64) - 1; offset &= ~(sizeof(__be64) - 1); limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64); /* for 4k blocks, limit = 503 */ @@ -219,8 +219,8 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, continue; error = gfs2_replay_read_block(jd, start, &bh_log); - if (error) - return error; + if (error) + return error; bh_ip = gfs2_meta_new(gl, blkno); memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size); @@ -248,8 +248,7 @@ static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { - gfs2_meta_sync(ip->i_gl, - DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); return; } if (pass != 1) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 5b10379c20e..6af3521339f 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -460,11 +460,10 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, 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); - } bh->b_private = bd; if (meta) -- GitLab From 38c60ef228596c8e331437ea9287ce035706b107 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 14:48:37 -0400 Subject: [PATCH 0228/1619] [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(-) diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 03881f9870f..1025960b0e6 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 3ebd8743ce8..a7ae7c177ca 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__ */ -- GitLab From dd538c832aaf8e35c46c98a825fa9dacee3cf226 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 14:53:30 -0400 Subject: [PATCH 0229/1619] [GFS2] Spelling sentinal -> sentinel A spelling mistake (one of mine). Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 6 +++--- fs/gfs2/ops_file.c | 4 ++-- fs/gfs2/ops_file.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index ae9c46e7539..96988ccf208 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -262,7 +262,7 @@ static int gfs2_readpage(struct file *file, struct page *page) int error; int do_unlock = 0; - if (likely(file != &gfs2_internal_file_sentinal)) { + if (likely(file != &gfs2_internal_file_sentinel)) { if (file) { struct gfs2_file *gf = file->private_data; if (test_bit(GFF_EXLOCK, &gf->f_flags)) @@ -285,7 +285,7 @@ skip_lock: if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = -EIO; - if (file != &gfs2_internal_file_sentinal) { + if (file != &gfs2_internal_file_sentinel) { gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); } @@ -324,7 +324,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, int ret; int do_unlock = 0; - if (likely(file != &gfs2_internal_file_sentinal)) { + if (likely(file != &gfs2_internal_file_sentinel)) { if (file) { struct gfs2_file *gf = file->private_data; if (test_bit(GFF_EXLOCK, &gf->f_flags)) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index f5ddd496d3e..9dcf72aa9f6 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -79,7 +79,7 @@ struct filldir_reg { * any other part of this. Its use is purely as a flag so that we * know (in readpage()) whether or not do to locking. */ -struct file gfs2_internal_file_sentinal = { +struct file gfs2_internal_file_sentinel = { .f_flags = O_NOATIME|O_RDONLY, }; @@ -112,7 +112,7 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, desc.count = size; desc.error = 0; do_generic_mapping_read(inode->i_mapping, ra_state, - &gfs2_internal_file_sentinal, pos, &desc, + &gfs2_internal_file_sentinel, pos, &desc, gfs2_read_actor); return desc.written ? desc.written : desc.error; } diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index 064e52c3066..b1c1bf838ec 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -9,7 +9,7 @@ #ifndef __OPS_FILE_DOT_H__ #define __OPS_FILE_DOT_H__ -extern struct file gfs2_internal_file_sentinal; +extern struct file gfs2_internal_file_sentinel; extern int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, char *buf, loff_t *pos, unsigned size); -- GitLab From 0bd5996a00346fee772cbdebc5666fd4e514089b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 14:59:35 -0400 Subject: [PATCH 0230/1619] [GFS2] Style changes in ops_address.c As per the remainder of Jan Engelhardt's fourth email comments, remove an cast thats not required. Also tidy up the "limit" code in stuck_releasepage(). Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 96988ccf208..d44d42fb416 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -517,7 +517,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, kaddr = kmap_atomic(page, KM_USER0); memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, - (char *)kaddr + from, to - from); + kaddr + from, to - from); kunmap_atomic(page, KM_USER0); SetPageUptodate(page); @@ -704,8 +704,9 @@ static void stuck_releasepage(struct buffer_head *bh) struct gfs2_glock *gl; static unsigned limit = 0; - if (limit++ > 3) + if (limit > 3) return; + limit++; fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", -- GitLab From 26c1a57412b59a2284a521c711d9e9105bb6ad23 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 15:32:10 -0400 Subject: [PATCH 0231/1619] [GFS2] More code style updates As per Jan Engelhardt's fifth email. This has most of the changes recommended, which is the removal of casts which are not required, some indenting fixes and similar. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 60 ++++++++++++++++++++++---------------------- fs/gfs2/ops_fstype.c | 4 +-- fs/gfs2/ops_inode.c | 2 +- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 9dcf72aa9f6..b551074a3c9 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -94,12 +94,12 @@ static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, kaddr = kmap(page); memcpy(desc->arg.buf, kaddr + offset, size); - kunmap(page); + kunmap(page); - desc->count = count - size; - desc->written += size; - desc->arg.buf += size; - return size; + 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, @@ -700,7 +700,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) 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; + flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; mutex_lock(&fp->f_fl_mutex); @@ -780,32 +780,32 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) } const struct file_operations gfs2_file_fops = { - .llseek = gfs2_llseek, - .read = generic_file_read, - .readv = generic_file_readv, - .aio_read = generic_file_aio_read, - .write = generic_file_write, - .writev = generic_file_writev, - .aio_write = generic_file_aio_write, - .unlocked_ioctl = gfs2_ioctl, - .mmap = gfs2_mmap, - .open = gfs2_open, - .release = gfs2_close, - .fsync = gfs2_fsync, - .lock = gfs2_lock, - .sendfile = generic_file_sendfile, - .flock = gfs2_flock, - .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .llseek = gfs2_llseek, + .read = generic_file_read, + .readv = generic_file_readv, + .aio_read = generic_file_aio_read, + .write = generic_file_write, + .writev = generic_file_writev, + .aio_write = generic_file_aio_write, + .unlocked_ioctl = gfs2_ioctl, + .mmap = gfs2_mmap, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .lock = gfs2_lock, + .sendfile = generic_file_sendfile, + .flock = gfs2_flock, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, }; const struct file_operations gfs2_dir_fops = { - .readdir = gfs2_readdir, - .unlocked_ioctl = gfs2_ioctl, - .open = gfs2_open, - .release = gfs2_close, - .fsync = gfs2_fsync, - .lock = gfs2_lock, - .flock = gfs2_flock, + .readdir = gfs2_readdir, + .unlocked_ioctl = gfs2_ioctl, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .lock = gfs2_lock, + .flock = gfs2_flock, }; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index d39314d5dd0..c94422b30ce 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -791,7 +791,7 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, if (error) goto out; sb = mnt->mnt_sb; - sdp = (struct gfs2_sbd*)sb->s_fs_info; + sdp = sb->s_fs_info; sdp->sd_gfs2mnt = mnt; out: return error; @@ -832,7 +832,7 @@ static int set_bdev_super(struct super_block *s, void *data) static int test_bdev_super(struct super_block *s, void *data) { - return (void *)s->s_bdev == data; + return s->s_bdev == data; } static struct super_block* get_gfs2_sb(const char *dev_name) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index c680f050e17..2f38313b4bd 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -1014,7 +1014,7 @@ out: /** * gfs2_getattr - Read out an inode's attributes - * @mnt: ? + * @mnt: The vfsmount the inode is being accessed from * @dentry: The dentry to stat * @stat: The inode's stats * -- GitLab From 5acd3967347dab361d296d39ba19f8241507ef65 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 16:16:45 -0400 Subject: [PATCH 0232/1619] [GFS2] Some further style changes Introduce a couple of new constants which make the NFS filehandle sizes that GFS2 uses a bit clearer. Also fix one or two minor issues as per Jan Engelhardt's sixth email. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_export.c | 11 ++++++----- fs/gfs2/ops_export.h | 3 +++ fs/gfs2/ops_super.c | 6 ++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index cf826893dd5..4b8c6a9893e 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -45,13 +45,13 @@ static struct dentry *gfs2_decode_fh(struct super_block *sb, memset(&parent, 0, sizeof(struct gfs2_inum)); switch (fh_type) { - case 10: + case GFS2_LARGE_FH_SIZE: parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32; parent.no_formal_ino |= be32_to_cpu(fh[5]); parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32; parent.no_addr |= be32_to_cpu(fh[7]); fh_obj.imode = be32_to_cpu(fh[8]); - case 4: + case GFS2_SMALL_FH_SIZE: this->no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32; this->no_formal_ino |= be32_to_cpu(fh[1]); this->no_addr = ((u64)be32_to_cpu(fh[2])) << 32; @@ -72,7 +72,8 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, struct super_block *sb = inode->i_sb; struct gfs2_inode *ip = GFS2_I(inode); - if (*len < 4 || (connectable && *len < 10)) + if (*len < GFS2_SMALL_FH_SIZE || + (connectable && *len < GFS2_LARGE_FH_SIZE)) return 255; fh[0] = ip->i_num.no_formal_ino >> 32; @@ -83,7 +84,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[2] = cpu_to_be32(fh[2]); fh[3] = ip->i_num.no_addr & 0xFFFFFFFF; fh[3] = cpu_to_be32(fh[3]); - *len = 4; + *len = GFS2_SMALL_FH_SIZE; if (!connectable || inode == sb->s_root->d_inode) return *len; @@ -105,7 +106,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[8] = cpu_to_be32(inode->i_mode); fh[9] = 0; /* pad to double word */ - *len = 10; + *len = GFS2_LARGE_FH_SIZE; iput(inode); diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h index d52c2d93010..09aca5046fb 100644 --- a/fs/gfs2/ops_export.h +++ b/fs/gfs2/ops_export.h @@ -10,6 +10,9 @@ #ifndef __OPS_EXPORT_DOT_H__ #define __OPS_EXPORT_DOT_H__ +#define GFS2_SMALL_FH_SIZE 4 +#define GFS2_LARGE_FH_SIZE 10 + extern struct export_operations gfs2_export_ops; struct gfs2_fh_obj { struct gfs2_inum this; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 6ced7124037..820db9333bd 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -79,7 +79,7 @@ static void gfs2_put_super(struct super_block *sb) return; if (!strncmp(sb->s_type->name, "gfs2meta", 8)) - return; /* meta fs. don't do nothin' */ + return; /* Nothing to do */ /* Unfreeze the filesystem, if we need to */ @@ -136,7 +136,6 @@ static void gfs2_put_super(struct super_block *sb) /* At this point, we're through participating in the lockspace */ gfs2_sys_fs_del(sdp); vfree(sdp); - sb->s_fs_info = NULL; } /** @@ -149,8 +148,7 @@ static void gfs2_put_super(struct super_block *sb) static void gfs2_write_super(struct super_block *sb) { - struct gfs2_sbd *sdp = sb->s_fs_info; - gfs2_log_flush(sdp, NULL); + gfs2_log_flush(sb->s_fs_info, NULL); } /** -- GitLab From 2bdbc5d73961c040fdc9b30d985fab3047d697a0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 09:34:20 -0400 Subject: [PATCH 0233/1619] [GFS2] Directory code style changes As per comments from Jan Engelhardt, remove redundant casts, redundant endian conversions, add a smattering of const and rewrite the dirent_next function in order to avoid as many casts as possible. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 92 ++++++++++++++++++++++----------------------- fs/gfs2/dir.h | 4 +- fs/gfs2/ops_super.c | 3 +- 3 files changed, 47 insertions(+), 52 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 2023dc4ea30..d74a52bda54 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -81,9 +81,10 @@ #define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) -typedef int (*leaf_call_t) (struct gfs2_inode *dip, - u32 index, u32 len, u64 leaf_no, - void *data); +typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len, + u64 leaf_no, void *data); +typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, + const struct qstr *name, void *opaque); int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, @@ -348,17 +349,13 @@ fail: return (copied) ? copied : error; } -typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, - const struct qstr *name, - void *opaque); - 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) + memcmp(dent+1, name->name, name->len) == 0) return ret; return 0; } @@ -483,8 +480,7 @@ wrong_type: return -1; } -static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, - void *buf, +static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, unsigned int len, gfs2_dscan_t scan, const struct qstr *name, void *opaque) @@ -500,7 +496,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, offset = ret; prev = NULL; - dent = (struct gfs2_dirent *)(buf + offset); + dent = buf + offset; size = be16_to_cpu(dent->de_rec_len); if (gfs2_check_dirent(dent, offset, size, len, 1)) goto consist_inode; @@ -512,7 +508,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, if (offset == len) break; prev = dent; - dent = (struct gfs2_dirent *)(buf + offset); + dent = buf + offset; size = be16_to_cpu(dent->de_rec_len); if (gfs2_check_dirent(dent, offset, size, len, 0)) goto consist_inode; @@ -567,6 +563,24 @@ static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, } } +static int dirent_check_reclen(struct gfs2_inode *dip, + const struct gfs2_dirent *d, const void *end_p) +{ + const void *ptr = d; + u16 rec_len = be16_to_cpu(d->de_rec_len); + + if (unlikely(rec_len < sizeof(struct gfs2_dirent))) + goto broken; + ptr += rec_len; + if (ptr < end_p) + return rec_len; + if (ptr == end_p) + return -ENOENT; +broken: + gfs2_consist_inode(dip); + return -EIO; +} + /** * dirent_next - Next dirent * @dip: the directory @@ -579,33 +593,18 @@ static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent **dent) { - struct gfs2_dirent *tmp, *cur; - char *bh_end; - u16 cur_rec_len; - - cur = *dent; - bh_end = bh->b_data + bh->b_size; - 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) { - gfs2_consist_inode(dip); - return -EIO; - } - return -ENOENT; - } - - tmp = (struct gfs2_dirent *)((char *)cur + cur_rec_len); + struct gfs2_dirent *cur = *dent, *tmp; + char *bh_end = bh->b_data + bh->b_size; + int ret; - if ((char *)tmp + be16_to_cpu(tmp->de_rec_len) > bh_end) { - gfs2_consist_inode(dip); - return -EIO; - } + ret = dirent_check_reclen(dip, cur, bh_end); + if (ret < 0) + return ret; - if (cur_rec_len == 0) { - gfs2_consist_inode(dip); - return -EIO; - } + tmp = (void *)cur + ret; + ret = dirent_check_reclen(dip, tmp, bh_end); + if (ret == -EIO) + return ret; /* Only the first dent could ever have de_inum.no_addr == 0 */ if (!tmp->de_inum.no_addr) { @@ -614,7 +613,6 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, } *dent = tmp; - return 0; } @@ -821,9 +819,9 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, 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_entries = 0; leaf->lf_dirent_format = cpu_to_be16(GFS2_FORMAT_DE); - leaf->lf_next = cpu_to_be64(0); + leaf->lf_next = 0; memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); dent = (struct gfs2_dirent *)(leaf+1); gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); @@ -1152,14 +1150,14 @@ fail: static int compare_dents(const void *a, const void *b) { - struct gfs2_dirent *dent_a, *dent_b; + const struct gfs2_dirent *dent_a, *dent_b; u32 hash_a, hash_b; int ret = 0; - dent_a = *(struct gfs2_dirent **)a; + dent_a = *(const struct gfs2_dirent **)a; hash_a = be32_to_cpu(dent_a->de_hash); - dent_b = *(struct gfs2_dirent **)b; + dent_b = *(const struct gfs2_dirent **)b; hash_b = be32_to_cpu(dent_b->de_hash); if (hash_a > hash_b) @@ -1175,9 +1173,7 @@ static int compare_dents(const void *a, const void *b) else if (len_a < len_b) ret = -1; else - ret = memcmp((char *)(dent_a + 1), - (char *)(dent_b + 1), - len_a); + ret = memcmp(dent_a + 1, dent_b + 1, len_a); } return ret; @@ -1246,7 +1242,7 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, gfs2_inum_in(&inum, (char *)&dent->de_inum); - error = filldir(opaque, (char *)(dent + 1), + error = filldir(opaque, (const char *)(dent + 1), be16_to_cpu(dent->de_name_len), off, &inum, be16_to_cpu(dent->de_type)); @@ -1298,7 +1294,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, return 0; error = -ENOMEM; - larr = vmalloc((leaves + entries) * sizeof(void*)); + larr = vmalloc((leaves + entries) * sizeof(void *)); if (!larr) goto out; darr = (const struct gfs2_dirent **)(larr + leaves); diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index f1f83faa36e..d32449f0839 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -46,7 +46,7 @@ int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, static inline u32 gfs2_disk_hash(const char *data, int len) { - return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF; + return crc32_le((u32)~0, data, len) ^ (u32)~0; } @@ -67,7 +67,7 @@ static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct 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); + memcpy(dent + 1, name->name, name->len); } #endif /* __DIR_DOT_H__ */ diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 820db9333bd..addcf1334b3 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -190,8 +190,7 @@ static void gfs2_write_super_lockfs(struct super_block *sb) static void gfs2_unlockfs(struct super_block *sb) { - struct gfs2_sbd *sdp = sb->s_fs_info; - gfs2_unfreeze_fs(sdp); + gfs2_unfreeze_fs(sb->s_fs_info); } /** -- GitLab From f2f7ba5237e2fe10ba3e328a4f728b9e1ff141da Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 10:39:21 -0400 Subject: [PATCH 0234/1619] [GFS2] Make headers compile on their own As per Jan Engelhardt's comments, this should make all the headers compile on their own by including and/or declaring structures early. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.h | 2 ++ fs/gfs2/bmap.h | 4 ++++ fs/gfs2/dir.h | 6 ++++++ fs/gfs2/eaops.h | 1 + fs/gfs2/eattr.h | 3 +++ fs/gfs2/glock.h | 2 ++ fs/gfs2/glops.h | 2 ++ fs/gfs2/incore.h | 2 ++ fs/gfs2/lm.h | 2 ++ fs/gfs2/log.h | 4 ++++ fs/gfs2/lops.h | 3 +++ fs/gfs2/meta_io.h | 4 ++++ fs/gfs2/mount.h | 2 ++ fs/gfs2/ops_address.h | 4 ++++ fs/gfs2/ops_dentry.h | 2 ++ fs/gfs2/ops_file.h | 4 ++++ fs/gfs2/ops_fstype.h | 2 ++ fs/gfs2/ops_inode.h | 2 ++ fs/gfs2/ops_super.h | 2 ++ fs/gfs2/ops_vm.h | 2 ++ fs/gfs2/quota.h | 3 +++ fs/gfs2/recovery.h | 2 ++ fs/gfs2/rgrp.h | 4 ++++ fs/gfs2/super.h | 2 ++ fs/gfs2/sys.h | 3 +++ fs/gfs2/trans.h | 9 +++++++-- fs/gfs2/util.h | 1 + 27 files changed, 77 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index 5856ba76468..05c294fe0d7 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -10,6 +10,8 @@ #ifndef __ACL_DOT_H__ #define __ACL_DOT_H__ +#include "incore.h" + #define GFS2_POSIX_ACL_ACCESS "posix_acl_access" #define GFS2_POSIX_ACL_ACCESS_LEN 16 #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index cb3b624fea3..503f1cdda29 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -10,6 +10,10 @@ #ifndef __BMAP_DOT_H__ #define __BMAP_DOT_H__ +struct inode; +struct gfs2_inode; +struct page; + int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index d32449f0839..371233419b0 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -10,6 +10,12 @@ #ifndef __DIR_DOT_H__ #define __DIR_DOT_H__ +#include + +struct inode; +struct gfs2_inode; +struct gfs2_inum; + /** * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read() * @opaque: opaque data used by the function diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 1c27700ee8b..b045897e1e8 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -11,6 +11,7 @@ #define __EAOPS_DOT_H__ struct gfs2_ea_request; +struct gfs2_inode; struct gfs2_eattr_operations { int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er); diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index 85c70c335c5..cb7c2d84676 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -10,6 +10,9 @@ #ifndef __EATTR_DOT_H__ #define __EATTR_DOT_H__ +struct gfs2_inode; +struct iattr; + #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) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 4762cdb04f6..2e1d3286632 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -10,6 +10,8 @@ #ifndef __GLOCK_DOT_H__ #define __GLOCK_DOT_H__ +#include "incore.h" + /* Flags for lock requests; used in gfs2_holder gh_flag field. From lm_interface.h: #define LM_FLAG_TRY 0x00000001 diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h index ba943e47366..a1d9b5b024e 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h @@ -10,6 +10,8 @@ #ifndef __GLOPS_DOT_H__ #define __GLOPS_DOT_H__ +#include "incore.h" + extern const struct gfs2_glock_operations gfs2_meta_glops; extern const struct gfs2_glock_operations gfs2_inode_glops; extern const struct gfs2_glock_operations gfs2_rgrp_glops; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 407afd18fa2..225924ca6b3 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -10,6 +10,8 @@ #ifndef __INCORE_DOT_H__ #define __INCORE_DOT_H__ +#include + #define DIO_FORCE 0x00000001 #define DIO_CLEAN 0x00000002 #define DIO_DIRTY 0x00000004 diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h index dbef88852ef..6b890e73e6c 100644 --- a/fs/gfs2/lm.h +++ b/fs/gfs2/lm.h @@ -10,6 +10,8 @@ #ifndef __LM_DOT_H__ #define __LM_DOT_H__ +struct gfs2_sbd; + #define GFS2_MIN_LVB_SIZE 32 int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 80764e388bb..7f5737d5561 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -10,6 +10,10 @@ #ifndef __LOG_DOT_H__ #define __LOG_DOT_H__ +#include +#include +#include "incore.h" + /** * gfs2_log_lock - acquire the right to mess with the log manager * @sdp: the filesystem diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 2e3365c2b10..5839c05ae6b 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -10,6 +10,9 @@ #ifndef __LOPS_DOT_H__ #define __LOPS_DOT_H__ +#include +#include "incore.h" + extern const struct gfs2_log_operations gfs2_glock_lops; extern const struct gfs2_log_operations gfs2_buf_lops; extern const struct gfs2_log_operations gfs2_revoke_lops; diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 9a9acc94029..086a472df3f 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -10,6 +10,10 @@ #ifndef __DIO_DOT_H__ #define __DIO_DOT_H__ +#include +#include +#include "incore.h" + static inline void gfs2_buffer_clear(struct buffer_head *bh) { memset(bh->b_data, 0, bh->b_size); diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h index 8a21897b63e..401288acfdf 100644 --- a/fs/gfs2/mount.h +++ b/fs/gfs2/mount.h @@ -10,6 +10,8 @@ #ifndef __MOUNT_DOT_H__ #define __MOUNT_DOT_H__ +struct gfs2_sbd; + int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount); #endif /* __MOUNT_DOT_H__ */ diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index 6c07aa2bd98..35aaee4aa7e 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -10,6 +10,10 @@ #ifndef __OPS_ADDRESS_DOT_H__ #define __OPS_ADDRESS_DOT_H__ +#include +#include +#include + 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); diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h index e7b05e5c62e..5caa3db4d3f 100644 --- a/fs/gfs2/ops_dentry.h +++ b/fs/gfs2/ops_dentry.h @@ -10,6 +10,8 @@ #ifndef __OPS_DENTRY_DOT_H__ #define __OPS_DENTRY_DOT_H__ +#include + extern struct dentry_operations gfs2_dops; #endif /* __OPS_DENTRY_DOT_H__ */ diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h index b1c1bf838ec..ce319f89ec8 100644 --- a/fs/gfs2/ops_file.h +++ b/fs/gfs2/ops_file.h @@ -9,6 +9,10 @@ #ifndef __OPS_FILE_DOT_H__ #define __OPS_FILE_DOT_H__ + +#include +struct gfs2_inode; + extern struct file gfs2_internal_file_sentinel; extern int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h index b85ecce3ca6..7cc2c296271 100644 --- a/fs/gfs2/ops_fstype.h +++ b/fs/gfs2/ops_fstype.h @@ -10,6 +10,8 @@ #ifndef __OPS_FSTYPE_DOT_H__ #define __OPS_FSTYPE_DOT_H__ +#include + extern struct file_system_type gfs2_fs_type; extern struct file_system_type gfs2meta_fs_type; diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index 6f4b54783d2..b15acb4fd34 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h @@ -10,6 +10,8 @@ #ifndef __OPS_INODE_DOT_H__ #define __OPS_INODE_DOT_H__ +#include + extern struct inode_operations gfs2_file_iops; extern struct inode_operations gfs2_dir_iops; extern struct inode_operations gfs2_symlink_iops; diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h index cbc4f73e9a9..9de73f042f7 100644 --- a/fs/gfs2/ops_super.h +++ b/fs/gfs2/ops_super.h @@ -10,6 +10,8 @@ #ifndef __OPS_SUPER_DOT_H__ #define __OPS_SUPER_DOT_H__ +#include + extern struct super_operations gfs2_super_ops; #endif /* __OPS_SUPER_DOT_H__ */ diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h index d5ba4b9c50f..4ae8f43ed5e 100644 --- a/fs/gfs2/ops_vm.h +++ b/fs/gfs2/ops_vm.h @@ -10,6 +10,8 @@ #ifndef __OPS_VM_DOT_H__ #define __OPS_VM_DOT_H__ +#include + extern struct vm_operations_struct gfs2_vm_ops_private; extern struct vm_operations_struct gfs2_vm_ops_sharewrite; diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index d93c61c9936..a8be1417051 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -10,6 +10,9 @@ #ifndef __QUOTA_DOT_H__ #define __QUOTA_DOT_H__ +struct gfs2_inode; +struct gfs2_sbd; + #define NO_QUOTA_CHANGE ((u32)-1) int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid); diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 1b35516b759..961feedf4d8 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -10,6 +10,8 @@ #ifndef __RECOVERY_DOT_H__ #define __RECOVERY_DOT_H__ +#include "incore.h" + static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) { if (++*blk == sdp->sd_jdesc->jd_blocks) diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 3d6ae37e85d..35589576738 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -10,6 +10,10 @@ #ifndef __RGRP_DOT_H__ #define __RGRP_DOT_H__ +struct gfs2_rgrpd; +struct gfs2_sbd; +struct gfs2_holder; + void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk); diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index b073300a93e..5fa5119cfba 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -10,6 +10,8 @@ #ifndef __SUPER_DOT_H__ #define __SUPER_DOT_H__ +#include "incore.h" + void gfs2_tune_init(struct gfs2_tune *gt); int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent); diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h index f8c01b50bfb..1ca8cdac530 100644 --- a/fs/gfs2/sys.h +++ b/fs/gfs2/sys.h @@ -10,6 +10,9 @@ #ifndef __SYS_DOT_H__ #define __SYS_DOT_H__ +#include +struct gfs2_sbd; + /* 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; diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 6550d3d1826..23d4cbe1de5 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -10,6 +10,11 @@ #ifndef __TRANS_DOT_H__ #define __TRANS_DOT_H__ +#include +struct gfs2_sbd; +struct gfs2_rgrpd; +struct gfs2_glock; + #define RES_DINODE 1 #define RES_INDIRECT 1 #define RES_JDATA 1 @@ -20,8 +25,8 @@ #define RES_STATFS 1 #define RES_QUOTA 2 -int gfs2_trans_begin(struct gfs2_sbd *sdp, - unsigned int blocks, unsigned int revokes); +int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, + unsigned int revokes); void gfs2_trans_end(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 204fdb81e34..76a50899fe9 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -10,6 +10,7 @@ #ifndef __UTIL_DOT_H__ #define __UTIL_DOT_H__ +#include "incore.h" #define fs_printk(level, fs, fmt, arg...) \ printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg) -- GitLab From ea67eedb211d3418fa62fe3477e0d19b2888225e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 10:53:09 -0400 Subject: [PATCH 0235/1619] [GFS2] Fix end of multi-line structures As per Jan Engelhardt's request, I've added a ',' to the end of each of the multi-line structures which didn't already have one (most already did). Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 18 +++++++++--------- fs/gfs2/lops.c | 12 ++++++------ fs/gfs2/sys.c | 16 ++++++++-------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d3e7b082a91..0c50a720d01 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -492,7 +492,7 @@ static int quota_go_demote_ok(struct gfs2_glock *gl) const struct gfs2_glock_operations gfs2_meta_glops = { .go_xmote_th = gfs2_glock_xmote_th, .go_drop_th = gfs2_glock_drop_th, - .go_type = LM_TYPE_META + .go_type = LM_TYPE_META, }; const struct gfs2_glock_operations gfs2_inode_glops = { @@ -505,7 +505,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { .go_lock = inode_go_lock, .go_unlock = inode_go_unlock, .go_greedy = inode_greedy, - .go_type = LM_TYPE_INODE + .go_type = LM_TYPE_INODE, }; const struct gfs2_glock_operations gfs2_rgrp_glops = { @@ -516,45 +516,45 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { .go_demote_ok = rgrp_go_demote_ok, .go_lock = rgrp_go_lock, .go_unlock = rgrp_go_unlock, - .go_type = LM_TYPE_RGRP + .go_type = LM_TYPE_RGRP, }; const 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 + .go_type = LM_TYPE_NONDISK, }; const 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 + .go_type = LM_TYPE_IOPEN, }; const 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 + .go_type = LM_TYPE_FLOCK, }; const 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 + .go_type = LM_TYPE_NONDISK, }; const 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 + .go_type = LM_TYPE_QUOTA, }; const 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 + .go_type = LM_TYPE_JOURNAL, }; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 5898d6d3c1f..07655a75561 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -760,7 +760,7 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) const struct gfs2_log_operations gfs2_glock_lops = { .lo_add = glock_lo_add, .lo_after_commit = glock_lo_after_commit, - .lo_name = "glock" + .lo_name = "glock", }; const struct gfs2_log_operations gfs2_buf_lops = { @@ -771,7 +771,7 @@ const struct gfs2_log_operations gfs2_buf_lops = { .lo_before_scan = buf_lo_before_scan, .lo_scan_elements = buf_lo_scan_elements, .lo_after_scan = buf_lo_after_scan, - .lo_name = "buf" + .lo_name = "buf", }; const struct gfs2_log_operations gfs2_revoke_lops = { @@ -780,13 +780,13 @@ const struct gfs2_log_operations gfs2_revoke_lops = { .lo_before_scan = revoke_lo_before_scan, .lo_scan_elements = revoke_lo_scan_elements, .lo_after_scan = revoke_lo_after_scan, - .lo_name = "revoke" + .lo_name = "revoke", }; const struct gfs2_log_operations gfs2_rg_lops = { .lo_add = rg_lo_add, .lo_after_commit = rg_lo_after_commit, - .lo_name = "rg" + .lo_name = "rg", }; const struct gfs2_log_operations gfs2_databuf_lops = { @@ -796,7 +796,7 @@ const struct gfs2_log_operations gfs2_databuf_lops = { .lo_after_commit = databuf_lo_after_commit, .lo_scan_elements = databuf_lo_scan_elements, .lo_after_scan = databuf_lo_after_scan, - .lo_name = "databuf" + .lo_name = "databuf", }; const struct gfs2_log_operations *gfs2_log_ops[] = { @@ -805,6 +805,6 @@ const struct gfs2_log_operations *gfs2_log_ops[] = { &gfs2_revoke_lops, &gfs2_rg_lops, &gfs2_databuf_lops, - NULL + NULL, }; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 8aefda22f98..7a282a4bde2 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -253,7 +253,7 @@ static struct attribute *lockstruct_attrs[] = { &lockstruct_attr_first.attr, &lockstruct_attr_lvb_size.attr, &lockstruct_attr_flags.attr, - NULL + NULL, }; /* @@ -310,7 +310,7 @@ static struct attribute *args_attrs[] = { &args_attr_suiddir.attr, &args_attr_data.attr, &args_attr_noatime.attr, - NULL + NULL, }; /* @@ -339,7 +339,7 @@ static struct attribute *counters_attrs[] = { &counters_attr_glock_held_count.attr, &counters_attr_inode_count.attr, &counters_attr_reclaimed.attr, - NULL + NULL, }; /* @@ -487,27 +487,27 @@ static struct attribute *tune_attrs[] = { &tune_attr_quota_scale.attr, &tune_attr_new_files_jdata.attr, &tune_attr_new_files_directio.attr, - NULL + NULL, }; static struct attribute_group lockstruct_group = { .name = "lockstruct", - .attrs = lockstruct_attrs + .attrs = lockstruct_attrs, }; static struct attribute_group counters_group = { .name = "counters", - .attrs = counters_attrs + .attrs = counters_attrs, }; static struct attribute_group args_group = { .name = "args", - .attrs = args_attrs + .attrs = args_attrs, }; static struct attribute_group tune_group = { .name = "tune", - .attrs = tune_attrs + .attrs = tune_attrs, }; int gfs2_sys_fs_add(struct gfs2_sbd *sdp) -- GitLab From 16910427e1eb2a8069708ee24406d2d465381ebd Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 11:15:45 -0400 Subject: [PATCH 0236/1619] [GFS2] Style changes in rgrp.c Change one constant plus remove a redundant !!. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index af49c8b82ff..baa93c5d959 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -29,7 +29,7 @@ #include "ops_file.h" #include "util.h" -#define BFITNOENT 0xFFFFFFFF +#define BFITNOENT (u32)~0 /* * These routines are used by the resource group routines (rgrp.c) @@ -257,7 +257,7 @@ static inline int rgrp_contains_block(struct gfs2_rindex *ri, u64 block) { u64 first = ri->ri_data0; u64 last = first + ri->ri_data; - return !!(first <= block && block < last); + return first <= block && block < last; } /** -- GitLab From cca195c5c09b81065018dee39f4013b95bf47502 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 13:15:18 -0400 Subject: [PATCH 0237/1619] [GFS2] Extended attribute code style changes As per Jan Engelhardt's request and also a few of my own. It has been possible to add a few most const to the code as a result of the change in gfs2_ea_name2type. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/eaops.c | 8 ++-- fs/gfs2/eaops.h | 2 +- fs/gfs2/eattr.c | 102 ++++++++++++++++++------------------------------ fs/gfs2/eattr.h | 10 ++--- 4 files changed, 48 insertions(+), 74 deletions(-) diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 3b8749c2273..adb898ceaa1 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -31,22 +31,22 @@ * Returns: GFS2_EATYPE_XXX */ -unsigned int gfs2_ea_name2type(const char *name, char **truncated_name) +unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name) { unsigned int type; if (strncmp(name, "system.", 7) == 0) { type = GFS2_EATYPE_SYS; if (truncated_name) - *truncated_name = strchr(name, '.') + 1; + *truncated_name = name + sizeof("system.") - 1; } else if (strncmp(name, "user.", 5) == 0) { type = GFS2_EATYPE_USR; if (truncated_name) - *truncated_name = strchr(name, '.') + 1; + *truncated_name = name + sizeof("user.") - 1; } else if (strncmp(name, "security.", 9) == 0) { type = GFS2_EATYPE_SECURITY; if (truncated_name) - *truncated_name = strchr(name, '.') + 1; + *truncated_name = name + sizeof("security.") - 1; } else { type = GFS2_EATYPE_UNUSED; if (truncated_name) diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index b045897e1e8..508b4f7a244 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -20,7 +20,7 @@ struct gfs2_eattr_operations { char *eo_name; }; -unsigned int gfs2_ea_name2type(const char *name, char **truncated_name); +unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name); extern struct gfs2_eattr_operations gfs2_system_eaops; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index f6b5e306a6c..d7b92fba699 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -68,11 +68,9 @@ static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er) return 0; } -typedef int (*ea_call_t) (struct gfs2_inode *ip, - struct buffer_head *bh, +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); + 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) @@ -86,9 +84,8 @@ static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, 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)) + 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; @@ -118,8 +115,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) u64 *eablk, *end; int error; - error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, - DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_START | DIO_WAIT, &bh); if (error) return error; @@ -143,8 +139,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) break; bn = be64_to_cpu(*eablk); - error = gfs2_meta_read(ip->i_gl, bn, DIO_START | DIO_WAIT, - &eabh); + 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); @@ -184,12 +179,6 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, } } -#if 0 - else if ((ip->i_di.di_flags & GFS2_DIF_EA_PACKED) && - er->er_type == GFS2_EATYPE_SYS) - return 1; -#endif - return 0; } @@ -246,11 +235,12 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, return 0; dataptrs = GFS2_EA2DATAPTRS(ea); - for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) + for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) { if (*dataptrs) { blks++; bn = be64_to_cpu(*dataptrs); } + } if (!blks) return 0; @@ -264,9 +254,8 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, if (error) return error; - error = gfs2_trans_begin(sdp, rgd->rd_ri.ri_length + - RES_DINODE + RES_EATTR + RES_STATFS + - RES_QUOTA, blks); + error = gfs2_trans_begin(sdp, rgd->rd_ri.ri_length + RES_DINODE + + RES_EATTR + RES_STATFS + RES_QUOTA, blks); if (error) goto out_gunlock; @@ -340,9 +329,7 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, if (error) goto out_quota; - error = ea_dealloc_unstuffed(ip, - bh, ea, prev, - (leave) ? &error : NULL); + error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL); gfs2_glock_dq_uninit(&al->al_ri_gh); @@ -423,9 +410,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) er->er_data_len = 0; } - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_SHARED, LM_FLAG_ANY, - &i_gh); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; @@ -445,9 +430,9 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) /** * ea_get_unstuffed - actually copies the unstuffed data into the * request buffer - * @ip: - * @ea: - * @data: + * @ip: The GFS2 inode + * @ea: The extended attribute header structure + * @data: The data to be copied * * Returns: errno */ @@ -492,8 +477,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, goto out; } - memcpy(data, - bh[x]->b_data + sizeof(struct gfs2_meta_header), + memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header), (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); amount -= sdp->sd_jbsize; @@ -511,9 +495,7 @@ 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)); + 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); @@ -521,8 +503,8 @@ int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, /** * gfs2_ea_get_i - - * @ip: - * @er: + * @ip: The GFS2 inode + * @er: The request structure * * Returns: actual size of data on success, -errno on error */ @@ -557,8 +539,8 @@ int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) /** * gfs2_ea_get - - * @ip: - * @er: + * @ip: The GFS2 inode + * @er: The request structure * * Returns: actual size of data on success, -errno on error */ @@ -576,9 +558,7 @@ int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) er->er_data_len = 0; } - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_SHARED, LM_FLAG_ANY, - &i_gh); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; @@ -592,7 +572,7 @@ int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) /** * ea_alloc_blk - allocates a new block for extended attributes. * @ip: A pointer to the inode that's getting extended attributes - * @bhp: + * @bhp: Pointer to pointer to a struct buffer_head * * Returns: errno */ @@ -624,8 +604,8 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) /** * 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 + * @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 @@ -669,14 +649,14 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, ip->i_di.di_blocks++; - copy = (data_len > sdp->sd_jbsize) ? sdp->sd_jbsize : - data_len; + 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((u64)bh->b_blocknr); + *dataptr++ = cpu_to_be64(bh->b_blocknr); data += copy; data_len -= copy; @@ -690,13 +670,11 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, } typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip, - struct gfs2_ea_request *er, - void *private); + 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) + ea_skeleton_call_t skeleton_call, void *private) { struct gfs2_alloc *al; struct buffer_head *dibh; @@ -1013,7 +991,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, goto out; if (private) - ea_set_remove_stuffed(ip, (struct gfs2_ea_location *)private); + ea_set_remove_stuffed(ip, private); out: brelse(indbh); @@ -1101,8 +1079,7 @@ 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) + 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; @@ -1264,8 +1241,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, gfs2_trans_add_bh(ip->i_gl, bh[x], 1); - memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), - data, + memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data, (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); amount -= sdp->sd_jbsize; @@ -1296,8 +1272,7 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, return error; gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); - memcpy(GFS2_EA2DATA(el->el_ea), - data, + 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); @@ -1382,9 +1357,8 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) if (error) goto out_rlist_free; - error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + - RES_INDIRECT + RES_STATFS + - RES_QUOTA, blks); + error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + RES_INDIRECT + + RES_STATFS + RES_QUOTA, blks); if (error) goto out_gunlock; @@ -1457,8 +1431,8 @@ static int ea_dealloc_block(struct gfs2_inode *ip) if (error) return error; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + - RES_STATFS + RES_QUOTA, 1); + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + RES_STATFS + + RES_QUOTA, 1); if (error) goto out_gunlock; diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index cb7c2d84676..ffa65947d68 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -46,7 +46,7 @@ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ #define GFS2_ERF_MODE 0x80000000 struct gfs2_ea_request { - char *er_name; + const char *er_name; char *er_data; unsigned int er_name_len; unsigned int er_data_len; @@ -87,13 +87,13 @@ 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)); + return 5 + ea->ea_name_len + 1; case GFS2_EATYPE_SYS: - return (7 + (ea->ea_name_len + 1)); + return 7 + ea->ea_name_len + 1; case GFS2_EATYPE_SECURITY: - return (9 + (ea->ea_name_len + 1)); + return 9 + ea->ea_name_len + 1; default: - return (0); + return 0; } } -- GitLab From a67cdbd4579c387c021a17c7447da8b88f2a94f4 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 14:41:30 -0400 Subject: [PATCH 0238/1619] [GFS2] Style changes in logging code As per Jan Engelhardt's comments, removed some unused code and removed some brackets which were not required. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 12 +----------- fs/gfs2/lops.c | 2 +- fs/gfs2/recovery.c | 4 ++-- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 57138901287..382a19eea1c 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -177,7 +177,6 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) gfs2_log_lock(sdp); } sdp->sd_log_blks_free -= blks; - /* printk(KERN_INFO "reserved %u blocks (%u left)\n", blks, sdp->sd_log_blks_free); */ gfs2_log_unlock(sdp); mutex_unlock(&sdp->sd_log_reserve_mutex); @@ -198,7 +197,6 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) gfs2_log_lock(sdp); sdp->sd_log_blks_free += blks; - /* printk(KERN_INFO "released %u blocks (%u left)\n", blks, sdp->sd_log_blks_free); */ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); @@ -213,9 +211,8 @@ static u64 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)) { + if (error || !dbn) printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, (unsigned long long)dbn, lbn); - } gfs2_assert_withdraw(sdp, !error && dbn); return dbn; @@ -414,13 +411,6 @@ 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; -#if 0 - 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); -#endif while (!list_empty(head)) { lb = list_entry(head->next, struct gfs2_log_buf, lb_list); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 07655a75561..f8f6d4b56a0 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -518,7 +518,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) unsigned int num, n; __be64 *ptr = NULL; - offset += (2*sizeof(__be64) - 1); + offset += 2*sizeof(__be64) - 1; offset &= ~(2*sizeof(__be64) - 1); limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index ab55191926c..a27569c5d85 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -306,8 +306,8 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, u32 length; __be64 *ptr; unsigned int offset = sizeof(struct gfs2_log_descriptor); - offset += (sizeof(__be64)-1); - offset &= ~(sizeof(__be64)-1); + offset += sizeof(__be64) - 1; + offset &= ~(sizeof(__be64) - 1); while (start != end) { error = gfs2_replay_read_block(jd, start, &bh); -- GitLab From 48fac1790935ef2f9548d92e7c8ba604d1b80c12 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 15:17:12 -0400 Subject: [PATCH 0239/1619] [GFS2] Remove unused code from quota As per Jan Engelhardt's request, some unused code is removed and some consts added in the quota code. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 63 ++++++++----------------------------------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f5830befc30..fe1828ffebf 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -503,24 +503,22 @@ void gfs2_quota_unhold(struct gfs2_inode *ip) 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; + const struct gfs2_quota_data *qd_a = *(const struct gfs2_quota_data **)a; + const struct gfs2_quota_data *qd_b = *(const struct gfs2_quota_data **)b; 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; + return -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 1; } + if (qd_a->qd_id < qd_b->qd_id) + return -1; + if (qd_a->qd_id > qd_b->qd_id) + return 1; - return ret; + return 0; } static void do_qc(struct gfs2_quota_data *qd, s64 change) @@ -622,17 +620,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, gfs2_trans_add_bh(ip->i_gl, bh, 0); kaddr = kmap_atomic(page, KM_USER0); - ptr = (__be64 *)(kaddr + offset); + ptr = kaddr + offset; value = (s64)be64_to_cpu(*ptr) + change; *ptr = cpu_to_be64(value); 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); @@ -1057,43 +1051,6 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) return error; } -#if 0 -int gfs2_quota_read(struct gfs2_sbd *sdp, int user, u32 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 = be64_to_cpu(qd->qd_qb.qb_limit); - q->qu_warn = be64_to_cpu(qd->qd_qb.qb_warn); - q->qu_value = be64_to_cpu(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; -} -#endif /* 0 */ - int gfs2_quota_init(struct gfs2_sbd *sdp) { struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); -- GitLab From 2c1e52aa905f2223dc600cfeda6c0dc94fac8b81 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 15:41:57 -0400 Subject: [PATCH 0240/1619] [GFS2] More style fixes As per Jan Engelhardt's follow up emails, here are a few small fixes which were missed earlier. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 13 +------------ fs/gfs2/rgrp.h | 5 ++++- fs/gfs2/sys.c | 2 +- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index baa93c5d959..7a5ab817ad9 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -29,7 +29,7 @@ #include "ops_file.h" #include "util.h" -#define BFITNOENT (u32)~0 +#define BFITNOENT ((u32)~0) /* * These routines are used by the resource group routines (rgrp.c) @@ -693,17 +693,6 @@ struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) 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 diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 35589576738..9eedfd12bff 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -30,7 +30,10 @@ 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); +static inline void gfs2_alloc_put(struct gfs2_inode *ip) +{ + return; /* Se we can see where ip->i_alloc is used */ +} int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 7a282a4bde2..0d7f0a4e371 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -223,7 +223,7 @@ static struct kobj_type gfs2_ktype = { static struct kset gfs2_kset = { .subsys = &fs_subsys, - .kobj = {.name = "gfs2",}, + .kobj = {.name = "gfs2"}, .ktype = &gfs2_ktype, }; -- GitLab From 7b62536141927212158ab84ce2afda9319ae6f2d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 5 Sep 2006 15:56:17 -0400 Subject: [PATCH 0241/1619] [GFS2] Add a comment in ops_export.c Ass a comment explaining the slightly odd construct used to pass error values back. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_export.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 4b8c6a9893e..470e8829e7f 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -182,6 +182,10 @@ static struct dentry *gfs2_get_parent(struct dentry *child) if (!inode) return ERR_PTR(-ENOENT); + /* + * In case of an error, @inode carries the error value, and we + * have to return that as a(n invalid) pointer to dentry. + */ if (IS_ERR(inode)) return ERR_PTR(PTR_ERR(inode)); -- GitLab From c53921248c79197befa7caa4c17b1af5c077a2c2 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 5 Sep 2006 14:30:40 +0200 Subject: [PATCH 0242/1619] [GFS2] More style changes Remove redundant brackets Signed-off-by: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 4 ++-- fs/gfs2/dir.c | 4 ++-- fs/gfs2/log.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 0f9567fe5c8..57caad7bc0d 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -618,7 +618,7 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, return error; top = (u64 *)(bh->b_data + mh_size) + - ((first) ? mp->mp_list[height] : 0); + (first ? mp->mp_list[height] : 0); bottom = (u64 *)(bh->b_data + mh_size) + sdp->sd_inptrs; } @@ -957,7 +957,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) int error; error = gfs2_trans_begin(sdp, - RES_DINODE + ((journaled) ? RES_JDATA : 0), 0); + RES_DINODE + (journaled ? RES_JDATA : 0), 0); if (error) return error; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index d74a52bda54..f3dbda216ca 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -284,7 +284,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, if (offset >= ip->i_di.di_size) return 0; - if ((offset + size) > ip->i_di.di_size) + if (offset + size > ip->i_di.di_size) size = ip->i_di.di_size - offset; if (!size) @@ -399,7 +399,7 @@ static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, if (!dent->de_inum.no_addr) actual = GFS2_DIRENT_SIZE(0); - if ((totlen - actual) >= required) + if (totlen - actual >= required) return 1; return 0; } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 382a19eea1c..8fce592f401 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -342,8 +342,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) ail2_empty(sdp, new_tail); gfs2_log_lock(sdp); - sdp->sd_log_blks_free += dist - ((pull) ? 1 : 0); - /* printk(KERN_INFO "pull tail refunding %u blocks (%u left) pull=%d\n", dist - ((pull) ? 1 : 0), sdp->sd_log_blks_free, pull); */ + sdp->sd_log_blks_free += dist - (pull ? 1 : 0); + /* printk(KERN_INFO "pull tail refunding %u blocks (%u left) pull=%d\n", dist - (pull ? 1 : 0), sdp->sd_log_blks_free, pull); */ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); -- GitLab From 3204a6c05588788f7686bc45585185a9a4788430 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 6 Sep 2006 16:57:06 -0500 Subject: [PATCH 0243/1619] [GFS2] use snprintf for sysfs show Use snprintf(buf, PAGE_SIZE, ...) instead of sprintf for sysfs show methods. Per instructions in Documentation/filesystems/sysfs.txt Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/sys.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 0d7f0a4e371..88386d8dc05 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -32,12 +32,12 @@ 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); + return snprintf(buf, PAGE_SIZE, "%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); + return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname); } static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) @@ -48,7 +48,7 @@ static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) count = sdp->sd_freeze_count; mutex_unlock(&sdp->sd_freeze_lock); - return sprintf(buf, "%u\n", count); + return snprintf(buf, PAGE_SIZE, "%u\n", count); } static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) @@ -80,7 +80,7 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) 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); + return snprintf(buf, PAGE_SIZE, "%u\n", b); } static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len) @@ -239,7 +239,7 @@ struct lockstruct_attr { #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); \ + return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_lockstruct.ls_##name); \ } \ static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name) @@ -268,7 +268,7 @@ struct args_attr { #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); \ + return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_args.ar_##name); \ } \ static struct args_attr args_attr_##name = __ATTR_RO(name) @@ -290,7 +290,8 @@ 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)); + return snprintf(buf, PAGE_SIZE, "%d\n", + !!test_bit(SDF_NOATIME, &sdp->sd_flags)); } static struct args_attr args_attr_noatime = __ATTR_RO(noatime); @@ -325,7 +326,8 @@ struct counters_attr { #define COUNTERS_ATTR(name, fmt) \ static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ { \ - return sprintf(buf, fmt, (unsigned int)atomic_read(&sdp->sd_##name)); \ + return snprintf(buf, PAGE_SIZE, fmt, \ + (unsigned int)atomic_read(&sdp->sd_##name)); \ } \ static struct counters_attr counters_attr_##name = __ATTR_RO(name) @@ -348,8 +350,9 @@ static struct attribute *counters_attrs[] = { 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); + return snprintf(buf, PAGE_SIZE, "%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, @@ -403,7 +406,7 @@ 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); \ + return snprintf(buf, PAGE_SIZE, "%u\n", sdp->sd_tune.gt_##name); \ } \ TUNE_ATTR_3(name, name##_show, store) -- GitLab From a1d144c71ddc11d3e9d9f29e92cf037da382a541 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 6 Sep 2006 17:01:40 -0500 Subject: [PATCH 0244/1619] [DLM] use snprintf in sysfs show Use snprintf(buf, PAGE_SIZE, ...) instead of sprintf in sysfs show methods. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lockspace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index ff83f80e43e..109333c8ecb 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -66,7 +66,7 @@ static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len) static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf) { - return sprintf(buf, "%u\n", ls->ls_global_id); + return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id); } static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len) @@ -78,12 +78,12 @@ static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len) static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf) { uint32_t status = dlm_recover_status(ls); - return sprintf(buf, "%x\n", status); + return snprintf(buf, PAGE_SIZE, "%x\n", status); } static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf) { - return sprintf(buf, "%d\n", ls->ls_recover_nodeid); + return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid); } struct dlm_attr { -- GitLab From 62f140c173f2c85e15527eefc6e2fb3c37a97eb1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 7 Sep 2006 09:54:55 -0400 Subject: [PATCH 0245/1619] [GFS2] Add brackets in locking/dlm/sysfs.c As per Jan Engelhardt's request. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index 82bef017f94..c1237a91fc6 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -42,8 +42,9 @@ static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len) else if (val == 0) { clear_bit(DFL_BLOCK_LOCKS, &ls->flags); gdlm_submit_delayed(ls); - } else + } else { ret = -EINVAL; + } return ret; } -- GitLab From b8547856f9c158ff70effbcfd15969c908fbe1b3 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 7 Sep 2006 13:12:27 -0400 Subject: [PATCH 0246/1619] [GFS2] Add gfs2 superblock to glock hash function This is another patch preparing for sharing of the glock hash table between different gfs2 mounts. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f2edc8b7612..00769674f2e 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -83,12 +83,14 @@ static inline int relaxed_state_ok(unsigned int actual, unsigned requested, * Returns: The number of the corresponding hash bucket */ -static unsigned int gl_hash(const struct lm_lockname *name) +static unsigned int gl_hash(const struct gfs2_sbd *sdp, + const struct lm_lockname *name) { unsigned int h; h = jhash(&name->ln_number, sizeof(u64), 0); h = jhash(&name->ln_type, sizeof(unsigned int), h); + h = jhash(&sdp, sizeof(struct gfs2_sbd *), h); h &= GFS2_GL_HASH_MASK; return h; @@ -232,7 +234,7 @@ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, const struct lm_lockname *name) { - struct gfs2_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(name)]; + struct gfs2_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(sdp, name)]; struct gfs2_glock *gl; read_lock(&bucket->hb_lock); @@ -266,7 +268,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, name.ln_number = number; name.ln_type = glops->go_type; - bucket = &sdp->sd_gl_hash[gl_hash(&name)]; + bucket = &sdp->sd_gl_hash[gl_hash(sdp, &name)]; read_lock(&bucket->hb_lock); gl = search_bucket(bucket, sdp, &name); -- GitLab From 85d1da67f7e1239afa3494d05be87da6fc3ecada Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 7 Sep 2006 14:40:21 -0400 Subject: [PATCH 0247/1619] [GFS2] Move glock hash table out of superblock There are several reasons why we want to do this: - Firstly its large and thus we'll scale better with multiple GFS2 fs mounted at the same time - Secondly its easier to scale its size as required (thats a plan for later patches) - Thirdly, we can use kzalloc rather than vmalloc when allocating the superblock (its now only 4888 bytes) - Fourth its all part of my plan to eventually be able to use RCU with the glock hash. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 54 ++++++++++++++++++++++++++++---------------- fs/gfs2/glock.h | 2 ++ fs/gfs2/incore.h | 12 ++++------ fs/gfs2/main.c | 6 ++++- fs/gfs2/ops_fstype.c | 9 +------- 5 files changed, 47 insertions(+), 36 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 00769674f2e..5759f52a1cf 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -49,6 +49,8 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl); static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct gfs2_glock *gl); +static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE]; + /** * relaxed_state_ok - is a requested lock compatible with the current lock mode? * @actual: the current state of the lock @@ -231,10 +233,10 @@ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, * Returns: NULL, or the struct gfs2_glock with the requested number */ -static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, +static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp, const struct lm_lockname *name) { - struct gfs2_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(sdp, name)]; + struct gfs2_gl_hash_bucket *bucket = &gl_hash_table[gl_hash(sdp, name)]; struct gfs2_glock *gl; read_lock(&bucket->hb_lock); @@ -268,7 +270,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, name.ln_number = number; name.ln_type = glops->go_type; - bucket = &sdp->sd_gl_hash[gl_hash(sdp, &name)]; + bucket = &gl_hash_table[gl_hash(sdp, &name)]; read_lock(&bucket->hb_lock); gl = search_bucket(bucket, sdp, &name); @@ -648,9 +650,9 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) set_bit(HIF_MUTEX, &gh.gh_iflags); spin_lock(&gl->gl_spin); - if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { list_add_tail(&gh.gh_list, &gl->gl_waiters1); - else { + } else { gl->gl_owner = current; gl->gl_ip = (unsigned long)__builtin_return_address(0); complete(&gh.gh_wait); @@ -673,9 +675,9 @@ static 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)) + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { acquired = 0; - else { + } else { gl->gl_owner = current; gl->gl_ip = (unsigned long)__builtin_return_address(0); } @@ -830,9 +832,9 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) spin_lock(&gl->gl_spin); list_del_init(&gh->gh_list); if (gl->gl_state == gh->gh_state || - gl->gl_state == LM_ST_UNLOCKED) + gl->gl_state == LM_ST_UNLOCKED) { gh->gh_error = 0; - else { + } 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); @@ -1090,8 +1092,7 @@ static int glock_wait_internal(struct gfs2_holder *gh) 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, + gfs2_assert_withdraw(sdp, relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)); if (test_bit(HIF_FIRST, &gh->gh_iflags)) { @@ -1901,6 +1902,8 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, if (test_bit(GLF_PLUG, &gl->gl_flags)) continue; + if (gl->gl_sbd != sdp) + continue; /* examiner() must glock_put() */ gfs2_glock_hold(gl); @@ -1953,7 +1956,7 @@ 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]); + examine_bucket(scan_glock, sdp, &gl_hash_table[x]); cond_resched(); } } @@ -2012,7 +2015,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) cont = 0; for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - if (examine_bucket(clear_glock, sdp, &sdp->sd_gl_hash[x])) + if (examine_bucket(clear_glock, sdp, &gl_hash_table[x])) cont = 1; if (!wait || !cont) @@ -2114,14 +2117,13 @@ static int dump_glock(struct gfs2_glock *gl) spin_lock(&gl->gl_spin); - printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", - gl, - gl->gl_name.ln_type, + printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); printk(KERN_INFO " gl_flags ="); - for (x = 0; x < 32; x++) + for (x = 0; x < 32; x++) { if (test_bit(x, &gl->gl_flags)) printk(" %u", x); + } printk(" \n"); printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref.refcount)); printk(KERN_INFO " gl_state = %u\n", gl->gl_state); @@ -2136,8 +2138,7 @@ static int dump_glock(struct gfs2_glock *gl) printk(KERN_INFO " reclaim = %s\n", (list_empty(&gl->gl_reclaim)) ? "no" : "yes"); if (gl->gl_aspace) - printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", - gl->gl_aspace, + printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace, gl->gl_aspace->i_mapping->nrpages); else printk(KERN_INFO " aspace = no\n"); @@ -2203,13 +2204,15 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) int error = 0; for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { - bucket = &sdp->sd_gl_hash[x]; + bucket = &gl_hash_table[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; + if (gl->gl_sbd != sdp) + continue; error = dump_glock(gl); if (error) @@ -2226,3 +2229,14 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) return error; } +int __init gfs2_glock_init(void) +{ + unsigned i; + for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { + struct gfs2_gl_hash_bucket *hb = &gl_hash_table[i]; + rwlock_init(&hb->hb_lock); + INIT_LIST_HEAD(&hb->hb_list); + } + return 0; +} + diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 2e1d3286632..0febca3d6d4 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -150,4 +150,6 @@ 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 __init gfs2_glock_init(void); + #endif /* __GLOCK_DOT_H__ */ diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 225924ca6b3..61849607211 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -30,7 +30,6 @@ struct gfs2_quota_data; struct gfs2_trans; struct gfs2_ail; struct gfs2_jdesc; -struct gfs2_gl_hash_bucket; struct gfs2_sbd; typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret); @@ -107,6 +106,11 @@ struct gfs2_bufdata { struct list_head bd_ail_gl_list; }; +struct gfs2_gl_hash_bucket { + rwlock_t hb_lock; + struct list_head hb_list; +}; + struct gfs2_glock_operations { void (*go_xmote_th) (struct gfs2_glock * gl, unsigned int state, int flags); @@ -442,11 +446,6 @@ struct gfs2_tune { 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, @@ -489,7 +488,6 @@ struct gfs2_sbd { /* 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; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 143fda727a9..2bdf246436c 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -23,6 +23,7 @@ #include "ops_fstype.h" #include "sys.h" #include "util.h" +#include "glock.h" static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long flags) { @@ -69,8 +70,11 @@ static int __init init_gfs2_fs(void) if (error) return error; - error = -ENOMEM; + error = gfs2_glock_init(); + if (error) + goto fail; + error = -ENOMEM; gfs2_glock_cachep = kmem_cache_create("gfs2_glock", sizeof(struct gfs2_glock), 0, 0, diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c94422b30ce..f5140bdc102 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -45,23 +45,16 @@ extern struct dentry_operations gfs2_dops; static struct gfs2_sbd *init_sbd(struct super_block *sb) { struct gfs2_sbd *sdp; - unsigned int x; - sdp = vmalloc(sizeof(struct gfs2_sbd)); + sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL); if (!sdp) return NULL; - memset(sdp, 0, sizeof(struct gfs2_sbd)); - sb->s_fs_info = sdp; sdp->sd_vfs = sb; gfs2_tune_init(&sdp->sd_tune); - for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { - rwlock_init(&sdp->sd_gl_hash[x].hb_lock); - 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); -- GitLab From b9201ce9a826f5ae4a8e153b52cf5d29f525ca11 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 7 Sep 2006 14:46:39 -0400 Subject: [PATCH 0248/1619] [GFS2] Forgot to remove unused include vmalloc.h Excatly as the subject line says. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index f5140bdc102..f4397ce5148 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include -- GitLab From 1c089c325d5cda0f64a3cf8edf3aaafa148f200a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 7 Sep 2006 15:50:20 -0400 Subject: [PATCH 0249/1619] [GFS2] Remove one typedef This removes one of the typedefs from the locking interface. It is replaced by a forward declaration of the gfs2 superblock. The other two are not so easy to solve since in their case, they can refer to one of two possible structures. Cc: David Teigland Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 5 ++--- fs/gfs2/glock.h | 2 +- fs/gfs2/lm_interface.h | 9 ++++----- fs/gfs2/locking.c | 6 +++--- fs/gfs2/locking/dlm/lock_dlm.h | 2 +- fs/gfs2/locking/dlm/mount.c | 8 ++++---- fs/gfs2/locking/dlm/sysfs.c | 2 +- fs/gfs2/locking/dlm/thread.c | 6 +++--- fs/gfs2/locking/nolock/main.c | 2 +- 9 files changed, 20 insertions(+), 22 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 5759f52a1cf..87b37fe269b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1704,7 +1704,7 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, /** * gfs2_glock_cb - Callback used by locking module - * @fsdata: Pointer to the superblock + * @sdp: Pointer to the superblock * @type: Type of callback * @data: Type dependent data pointer * @@ -1713,9 +1713,8 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, * a journal from another client needs to be recovered. */ -void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data) +void gfs2_glock_cb(struct gfs2_sbd *sdp, unsigned int type, void *data) { - struct gfs2_sbd *sdp = (struct gfs2_sbd *)fsdata; switch (type) { case LM_CB_NEED_E: diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 0febca3d6d4..e3bf4bcd4b2 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -140,7 +140,7 @@ 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_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data); +void gfs2_glock_cb(struct gfs2_sbd *sdp, unsigned int type, void *data); void gfs2_iopen_go_callback(struct gfs2_glock *gl, unsigned int state); diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index e2dfc3da4da..75835e0f425 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -17,10 +17,9 @@ typedef void lm_lockspace_t; typedef void lm_lock_t; -typedef void lm_fsdata_t; +struct gfs2_sbd; -typedef void (*lm_callback_t) (lm_fsdata_t *fsdata, unsigned int type, - void *data); +typedef void (*lm_callback_t) (struct gfs2_sbd *sdp, unsigned int type, void *data); /* * lm_mount() flags @@ -183,7 +182,7 @@ struct lm_lockops { */ int (*lm_mount) (char *table_name, char *host_data, - lm_callback_t cb, lm_fsdata_t *fsdata, + lm_callback_t cb, struct gfs2_sbd *sdp, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj); @@ -275,7 +274,7 @@ void gfs2_unregister_lockproto(struct lm_lockops *proto); */ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, - lm_callback_t cb, lm_fsdata_t *fsdata, + lm_callback_t cb, struct gfs2_sbd *sdp, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj); diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index fce2001e5e2..31421ee6d86 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -99,7 +99,7 @@ void gfs2_unregister_lockproto(struct lm_lockops *proto) * @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 + * @sdp - The GFS2 superblock * @min_lvb_size - the mininum LVB size that the caller can deal with * @flags - LM_MFLAG_* * @lockstruct - a structure returned describing the mount @@ -108,7 +108,7 @@ void gfs2_unregister_lockproto(struct lm_lockops *proto) */ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, - lm_callback_t cb, lm_fsdata_t *fsdata, + lm_callback_t cb, struct gfs2_sbd *sdp, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj) @@ -147,7 +147,7 @@ retry: goto retry; } - error = lw->lw_ops->lm_mount(table_name, host_data, cb, fsdata, + error = lw->lw_ops->lm_mount(table_name, host_data, cb, sdp, min_lvb_size, flags, lockstruct, fskobj); if (error) module_put(lw->lw_ops->lm_owner); diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index c7b6e370258..e6898d23652 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -67,7 +67,7 @@ struct gdlm_ls { int fsflags; dlm_lockspace_t *dlm_lockspace; lm_callback_t fscb; - lm_fsdata_t *fsdata; + struct gfs2_sbd *sdp; int recover_jid; int recover_jid_done; int recover_jid_status; diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 82ac00af84a..8a1764f4d71 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -14,7 +14,7 @@ int gdlm_drop_period; struct lm_lockops gdlm_ops; -static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata, +static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp, int flags, char *table_name) { struct gdlm_ls *ls; @@ -27,7 +27,7 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata, ls->drop_locks_count = gdlm_drop_count; ls->drop_locks_period = gdlm_drop_period; ls->fscb = cb; - ls->fsdata = fsdata; + ls->sdp = sdp; ls->fsflags = flags; spin_lock_init(&ls->async_lock); INIT_LIST_HEAD(&ls->complete); @@ -120,7 +120,7 @@ static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) } static int gdlm_mount(char *table_name, char *host_data, - lm_callback_t cb, lm_fsdata_t *fsdata, + lm_callback_t cb, struct gfs2_sbd *sdp, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj) @@ -131,7 +131,7 @@ static int gdlm_mount(char *table_name, char *host_data, if (min_lvb_size > GDLM_LVB_SIZE) goto out; - ls = init_gdlm(cb, fsdata, flags, table_name); + ls = init_gdlm(cb, sdp, flags, table_name); if (!ls) goto out; diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index c1237a91fc6..29ae06f9494 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -102,7 +102,7 @@ static ssize_t recover_show(struct gdlm_ls *ls, char *buf) 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); + ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid); return len; } diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index d4895ec242f..554bf882a4c 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -41,7 +41,7 @@ static void process_blocking(struct gdlm_lock *lp, int bast_mode) gdlm_assert(0, "unknown bast mode %u", lp->bast_mode); } - ls->fscb(ls->fsdata, cb, &lp->lockname); + ls->fscb(ls->sdp, cb, &lp->lockname); } static void process_complete(struct gdlm_lock *lp) @@ -232,7 +232,7 @@ out: (lp->cur > DLM_LOCK_NL) && (prev_mode > DLM_LOCK_NL)) acb.lc_ret |= LM_OUT_CACHEABLE; - ls->fscb(ls->fsdata, LM_CB_ASYNC, &acb); + ls->fscb(ls->sdp, LM_CB_ASYNC, &acb); } static inline int no_work(struct gdlm_ls *ls, int blocking) @@ -318,7 +318,7 @@ static int gdlm_thread(void *data) gdlm_do_lock(lp); if (drop) - ls->fscb(ls->fsdata, LM_CB_DROPLOCKS, NULL); + ls->fscb(ls->sdp, LM_CB_DROPLOCKS, NULL); schedule(); } diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 95a29914730..e326079430a 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -24,7 +24,7 @@ struct nolock_lockspace { static struct lm_lockops nolock_ops; static int nolock_mount(char *table_name, char *host_data, - lm_callback_t cb, lm_fsdata_t *fsdata, + lm_callback_t cb, struct gfs2_sbd *sdp, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj) -- GitLab From 5ce311ebdb90429519f7c6d2092e4ae6ca8cba74 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 7 Sep 2006 17:35:48 -0400 Subject: [PATCH 0250/1619] [GFS2] Remove unused sync_lvb code from lock modules This code is no longer used for anything and can be removed from the locking modules. The sync_lvb function is not required as this happens automatically with the current locking system. Signed-off-by: Steven Whitehouse --- fs/gfs2/lm_interface.h | 1 - fs/gfs2/locking/dlm/lock.c | 17 ----------------- fs/gfs2/locking/dlm/lock_dlm.h | 1 - fs/gfs2/locking/dlm/mount.c | 1 - fs/gfs2/locking/nolock/main.c | 12 ------------ 5 files changed, 32 deletions(-) diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index 75835e0f425..148136a3462 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -211,7 +211,6 @@ struct lm_lockops { 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 diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index dceea419b94..e4359b1b717 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -490,23 +490,6 @@ void gdlm_unhold_lvb(lm_lock_t *lock, char *lvb) gdlm_del_lvb(lp); } -void gdlm_sync_lvb(lm_lock_t *lock, char *lvb) -{ - struct gdlm_lock *lp = (struct gdlm_lock *) lock; - - if (lp->cur != DLM_LOCK_EX) - return; - - init_completion(&lp->ast_wait); - set_bit(LFL_SYNC_LVB, &lp->flags); - - lp->req = DLM_LOCK_EX; - lp->lkf = make_flags(lp, 0, lp->cur, lp->req); - - gdlm_do_lock(lp); - wait_for_completion(&lp->ast_wait); -} - void gdlm_submit_delayed(struct gdlm_ls *ls) { struct gdlm_lock *lp, *safe; diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index e6898d23652..a4f534a0ecf 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -172,7 +172,6 @@ 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 */ diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 8a1764f4d71..832fb819a2b 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -249,7 +249,6 @@ struct lm_lockops gdlm_ops = { .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/nolock/main.c b/fs/gfs2/locking/nolock/main.c index e326079430a..ba7399787f6 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -162,17 +162,6 @@ static void nolock_unhold_lvb(lm_lock_t *lock, char *lvb) kfree(lvb); } -/** - * nolock_sync_lvb - sync out the value of a lvb - * @lock: the lock the LVB is associated with - * @lvb: the lock value block - * - */ - -static void nolock_sync_lvb(lm_lock_t *lock, char *lvb) -{ -} - static int nolock_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { @@ -221,7 +210,6 @@ static struct lm_lockops nolock_ops = { .lm_cancel = nolock_cancel, .lm_hold_lvb = nolock_hold_lvb, .lm_unhold_lvb = nolock_unhold_lvb, - .lm_sync_lvb = nolock_sync_lvb, .lm_plock_get = nolock_plock_get, .lm_plock = nolock_plock, .lm_punlock = nolock_punlock, -- GitLab From a2c4580797f62b0dd9a48f1e0ce3fe8b8fd76262 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 8 Sep 2006 10:13:03 -0400 Subject: [PATCH 0251/1619] [GFS2] vfree should be kfree This was missed in an earlier patch when changing over from vmalloc to kmalloc for the superblock. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index f4397ce5148..e8b7a1ae163 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -769,7 +769,7 @@ fail_lm: fail_sys: gfs2_sys_fs_del(sdp); fail: - vfree(sdp); + kfree(sdp); sb->s_fs_info = NULL; return error; } -- GitLab From 9b47c11d1cbedcba685c9bd90c73fd41acdfab0e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 8 Sep 2006 10:17:58 -0400 Subject: [PATCH 0252/1619] [GFS2] Use void * instead of typedef for locking module interface As requested by Jan Engelhardt, this removes the typedefs in the locking module interface and replaces them with void *. Also since we are changing the interface, I've added a few consts as well. Cc: Jan Engelhardt Cc: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 3 +- fs/gfs2/glock.h | 2 +- fs/gfs2/incore.h | 2 +- fs/gfs2/lm.c | 14 ++++----- fs/gfs2/lm.h | 14 ++++----- fs/gfs2/lm_interface.h | 57 +++++++++++++--------------------- fs/gfs2/locking.c | 10 +++--- fs/gfs2/locking/dlm/lock.c | 32 +++++++++---------- fs/gfs2/locking/dlm/lock_dlm.h | 22 ++++++------- fs/gfs2/locking/dlm/mount.c | 24 +++++++------- fs/gfs2/locking/dlm/plock.c | 15 +++++---- fs/gfs2/locking/nolock/main.c | 44 +++++++++++++------------- 12 files changed, 113 insertions(+), 126 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 87b37fe269b..92aa0e8c909 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1713,8 +1713,9 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, * a journal from another client needs to be recovered. */ -void gfs2_glock_cb(struct gfs2_sbd *sdp, unsigned int type, void *data) +void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) { + struct gfs2_sbd *sdp = cb_data; switch (type) { case LM_CB_NEED_E: diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index e3bf4bcd4b2..52b8a308635 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -140,7 +140,7 @@ 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_glock_cb(struct gfs2_sbd *sdp, unsigned int type, void *data); +void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); void gfs2_iopen_go_callback(struct gfs2_glock *gl, unsigned int state); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 61849607211..9f5d98ff823 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -187,7 +187,7 @@ struct gfs2_glock { struct gfs2_holder *gl_req_gh; gfs2_glop_bh_t gl_req_bh; - lm_lock_t *gl_lock; + void *gl_lock; char *gl_lvb; atomic_t gl_lvb_count; diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index e60f95cae6c..4e23aa5ef75 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -122,7 +122,7 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) } int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, - lm_lock_t **lockp) + void **lockp) { int error = -EIO; if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) @@ -131,13 +131,13 @@ int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, return error; } -void gfs2_lm_put_lock(struct gfs2_sbd *sdp, lm_lock_t *lock) +void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *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 gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, unsigned int cur_state, unsigned int req_state, unsigned int flags) { @@ -148,7 +148,7 @@ unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, lm_lock_t *lock, return ret; } -unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, lm_lock_t *lock, +unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock, unsigned int cur_state) { int ret = 0; @@ -157,13 +157,13 @@ unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, lm_lock_t *lock, return ret; } -void gfs2_lm_cancel(struct gfs2_sbd *sdp, lm_lock_t *lock) +void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *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 gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp) { int error = -EIO; if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) @@ -171,7 +171,7 @@ int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char **lvbp) return error; } -void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) +void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb) { if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb); diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h index 6b890e73e6c..21cdc30ee08 100644 --- a/fs/gfs2/lm.h +++ b/fs/gfs2/lm.h @@ -20,16 +20,16 @@ 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, + void **lockp); +void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock); +unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *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 gfs2_lm_unlock(struct gfs2_sbd *sdp, void *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_cancel(struct gfs2_sbd *sdp, void *lock); +int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp); +void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *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, diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h index 148136a3462..1418fdc9ac0 100644 --- a/fs/gfs2/lm_interface.h +++ b/fs/gfs2/lm_interface.h @@ -10,16 +10,8 @@ #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; -struct gfs2_sbd; - -typedef void (*lm_callback_t) (struct gfs2_sbd *sdp, unsigned int type, void *data); +typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); /* * lm_mount() flags @@ -175,64 +167,60 @@ struct lm_async_cb { struct lm_lockstruct; struct lm_lockops { - char lm_proto_name[256]; + const char *lm_proto_name; /* * Mount/Unmount */ int (*lm_mount) (char *table_name, char *host_data, - lm_callback_t cb, struct gfs2_sbd *sdp, + 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) (lm_lockspace_t *lockspace); + void (*lm_others_may_mount) (void *lockspace); - void (*lm_unmount) (lm_lockspace_t *lockspace); + void (*lm_unmount) (void *lockspace); - void (*lm_withdraw) (lm_lockspace_t *lockspace); + void (*lm_withdraw) (void *lockspace); /* * Lock oriented operations */ - int (*lm_get_lock) (lm_lockspace_t *lockspace, - struct lm_lockname *name, lm_lock_t **lockp); + int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp); - void (*lm_put_lock) (lm_lock_t *lock); + void (*lm_put_lock) (void *lock); - unsigned int (*lm_lock) (lm_lock_t *lock, unsigned int cur_state, + unsigned int (*lm_lock) (void *lock, unsigned int cur_state, unsigned int req_state, unsigned int flags); - unsigned int (*lm_unlock) (lm_lock_t *lock, unsigned int cur_state); + unsigned int (*lm_unlock) (void *lock, unsigned int cur_state); - void (*lm_cancel) (lm_lock_t *lock); + void (*lm_cancel) (void *lock); - int (*lm_hold_lvb) (lm_lock_t *lock, char **lvbp); - void (*lm_unhold_lvb) (lm_lock_t *lock, char *lvb); + int (*lm_hold_lvb) (void *lock, char **lvbp); + void (*lm_unhold_lvb) (void *lock, char *lvb); /* * Posix Lock oriented operations */ - int (*lm_plock_get) (lm_lockspace_t *lockspace, - struct lm_lockname *name, + int (*lm_plock_get) (void *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl); - int (*lm_plock) (lm_lockspace_t *lockspace, - struct lm_lockname *name, + int (*lm_plock) (void *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, + int (*lm_punlock) (void *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, + void (*lm_recovery_done) (void *lockspace, unsigned int jid, unsigned int message); struct module *lm_owner; @@ -253,8 +241,8 @@ 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; + void *ls_lockspace; + const struct lm_lockops *ls_ops; int ls_flags; }; @@ -263,9 +251,8 @@ struct lm_lockstruct { * with these functions. */ -int gfs2_register_lockproto(struct lm_lockops *proto); - -void gfs2_unregister_lockproto(struct lm_lockops *proto); +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 @@ -273,7 +260,7 @@ void gfs2_unregister_lockproto(struct lm_lockops *proto); */ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, - lm_callback_t cb, struct gfs2_sbd *sdp, + lm_callback_t cb, void *cb_data, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj); diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 31421ee6d86..65eca48b2ea 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -21,7 +21,7 @@ struct lmh_wrapper { struct list_head lw_list; - struct lm_lockops *lw_ops; + const struct lm_lockops *lw_ops; }; /* List of registered low-level locking protocols. A file system selects one @@ -37,7 +37,7 @@ static DEFINE_MUTEX(lmh_lock); * Returns: 0 on success, -EXXX on failure */ -int gfs2_register_lockproto(struct lm_lockops *proto) +int gfs2_register_lockproto(const struct lm_lockops *proto) { struct lmh_wrapper *lw; @@ -72,7 +72,7 @@ int gfs2_register_lockproto(struct lm_lockops *proto) * */ -void gfs2_unregister_lockproto(struct lm_lockops *proto) +void gfs2_unregister_lockproto(const struct lm_lockops *proto) { struct lmh_wrapper *lw; @@ -108,7 +108,7 @@ void gfs2_unregister_lockproto(struct lm_lockops *proto) */ int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, - lm_callback_t cb, struct gfs2_sbd *sdp, + lm_callback_t cb, void *cb_data, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj) @@ -147,7 +147,7 @@ retry: goto retry; } - error = lw->lw_ops->lm_mount(table_name, host_data, cb, sdp, + error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data, min_lvb_size, flags, lockstruct, fskobj); if (error) module_put(lw->lw_ops->lm_owner); diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index e4359b1b717..b167addf9fd 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -207,21 +207,21 @@ void gdlm_delete_lp(struct gdlm_lock *lp) kfree(lp); } -int gdlm_get_lock(lm_lockspace_t *lockspace, struct lm_lockname *name, - lm_lock_t **lockp) +int gdlm_get_lock(void *lockspace, struct lm_lockname *name, + void **lockp) { struct gdlm_lock *lp; int error; - error = gdlm_create_lp((struct gdlm_ls *) lockspace, name, &lp); + error = gdlm_create_lp(lockspace, name, &lp); - *lockp = (lm_lock_t *) lp; + *lockp = lp; return error; } -void gdlm_put_lock(lm_lock_t *lock) +void gdlm_put_lock(void *lock) { - gdlm_delete_lp((struct gdlm_lock *) lock); + gdlm_delete_lp(lock); } unsigned int gdlm_do_lock(struct gdlm_lock *lp) @@ -305,10 +305,10 @@ static unsigned int gdlm_do_unlock(struct gdlm_lock *lp) return LM_OUT_ASYNC; } -unsigned int gdlm_lock(lm_lock_t *lock, unsigned int cur_state, +unsigned int gdlm_lock(void *lock, unsigned int cur_state, unsigned int req_state, unsigned int flags) { - struct gdlm_lock *lp = (struct gdlm_lock *) lock; + struct gdlm_lock *lp = lock; clear_bit(LFL_DLM_CANCEL, &lp->flags); if (flags & LM_FLAG_NOEXP) @@ -321,9 +321,9 @@ unsigned int gdlm_lock(lm_lock_t *lock, unsigned int cur_state, return gdlm_do_lock(lp); } -unsigned int gdlm_unlock(lm_lock_t *lock, unsigned int cur_state) +unsigned int gdlm_unlock(void *lock, unsigned int cur_state) { - struct gdlm_lock *lp = (struct gdlm_lock *) lock; + struct gdlm_lock *lp = lock; clear_bit(LFL_DLM_CANCEL, &lp->flags); if (lp->cur == DLM_LOCK_IV) @@ -331,9 +331,9 @@ unsigned int gdlm_unlock(lm_lock_t *lock, unsigned int cur_state) return gdlm_do_unlock(lp); } -void gdlm_cancel(lm_lock_t *lock) +void gdlm_cancel(void *lock) { - struct gdlm_lock *lp = (struct gdlm_lock *) lock; + struct gdlm_lock *lp = lock; struct gdlm_ls *ls = lp->ls; int error, delay_list = 0; @@ -464,9 +464,9 @@ static void unhold_null_lock(struct gdlm_lock *lp) intact on the resource while the lvb is "held" even if it's holding no locks on the resource. */ -int gdlm_hold_lvb(lm_lock_t *lock, char **lvbp) +int gdlm_hold_lvb(void *lock, char **lvbp) { - struct gdlm_lock *lp = (struct gdlm_lock *) lock; + struct gdlm_lock *lp = lock; int error; error = gdlm_add_lvb(lp); @@ -482,9 +482,9 @@ int gdlm_hold_lvb(lm_lock_t *lock, char **lvbp) return error; } -void gdlm_unhold_lvb(lm_lock_t *lock, char *lvb) +void gdlm_unhold_lvb(void *lock, char *lvb) { - struct gdlm_lock *lp = (struct gdlm_lock *) lock; + struct gdlm_lock *lp = lock; unhold_null_lock(lp); gdlm_del_lvb(lp); diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index a4f534a0ecf..3a45c020d01 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -112,7 +112,7 @@ struct gdlm_lock { s16 cur; s16 req; s16 prev_req; - u32 lkf; /* dlm flags DLM_LKF_ */ + u32 lkf; /* dlm flags DLM_LKF_ */ unsigned long flags; /* lock_dlm flags LFL_ */ int bast_mode; /* protected by async_lock */ @@ -165,23 +165,23 @@ int gdlm_release_all_locks(struct gdlm_ls *); void gdlm_delete_lp(struct gdlm_lock *); unsigned int gdlm_do_lock(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 *); +int gdlm_get_lock(void *, struct lm_lockname *, void **); +void gdlm_put_lock(void *); +unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int); +unsigned int gdlm_unlock(void *, unsigned int); +void gdlm_cancel(void *); +int gdlm_hold_lvb(void *, char **); +void gdlm_unhold_lvb(void *, 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, +int gdlm_plock(void *, struct lm_lockname *, struct file *, int, struct file_lock *); -int gdlm_plock_get(lm_lockspace_t *, struct lm_lockname *, struct file *, +int gdlm_plock_get(void *, struct lm_lockname *, struct file *, struct file_lock *); -int gdlm_punlock(lm_lockspace_t *, struct lm_lockname *, struct file *, +int gdlm_punlock(void *, struct lm_lockname *, struct file *, struct file_lock *); #endif diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 832fb819a2b..1f94dd35a94 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -11,7 +11,7 @@ int gdlm_drop_count; int gdlm_drop_period; -struct lm_lockops gdlm_ops; +const struct lm_lockops gdlm_ops; static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp, @@ -120,7 +120,7 @@ static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) } static int gdlm_mount(char *table_name, char *host_data, - lm_callback_t cb, struct gfs2_sbd *sdp, + lm_callback_t cb, void *cb_data, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj) @@ -131,7 +131,7 @@ static int gdlm_mount(char *table_name, char *host_data, if (min_lvb_size > GDLM_LVB_SIZE) goto out; - ls = init_gdlm(cb, sdp, flags, table_name); + ls = init_gdlm(cb, cb_data, flags, table_name); if (!ls) goto out; @@ -174,9 +174,9 @@ out: return error; } -static void gdlm_unmount(lm_lockspace_t *lockspace) +static void gdlm_unmount(void *lockspace) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; int rv; log_debug("unmount flags %lx", ls->flags); @@ -198,18 +198,18 @@ out: kfree(ls); } -static void gdlm_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, +static void gdlm_recovery_done(void *lockspace, unsigned int jid, unsigned int message) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; ls->recover_jid_done = jid; ls->recover_jid_status = message; kobject_uevent(&ls->kobj, KOBJ_CHANGE); } -static void gdlm_others_may_mount(lm_lockspace_t *lockspace) +static void gdlm_others_may_mount(void *lockspace) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; ls->first_done = 1; kobject_uevent(&ls->kobj, KOBJ_CHANGE); } @@ -218,9 +218,9 @@ static void gdlm_others_may_mount(lm_lockspace_t *lockspace) 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) +static void gdlm_withdraw(void *lockspace) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; kobject_uevent(&ls->kobj, KOBJ_OFFLINE); @@ -233,7 +233,7 @@ static void gdlm_withdraw(lm_lockspace_t *lockspace) gdlm_kobject_release(ls); } -struct lm_lockops gdlm_ops = { +const struct lm_lockops gdlm_ops = { .lm_proto_name = "lock_dlm", .lm_mount = gdlm_mount, .lm_others_may_mount = gdlm_others_may_mount, diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 263636b390f..7365aec9511 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -58,10 +58,10 @@ static void send_op(struct plock_op *op) wake_up(&send_wq); } -int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, +int gdlm_plock(void *lockspace, struct lm_lockname *name, struct file *file, int cmd, struct file_lock *fl) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; struct plock_op *op; int rv; @@ -102,10 +102,10 @@ int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, return rv; } -int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, +int gdlm_punlock(void *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; struct plock_op *op; int rv; @@ -141,10 +141,10 @@ int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, return rv; } -int gdlm_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, +int gdlm_plock_get(void *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { - struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct gdlm_ls *ls = lockspace; struct plock_op *op; int rv; @@ -231,8 +231,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, spin_lock(&ops_lock); list_for_each_entry(op, &recv_list, list) { - if (op->info.fsid == info.fsid && - op->info.number == info.number && + if (op->info.fsid == info.fsid && op->info.number == info.number && op->info.owner == info.owner) { list_del_init(&op->list); found = 1; diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index ba7399787f6..7b263fc6c27 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -21,10 +21,10 @@ struct nolock_lockspace { unsigned int nl_lvb_size; }; -static struct lm_lockops nolock_ops; +static const struct lm_lockops nolock_ops; static int nolock_mount(char *table_name, char *host_data, - lm_callback_t cb, struct gfs2_sbd *sdp, + lm_callback_t cb, void *cb_data, unsigned int min_lvb_size, int flags, struct lm_lockstruct *lockstruct, struct kobject *fskobj) @@ -50,24 +50,24 @@ static int nolock_mount(char *table_name, char *host_data, lockstruct->ls_jid = jid; lockstruct->ls_first = 1; lockstruct->ls_lvb_size = min_lvb_size; - lockstruct->ls_lockspace = (lm_lockspace_t *)nl; + lockstruct->ls_lockspace = nl; lockstruct->ls_ops = &nolock_ops; lockstruct->ls_flags = LM_LSFLAG_LOCAL; return 0; } -static void nolock_others_may_mount(lm_lockspace_t *lockspace) +static void nolock_others_may_mount(void *lockspace) { } -static void nolock_unmount(lm_lockspace_t *lockspace) +static void nolock_unmount(void *lockspace) { - struct nolock_lockspace *nl = (struct nolock_lockspace *)lockspace; + struct nolock_lockspace *nl = lockspace; kfree(nl); } -static void nolock_withdraw(lm_lockspace_t *lockspace) +static void nolock_withdraw(void *lockspace) { } @@ -80,10 +80,10 @@ static void nolock_withdraw(lm_lockspace_t *lockspace) * Returns: 0 on success, -EXXX on failure */ -static int nolock_get_lock(lm_lockspace_t *lockspace, struct lm_lockname *name, - lm_lock_t **lockp) +static int nolock_get_lock(void *lockspace, struct lm_lockname *name, + void **lockp) { - *lockp = (lm_lock_t *)lockspace; + *lockp = lockspace; return 0; } @@ -93,7 +93,7 @@ static int nolock_get_lock(lm_lockspace_t *lockspace, struct lm_lockname *name, * */ -static void nolock_put_lock(lm_lock_t *lock) +static void nolock_put_lock(void *lock) { } @@ -107,7 +107,7 @@ static void nolock_put_lock(lm_lock_t *lock) * Returns: A bitmap of LM_OUT_* */ -static unsigned int nolock_lock(lm_lock_t *lock, unsigned int cur_state, +static unsigned int nolock_lock(void *lock, unsigned int cur_state, unsigned int req_state, unsigned int flags) { return req_state | LM_OUT_CACHEABLE; @@ -121,12 +121,12 @@ static unsigned int nolock_lock(lm_lock_t *lock, unsigned int cur_state, * Returns: 0 */ -static unsigned int nolock_unlock(lm_lock_t *lock, unsigned int cur_state) +static unsigned int nolock_unlock(void *lock, unsigned int cur_state) { return 0; } -static void nolock_cancel(lm_lock_t *lock) +static void nolock_cancel(void *lock) { } @@ -138,9 +138,9 @@ static void nolock_cancel(lm_lock_t *lock) * Returns: 0 on success, -EXXX on failure */ -static int nolock_hold_lvb(lm_lock_t *lock, char **lvbp) +static int nolock_hold_lvb(void *lock, char **lvbp) { - struct nolock_lockspace *nl = (struct nolock_lockspace *)lock; + struct nolock_lockspace *nl = lock; int error = 0; *lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL); @@ -157,12 +157,12 @@ static int nolock_hold_lvb(lm_lock_t *lock, char **lvbp) * */ -static void nolock_unhold_lvb(lm_lock_t *lock, char *lvb) +static void nolock_unhold_lvb(void *lock, char *lvb) { kfree(lvb); } -static int nolock_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, +static int nolock_plock_get(void *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { struct file_lock tmp; @@ -176,7 +176,7 @@ static int nolock_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, return 0; } -static int nolock_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, +static int nolock_plock(void *lockspace, struct lm_lockname *name, struct file *file, int cmd, struct file_lock *fl) { int error; @@ -184,7 +184,7 @@ static int nolock_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, return error; } -static int nolock_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, +static int nolock_punlock(void *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { int error; @@ -192,12 +192,12 @@ static int nolock_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, return error; } -static void nolock_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, +static void nolock_recovery_done(void *lockspace, unsigned int jid, unsigned int message) { } -static struct lm_lockops nolock_ops = { +static const struct lm_lockops nolock_ops = { .lm_proto_name = "lock_nolock", .lm_mount = nolock_mount, .lm_others_may_mount = nolock_others_may_mount, -- GitLab From 37b2fa6a24f996d751dc80fbc8a77602cead269b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 8 Sep 2006 13:35:56 -0400 Subject: [PATCH 0253/1619] [GFS2] Move rwlocks in glock.c into their own array This splits the rwlocks guarding the hash chains of the glock hash table into their own array. This will reduce memory usage in some cases due to better alignment, although the real reason for doing it is to allow the two tables to be different sizes in future (i.e. the locks will be sized proportionally with the max number of CPUs and the hash chains sized proportinally with the size of physical memory) In order to allow this, the gl_bucket member of struct gfs2_glock has now become gl_hash, so we record the hash rather than a pointer to the bucket itself. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 87 +++++++++++++++++++++++------------------------- fs/gfs2/incore.h | 7 +--- 2 files changed, 43 insertions(+), 51 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 92aa0e8c909..49512696160 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -44,12 +44,17 @@ struct greedy { struct work_struct gr_work; }; +struct gfs2_gl_hash_bucket { + struct list_head hb_list; +}; + typedef void (*glock_examiner) (struct gfs2_glock * gl); static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct gfs2_glock *gl); static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE]; +static rwlock_t gl_hash_locks[GFS2_GL_HASH_SIZE]; /** * relaxed_state_ok - is a requested lock compatible with the current lock mode? @@ -154,19 +159,18 @@ static void kill_glock(struct kref *kref) int gfs2_glock_put(struct gfs2_glock *gl) { - struct gfs2_gl_hash_bucket *bucket = gl->gl_bucket; int rv = 0; - write_lock(&bucket->hb_lock); + write_lock(&gl_hash_locks[gl->gl_hash]); if (kref_put(&gl->gl_ref, kill_glock)) { - list_del_init(&gl->gl_list); - write_unlock(&bucket->hb_lock); + list_del_init(&gl_hash_table[gl->gl_hash].hb_list); + write_unlock(&gl_hash_locks[gl->gl_hash]); BUG_ON(spin_is_locked(&gl->gl_spin)); glock_free(gl); rv = 1; goto out; } - write_unlock(&bucket->hb_lock); + write_unlock(&gl_hash_locks[gl->gl_hash]); out: return rv; } @@ -203,13 +207,13 @@ static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head) * Returns: NULL, or the struct gfs2_glock with the requested number */ -static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, +static struct gfs2_glock *search_bucket(unsigned int hash, const struct gfs2_sbd *sdp, const struct lm_lockname *name) { struct gfs2_glock *gl; - list_for_each_entry(gl, &bucket->hb_list, gl_list) { + list_for_each_entry(gl, &gl_hash_table[hash].hb_list, gl_list) { if (test_bit(GLF_PLUG, &gl->gl_flags)) continue; if (!lm_name_equal(&gl->gl_name, name)) @@ -236,12 +240,12 @@ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp, const struct lm_lockname *name) { - struct gfs2_gl_hash_bucket *bucket = &gl_hash_table[gl_hash(sdp, name)]; + unsigned int hash = gl_hash(sdp, name); struct gfs2_glock *gl; - read_lock(&bucket->hb_lock); - gl = search_bucket(bucket, sdp, name); - read_unlock(&bucket->hb_lock); + read_lock(&gl_hash_locks[hash]); + gl = search_bucket(hash, sdp, name); + read_unlock(&gl_hash_locks[hash]); return gl; } @@ -263,18 +267,14 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp) { - struct lm_lockname name; + struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type }; struct gfs2_glock *gl, *tmp; - struct gfs2_gl_hash_bucket *bucket; + unsigned int hash = gl_hash(sdp, &name); int error; - name.ln_number = number; - name.ln_type = glops->go_type; - bucket = &gl_hash_table[gl_hash(sdp, &name)]; - - read_lock(&bucket->hb_lock); - gl = search_bucket(bucket, sdp, &name); - read_unlock(&bucket->hb_lock); + read_lock(&gl_hash_locks[hash]); + gl = search_bucket(hash, sdp, &name); + read_unlock(&gl_hash_locks[hash]); if (gl || !create) { *glp = gl; @@ -289,6 +289,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_name = name; kref_init(&gl->gl_ref); gl->gl_state = LM_ST_UNLOCKED; + gl->gl_hash = hash; gl->gl_owner = NULL; gl->gl_ip = 0; gl->gl_ops = glops; @@ -297,7 +298,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_vn = 0; gl->gl_stamp = jiffies; gl->gl_object = NULL; - gl->gl_bucket = bucket; gl->gl_sbd = sdp; gl->gl_aspace = NULL; lops_init_le(&gl->gl_le, &gfs2_glock_lops); @@ -316,15 +316,15 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, if (error) goto fail_aspace; - write_lock(&bucket->hb_lock); - tmp = search_bucket(bucket, sdp, &name); + write_lock(&gl_hash_locks[hash]); + tmp = search_bucket(hash, sdp, &name); if (tmp) { - write_unlock(&bucket->hb_lock); + write_unlock(&gl_hash_locks[hash]); glock_free(gl); gl = tmp; } else { - list_add_tail(&gl->gl_list, &bucket->hb_list); - write_unlock(&bucket->hb_lock); + list_add_tail(&gl->gl_list, &gl_hash_table[hash].hb_list); + write_unlock(&gl_hash_locks[hash]); } *glp = gl; @@ -1868,7 +1868,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) */ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, - struct gfs2_gl_hash_bucket *bucket) + unsigned int hash) { struct glock_plug plug; struct list_head *tmp; @@ -1879,20 +1879,20 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, 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); + write_lock(&gl_hash_locks[hash]); + list_add(&plug.gl_list, &gl_hash_table[hash].hb_list); + write_unlock(&gl_hash_locks[hash]); for (;;) { - write_lock(&bucket->hb_lock); + write_lock(&gl_hash_locks[hash]); for (;;) { tmp = plug.gl_list.next; - if (tmp == &bucket->hb_list) { + if (tmp == &gl_hash_table[hash].hb_list) { list_del(&plug.gl_list); - entries = !list_empty(&bucket->hb_list); - write_unlock(&bucket->hb_lock); + entries = !list_empty(&gl_hash_table[hash].hb_list); + write_unlock(&gl_hash_locks[hash]); return entries; } gl = list_entry(tmp, struct gfs2_glock, gl_list); @@ -1911,7 +1911,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, break; } - write_unlock(&bucket->hb_lock); + write_unlock(&gl_hash_locks[hash]); examiner(gl); } @@ -1956,7 +1956,7 @@ 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, &gl_hash_table[x]); + examine_bucket(scan_glock, sdp, x); cond_resched(); } } @@ -2015,7 +2015,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) cont = 0; for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - if (examine_bucket(clear_glock, sdp, &gl_hash_table[x])) + if (examine_bucket(clear_glock, sdp, x)) cont = 1; if (!wait || !cont) @@ -2198,17 +2198,15 @@ out: static 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 = &gl_hash_table[x]; - read_lock(&bucket->hb_lock); + read_lock(&gl_hash_locks[x]); - list_for_each_entry(gl, &bucket->hb_list, gl_list) { + list_for_each_entry(gl, &gl_hash_table[x].hb_list, gl_list) { if (test_bit(GLF_PLUG, &gl->gl_flags)) continue; if (gl->gl_sbd != sdp) @@ -2219,7 +2217,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) break; } - read_unlock(&bucket->hb_lock); + read_unlock(&gl_hash_locks[x]); if (error) break; @@ -2233,9 +2231,8 @@ int __init gfs2_glock_init(void) { unsigned i; for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { - struct gfs2_gl_hash_bucket *hb = &gl_hash_table[i]; - rwlock_init(&hb->hb_lock); - INIT_LIST_HEAD(&hb->hb_list); + rwlock_init(&gl_hash_locks[i]); + INIT_LIST_HEAD(&gl_hash_table[i].hb_list); } return 0; } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 9f5d98ff823..f50ea6282e7 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -106,11 +106,6 @@ struct gfs2_bufdata { struct list_head bd_ail_gl_list; }; -struct gfs2_gl_hash_bucket { - rwlock_t hb_lock; - struct list_head hb_list; -}; - struct gfs2_glock_operations { void (*go_xmote_th) (struct gfs2_glock * gl, unsigned int state, int flags); @@ -175,6 +170,7 @@ struct gfs2_glock { spinlock_t gl_spin; unsigned int gl_state; + unsigned int gl_hash; struct task_struct *gl_owner; unsigned long gl_ip; struct list_head gl_holders; @@ -195,7 +191,6 @@ struct gfs2_glock { unsigned long gl_stamp; void *gl_object; - struct gfs2_gl_hash_bucket *gl_bucket; struct list_head gl_reclaim; struct gfs2_sbd *gl_sbd; -- GitLab From fa9f0e4925c7796afd14bf7bbf7a064078818bbc Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 8 Sep 2006 08:36:35 -0500 Subject: [PATCH 0254/1619] [DLM] confirm master for recovered waiting requests Fixing the following scenario: - A request is on the waiters list waiting for a reply from a remote node. - The request is the first one on the resource, so first_lkid is set. - The remote node fails causing recovery. - During recovery the requesting node becomes master. - The request is now processed locally instead of being a remote operation. - At this point we need to call confirm_master() on the resource since we're certain we're now the master node. This will clear first_lkid. - We weren't calling confirm_master(), so first_lkid was not being cleared causing subsequent requests on that resource to get stuck. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 67247f0b508..af2f2f01bd5 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3283,6 +3283,8 @@ int dlm_recover_waiters_post(struct dlm_ls *ls) 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; -- GitLab From ff6af411ae65da95a1801668b9580c5c33f0f7d1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sat, 9 Sep 2006 16:56:34 -0400 Subject: [PATCH 0255/1619] [GFS2] vfree should be kfree (II) The superblock is now created with kmalloc, not vmalloc. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index addcf1334b3..975e93b7992 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -135,7 +134,7 @@ static void gfs2_put_super(struct super_block *sb) /* At this point, we're through participating in the lockspace */ gfs2_sys_fs_del(sdp); - vfree(sdp); + kfree(sdp); } /** -- GitLab From 087efdd391f47305dc251a7b00dcc5d69e8c636a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sat, 9 Sep 2006 16:59:11 -0400 Subject: [PATCH 0256/1619] [GFS2] Make glock hash locks proportional to NR_CPUS Make the number of locks used for hash chains in glock.c proportional to NR_CPUS. Also move constants for the number of hash chains into glock.c from incore.h since they are not used outside of glock.c. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 93 ++++++++++++++++++++++++++++++++++++++---------- fs/gfs2/incore.h | 3 -- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 49512696160..8abfefe4efd 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -53,8 +53,59 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl); static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct gfs2_glock *gl); +#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) + static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE]; -static rwlock_t gl_hash_locks[GFS2_GL_HASH_SIZE]; + +/* + * Despite what you might think, the numbers below are not arbitrary :-) + * They are taken from the ipv4 routing hash code, which is well tested + * and thus should be nearly optimal. Later on we might tweek the numbers + * but for now this should be fine. + * + * The reason for putting the locks in a separate array from the list heads + * is that we can have fewer locks than list heads and save memory. We use + * the same hash function for both, but with a different hash mask. + */ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \ + defined(CONFIG_PROVE_LOCKING) + +#ifdef CONFIG_LOCKDEP +# define GL_HASH_LOCK_SZ 256 +#else +# if NR_CPUS >= 32 +# define GL_HASH_LOCK_SZ 4096 +# elif NR_CPUS >= 16 +# define GL_HASH_LOCK_SZ 2048 +# elif NR_CPUS >= 8 +# define GL_HASH_LOCK_SZ 1024 +# elif NR_CPUS >= 4 +# define GL_HASH_LOCK_SZ 512 +# else +# define GL_HASH_LOCK_SZ 256 +# endif +#endif + +/* We never want more locks than chains */ +#if GFS2_GL_HASH_SIZE < GL_HASH_LOCK_SZ +# undef GL_HASH_LOCK_SZ +# define GL_HASH_LOCK_SZ GFS2_GL_HASH_SIZE +#endif + +static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ]; + +static inline rwlock_t *gl_lock_addr(unsigned int x) +{ + return &gl_hash_locks[(x) & (GL_HASH_LOCK_SZ-1)]; +} +#else /* not SMP, so no spinlocks required */ +static inline rwlock_t *gl_lock_addr(x) +{ + return NULL; +} +#endif /** * relaxed_state_ok - is a requested lock compatible with the current lock mode? @@ -161,16 +212,16 @@ int gfs2_glock_put(struct gfs2_glock *gl) { int rv = 0; - write_lock(&gl_hash_locks[gl->gl_hash]); + write_lock(gl_lock_addr(gl->gl_hash)); if (kref_put(&gl->gl_ref, kill_glock)) { list_del_init(&gl_hash_table[gl->gl_hash].hb_list); - write_unlock(&gl_hash_locks[gl->gl_hash]); + write_unlock(gl_lock_addr(gl->gl_hash)); BUG_ON(spin_is_locked(&gl->gl_spin)); glock_free(gl); rv = 1; goto out; } - write_unlock(&gl_hash_locks[gl->gl_hash]); + write_unlock(gl_lock_addr(gl->gl_hash)); out: return rv; } @@ -243,9 +294,9 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp, unsigned int hash = gl_hash(sdp, name); struct gfs2_glock *gl; - read_lock(&gl_hash_locks[hash]); + read_lock(gl_lock_addr(hash)); gl = search_bucket(hash, sdp, name); - read_unlock(&gl_hash_locks[hash]); + read_unlock(gl_lock_addr(hash)); return gl; } @@ -272,9 +323,9 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, unsigned int hash = gl_hash(sdp, &name); int error; - read_lock(&gl_hash_locks[hash]); + read_lock(gl_lock_addr(hash)); gl = search_bucket(hash, sdp, &name); - read_unlock(&gl_hash_locks[hash]); + read_unlock(gl_lock_addr(hash)); if (gl || !create) { *glp = gl; @@ -316,15 +367,15 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, if (error) goto fail_aspace; - write_lock(&gl_hash_locks[hash]); + write_lock(gl_lock_addr(hash)); tmp = search_bucket(hash, sdp, &name); if (tmp) { - write_unlock(&gl_hash_locks[hash]); + write_unlock(gl_lock_addr(hash)); glock_free(gl); gl = tmp; } else { list_add_tail(&gl->gl_list, &gl_hash_table[hash].hb_list); - write_unlock(&gl_hash_locks[hash]); + write_unlock(gl_lock_addr(hash)); } *glp = gl; @@ -1879,12 +1930,12 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, memset(&plug.gl_flags, 0, sizeof(unsigned long)); set_bit(GLF_PLUG, &plug.gl_flags); - write_lock(&gl_hash_locks[hash]); + write_lock(gl_lock_addr(hash)); list_add(&plug.gl_list, &gl_hash_table[hash].hb_list); - write_unlock(&gl_hash_locks[hash]); + write_unlock(gl_lock_addr(hash)); for (;;) { - write_lock(&gl_hash_locks[hash]); + write_lock(gl_lock_addr(hash)); for (;;) { tmp = plug.gl_list.next; @@ -1892,7 +1943,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, if (tmp == &gl_hash_table[hash].hb_list) { list_del(&plug.gl_list); entries = !list_empty(&gl_hash_table[hash].hb_list); - write_unlock(&gl_hash_locks[hash]); + write_unlock(gl_lock_addr(hash)); return entries; } gl = list_entry(tmp, struct gfs2_glock, gl_list); @@ -1911,7 +1962,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, break; } - write_unlock(&gl_hash_locks[hash]); + write_unlock(gl_lock_addr(hash)); examiner(gl); } @@ -2204,7 +2255,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { - read_lock(&gl_hash_locks[x]); + read_lock(gl_lock_addr(x)); list_for_each_entry(gl, &gl_hash_table[x].hb_list, gl_list) { if (test_bit(GLF_PLUG, &gl->gl_flags)) @@ -2217,7 +2268,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) break; } - read_unlock(&gl_hash_locks[x]); + read_unlock(gl_lock_addr(x)); if (error) break; @@ -2231,9 +2282,13 @@ int __init gfs2_glock_init(void) { unsigned i; for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { - rwlock_init(&gl_hash_locks[i]); INIT_LIST_HEAD(&gl_hash_table[i].hb_list); } +#ifdef GL_HASH_LOCK_SZ + for(i = 0; i < GL_HASH_LOCK_SZ; i++) { + rwlock_init(&gl_hash_locks[i]); + } +#endif return 0; } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index f50ea6282e7..64e13435ca3 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -448,9 +448,6 @@ enum { 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 { -- GitLab From a5e08a9ef50e8b6feb099f8e4b253df04f5ec9db Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sat, 9 Sep 2006 17:07:05 -0400 Subject: [PATCH 0257/1619] [GFS2] Add consts to glock sorting function Add back the consts which were casted away in the glock sorting function. Also add early exit code. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 8abfefe4efd..e941183bbcd 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1494,26 +1494,20 @@ int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, 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; + const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a; + const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b; + const struct lm_lockname *a = &gh_a->gh_gl->gl_name; + const struct lm_lockname *b = &gh_b->gh_gl->gl_name; 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; + return 1; + if (a->ln_number < b->ln_number) + return -1; + if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE) + return 1; + if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL)) + return 1; + return 0; } /** -- GitLab From 94610610f10749c0e17b4d2840ff8a7cb636c413 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sat, 9 Sep 2006 18:59:27 -0400 Subject: [PATCH 0258/1619] [GFS2] Remove unused function from glock.c The callback for iopen locks is unused, so this removes it. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 22 ++-------------------- fs/gfs2/glock.h | 2 -- fs/gfs2/glops.c | 1 - 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index e941183bbcd..b348053c436 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -98,7 +98,7 @@ static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ]; static inline rwlock_t *gl_lock_addr(unsigned int x) { - return &gl_hash_locks[(x) & (GL_HASH_LOCK_SZ-1)]; + return &gl_hash_locks[x & (GL_HASH_LOCK_SZ-1)]; } #else /* not SMP, so no spinlocks required */ static inline rwlock_t *gl_lock_addr(x) @@ -1805,22 +1805,6 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) } } -/** - * 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) -{ - - if (state != LM_ST_UNLOCKED) - return; - /* FIXME: remove this? */ -} - /** * demote_ok - Check to see if it's ok to unlock a glock * @gl: the glock @@ -2000,10 +1984,8 @@ void gfs2_scand_internal(struct gfs2_sbd *sdp) { unsigned int x; - for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) examine_bucket(scan_glock, sdp, x); - cond_resched(); - } } /** diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 52b8a308635..2b2a889ee2c 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -142,8 +142,6 @@ void gfs2_lvb_unhold(struct gfs2_glock *gl); void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); -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); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 0c50a720d01..d3aef74ea5d 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -529,7 +529,6 @@ const struct gfs2_glock_operations gfs2_trans_glops = { const 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, }; -- GitLab From 24264434603cc102d71fb2a1b3b7e282a781f449 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 11 Sep 2006 21:40:30 -0400 Subject: [PATCH 0259/1619] [GFS2] Rewrite of examine_bucket() The existing implementation of this function in glock.c was not very efficient as it relied upon keeping a cursor element upon the hash chain in question and moving it along. This new version improves upon this by using the current element as a cursor. This is possible since we only look at the "next" element in the list after we've taken the read_lock() subsequent to calling the examiner function. Obviously we have to eventually drop the ref count that we are then left with and we cannot do that while holding the read_lock, so we do that next time we drop the lock. That means either just before we examine another glock, or when the loop has terminated. The new implementation has several advantages: it uses only a read_lock() rather than a write_lock(), so it can run simnultaneously with other code, it doesn't need a "plug" element, so that it removes a test not only from this list iterator, but from all the other glock list iterators too. So it makes things faster and smaller. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 95 ++++++++++++++++-------------------------------- fs/gfs2/incore.h | 1 - 2 files changed, 31 insertions(+), 65 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index b348053c436..b5effb9e4a3 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -33,12 +34,6 @@ #include "super.h" #include "util.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; @@ -52,6 +47,7 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl); static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct gfs2_glock *gl); +static int dump_inode(struct gfs2_inode *ip); #define GFS2_GL_HASH_SHIFT 13 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) @@ -214,7 +210,7 @@ int gfs2_glock_put(struct gfs2_glock *gl) write_lock(gl_lock_addr(gl->gl_hash)); if (kref_put(&gl->gl_ref, kill_glock)) { - list_del_init(&gl_hash_table[gl->gl_hash].hb_list); + list_del_init(&gl->gl_list); write_unlock(gl_lock_addr(gl->gl_hash)); BUG_ON(spin_is_locked(&gl->gl_spin)); glock_free(gl); @@ -265,8 +261,6 @@ static struct gfs2_glock *search_bucket(unsigned int hash, struct gfs2_glock *gl; list_for_each_entry(gl, &gl_hash_table[hash].hb_list, gl_list) { - if (test_bit(GLF_PLUG, &gl->gl_flags)) - continue; if (!lm_name_equal(&gl->gl_name, name)) continue; if (gl->gl_sbd != sdp) @@ -1899,51 +1893,33 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, unsigned int hash) { - 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(gl_lock_addr(hash)); - list_add(&plug.gl_list, &gl_hash_table[hash].hb_list); - write_unlock(gl_lock_addr(hash)); - - for (;;) { - write_lock(gl_lock_addr(hash)); - - for (;;) { - tmp = plug.gl_list.next; + struct gfs2_glock *gl, *prev = NULL; + int has_entries = 0; + struct list_head *head = &gl_hash_table[hash].hb_list; - if (tmp == &gl_hash_table[hash].hb_list) { - list_del(&plug.gl_list); - entries = !list_empty(&gl_hash_table[hash].hb_list); - write_unlock(gl_lock_addr(hash)); - 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; - if (gl->gl_sbd != sdp) - continue; - - /* examiner() must glock_put() */ + read_lock(gl_lock_addr(hash)); + /* Can't use list_for_each_entry - don't want prefetch here */ + if (list_empty(head)) + goto out; + has_entries = 1; + gl = list_entry(head->next, struct gfs2_glock, gl_list); + while(&gl->gl_list != head) { + if (gl->gl_sbd == sdp) { gfs2_glock_hold(gl); - - break; + read_unlock(gl_lock_addr(hash)); + if (prev) + gfs2_glock_put(prev); + prev = gl; + examiner(gl); + read_lock(gl_lock_addr(hash)); } - - write_unlock(gl_lock_addr(hash)); - - examiner(gl); + gl = list_entry(gl->gl_list.next, struct gfs2_glock, gl_list); } +out: + read_unlock(gl_lock_addr(hash)); + if (prev) + gfs2_glock_put(prev); + return has_entries; } /** @@ -1955,23 +1931,19 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, static void scan_glock(struct gfs2_glock *gl) { if (gl->gl_ops == &gfs2_inode_glops) - goto out; + return; if (gfs2_glmutex_trylock(gl)) { if (queue_empty(gl, &gl->gl_holders) && - gl->gl_state != LM_ST_UNLOCKED && - demote_ok(gl)) + gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) goto out_schedule; gfs2_glmutex_unlock(gl); } -out: - gfs2_glock_put(gl); return; out_schedule: gfs2_glmutex_unlock(gl); gfs2_glock_schedule_for_reclaim(gl); - gfs2_glock_put(gl); } /** @@ -2014,11 +1986,8 @@ static void clear_glock(struct gfs2_glock *gl) 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); } /** @@ -2040,10 +2009,10 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) for (;;) { cont = 0; - - for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - if (examine_bucket(clear_glock, sdp, x)) + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { + if (examine_bucket(clear_glock, sdp, x)) cont = 1; + } if (!wait || !cont) break; @@ -2234,8 +2203,6 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) read_lock(gl_lock_addr(x)); list_for_each_entry(gl, &gl_hash_table[x].hb_list, gl_list) { - if (test_bit(GLF_PLUG, &gl->gl_flags)) - continue; if (gl->gl_sbd != sdp) continue; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 64e13435ca3..1fed8d1abae 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -152,7 +152,6 @@ struct gfs2_holder { }; enum { - GLF_PLUG = 0, GLF_LOCK = 1, GLF_STICKY = 2, GLF_PREFETCH = 3, -- GitLab From b6397893a5ed81970e803d61ee2f1a0e79f87438 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 12 Sep 2006 10:10:01 -0400 Subject: [PATCH 0260/1619] [GFS2] Use hlist for glock hash chains This results in smaller list heads, so that we can have more chains in the same amount of memory (twice as many). I've multiplied the size of the table by four though - this is because we are saving memory by not having one lock per chain any more. So we land up using about the same amount of memory for the hash table as we did before I started these changes, the difference being that we now have four times as many hash chains. The reason that I say "about the same amount of memory" is that the actual amount now depends upon the NR_CPUS and some of the config variables, so that its not exact and in some cases we do use more memory. Eventually we might want to scale the hash table size according to the size of physical ram as measured on module load. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 28 ++++++++++++++++------------ fs/gfs2/incore.h | 2 +- fs/gfs2/main.c | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index b5effb9e4a3..cf54b0b001f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -40,7 +40,7 @@ struct greedy { }; struct gfs2_gl_hash_bucket { - struct list_head hb_list; + struct hlist_head hb_list; }; typedef void (*glock_examiner) (struct gfs2_glock * gl); @@ -49,7 +49,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct gfs2_glock *gl); static int dump_inode(struct gfs2_inode *ip); -#define GFS2_GL_HASH_SHIFT 13 +#define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) #define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1) @@ -210,7 +210,7 @@ int gfs2_glock_put(struct gfs2_glock *gl) write_lock(gl_lock_addr(gl->gl_hash)); if (kref_put(&gl->gl_ref, kill_glock)) { - list_del_init(&gl->gl_list); + hlist_del(&gl->gl_list); write_unlock(gl_lock_addr(gl->gl_hash)); BUG_ON(spin_is_locked(&gl->gl_spin)); glock_free(gl); @@ -259,8 +259,9 @@ static struct gfs2_glock *search_bucket(unsigned int hash, const struct lm_lockname *name) { struct gfs2_glock *gl; + struct hlist_node *h; - list_for_each_entry(gl, &gl_hash_table[hash].hb_list, gl_list) { + hlist_for_each_entry(gl, h, &gl_hash_table[hash].hb_list, gl_list) { if (!lm_name_equal(&gl->gl_name, name)) continue; if (gl->gl_sbd != sdp) @@ -368,7 +369,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, glock_free(gl); gl = tmp; } else { - list_add_tail(&gl->gl_list, &gl_hash_table[hash].hb_list); + hlist_add_head(&gl->gl_list, &gl_hash_table[hash].hb_list); write_unlock(gl_lock_addr(hash)); } @@ -1895,15 +1896,15 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, { struct gfs2_glock *gl, *prev = NULL; int has_entries = 0; - struct list_head *head = &gl_hash_table[hash].hb_list; + struct hlist_head *head = &gl_hash_table[hash].hb_list; read_lock(gl_lock_addr(hash)); - /* Can't use list_for_each_entry - don't want prefetch here */ - if (list_empty(head)) + /* Can't use hlist_for_each_entry - don't want prefetch here */ + if (hlist_empty(head)) goto out; has_entries = 1; - gl = list_entry(head->next, struct gfs2_glock, gl_list); - while(&gl->gl_list != head) { + gl = list_entry(head->first, struct gfs2_glock, gl_list); + while(1) { if (gl->gl_sbd == sdp) { gfs2_glock_hold(gl); read_unlock(gl_lock_addr(hash)); @@ -1913,6 +1914,8 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, examiner(gl); read_lock(gl_lock_addr(hash)); } + if (gl->gl_list.next == NULL) + break; gl = list_entry(gl->gl_list.next, struct gfs2_glock, gl_list); } out: @@ -2195,6 +2198,7 @@ out: static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) { struct gfs2_glock *gl; + struct hlist_node *h; unsigned int x; int error = 0; @@ -2202,7 +2206,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) read_lock(gl_lock_addr(x)); - list_for_each_entry(gl, &gl_hash_table[x].hb_list, gl_list) { + hlist_for_each_entry(gl, h, &gl_hash_table[x].hb_list, gl_list) { if (gl->gl_sbd != sdp) continue; @@ -2225,7 +2229,7 @@ int __init gfs2_glock_init(void) { unsigned i; for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { - INIT_LIST_HEAD(&gl_hash_table[i].hb_list); + INIT_HLIST_HEAD(&gl_hash_table[i].hb_list); } #ifdef GL_HASH_LOCK_SZ for(i = 0; i < GL_HASH_LOCK_SZ; i++) { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 1fed8d1abae..c68d39271ed 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -161,7 +161,7 @@ enum { }; struct gfs2_glock { - struct list_head gl_list; + struct hlist_node gl_list; unsigned long gl_flags; /* GLF_... */ struct lm_lockname gl_name; struct kref gl_ref; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 2bdf246436c..d2867988cc3 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -42,7 +42,7 @@ static void gfs2_init_glock_once(void *foo, kmem_cache_t *cachep, unsigned long struct gfs2_glock *gl = foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { - INIT_LIST_HEAD(&gl->gl_list); + INIT_HLIST_NODE(&gl->gl_list); spin_lock_init(&gl->gl_spin); INIT_LIST_HEAD(&gl->gl_holders); INIT_LIST_HEAD(&gl->gl_waiters1); -- GitLab From 16feb9fec0e1f74339bd6992130ceedb3aa9567e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 13 Sep 2006 10:43:37 -0400 Subject: [PATCH 0261/1619] [GFS2] Use atomic_t rather than kref in glock.c Use atomic_t as the ref count in glocks rather than a kref. This is another step towards using RCU for the glock hash. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 34 ++++++++++++---------------------- fs/gfs2/incore.h | 2 +- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index cf54b0b001f..2316490723c 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -179,23 +178,7 @@ static void glock_free(struct gfs2_glock *gl) 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)); + atomic_inc(&gl->gl_ref); } /** @@ -207,12 +190,19 @@ static void kill_glock(struct kref *kref) int gfs2_glock_put(struct gfs2_glock *gl) { int rv = 0; + struct gfs2_sbd *sdp = gl->gl_sbd; write_lock(gl_lock_addr(gl->gl_hash)); - if (kref_put(&gl->gl_ref, kill_glock)) { + if (atomic_dec_and_test(&gl->gl_ref)) { hlist_del(&gl->gl_list); write_unlock(gl_lock_addr(gl->gl_hash)); BUG_ON(spin_is_locked(&gl->gl_spin)); + 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)); glock_free(gl); rv = 1; goto out; @@ -267,7 +257,7 @@ static struct gfs2_glock *search_bucket(unsigned int hash, if (gl->gl_sbd != sdp) continue; - kref_get(&gl->gl_ref); + atomic_inc(&gl->gl_ref); return gl; } @@ -333,7 +323,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_flags = 0; gl->gl_name = name; - kref_init(&gl->gl_ref); + atomic_set(&gl->gl_ref, 1); gl->gl_state = LM_ST_UNLOCKED; gl->gl_hash = hash; gl->gl_owner = NULL; @@ -2124,7 +2114,7 @@ static int dump_glock(struct gfs2_glock *gl) printk(" %u", x); } printk(" \n"); - printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref.refcount)); + printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref)); printk(KERN_INFO " gl_state = %u\n", gl->gl_state); printk(KERN_INFO " gl_owner = %s\n", gl->gl_owner->comm); print_symbol(KERN_INFO " gl_ip = %s\n", gl->gl_ip); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index c68d39271ed..89df68b32fc 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -164,7 +164,7 @@ struct gfs2_glock { struct hlist_node gl_list; unsigned long gl_flags; /* GLF_... */ struct lm_lockname gl_name; - struct kref gl_ref; + atomic_t gl_ref; spinlock_t gl_spin; -- GitLab From faa31ce85f626dff30ba865684bd1f0ad97a9ca0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 13 Sep 2006 11:13:27 -0400 Subject: [PATCH 0262/1619] [GFS2] Tidy up log.c Based upon previous feedback from lkml and also removing some commented out debugging which is no longer needed. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 8fce592f401..50f88059c3d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -47,8 +47,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, unsigned int first, second; blks = 1; - first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / - ssize; + first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize; if (nstruct > first) { second = (sdp->sd_sb.sb_bsize - @@ -230,8 +229,7 @@ static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) * Returns: the distance in blocks */ -static inline unsigned int log_distance(struct gfs2_sbd *sdp, - unsigned int newer, +static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer, unsigned int older) { int dist; @@ -250,11 +248,10 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) gfs2_log_lock(sdp); - if (list_empty(&sdp->sd_ail1_list)) + 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); + } else { + ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, ai_list); tail = ai->ai_first; } @@ -266,8 +263,7 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) 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); + 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; @@ -343,9 +339,7 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) gfs2_log_lock(sdp); sdp->sd_log_blks_free += dist - (pull ? 1 : 0); - /* printk(KERN_INFO "pull tail refunding %u blocks (%u left) pull=%d\n", dist - (pull ? 1 : 0), sdp->sd_log_blks_free, pull); */ - gfs2_assert_withdraw(sdp, - sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); + gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); sdp->sd_log_tail = new_tail; @@ -366,8 +360,6 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) unsigned int tail; u32 hash; - /* printk(KERN_INFO "log write header start (flags=%08x, pull=%d)\n", flags, pull); */ - bh = sb_getblk(sdp->sd_vfs, blkno); lock_buffer(bh); memset(bh->b_data, 0, bh->b_size); @@ -402,8 +394,6 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); log_incr_head(sdp); - - /* printk(KERN_INFO "log write header out\n"); */ } static void log_flush_commit(struct gfs2_sbd *sdp) @@ -459,8 +449,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) INIT_LIST_HEAD(&ai->ai_ail1_list); INIT_LIST_HEAD(&ai->ai_ail2_list); - gfs2_assert_withdraw(sdp, - sdp->sd_log_num_buf == sdp->sd_log_commited_buf); + 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); @@ -476,13 +465,12 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) lops_after_commit(sdp, ai); sdp->sd_log_head = sdp->sd_log_flush_head; - /* printk(KERN_INFO "sd_log_num_hdrs %u\n", sdp->sd_log_num_hdrs); */ sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs; - sdp->sd_log_blks_reserved = - sdp->sd_log_commited_buf = - sdp->sd_log_num_hdrs = - sdp->sd_log_commited_revoke = 0; + sdp->sd_log_blks_reserved = 0; + sdp->sd_log_commited_buf = 0; + sdp->sd_log_num_hdrs = 0; + sdp->sd_log_commited_revoke = 0; gfs2_log_lock(sdp); if (!list_empty(&ai->ai_ail1_list)) { @@ -551,8 +539,9 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) { gfs2_log_unlock(sdp); gfs2_log_flush(sdp, NULL); - } else + } else { gfs2_log_unlock(sdp); + } } /** @@ -580,7 +569,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0); - /* printk(KERN_INFO "sd_log_blks_free %u, sd_jdesc->jd_blocks %u\n", sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); */ gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); -- GitLab From a8336344a5fd1366eb3616d351c39cadcd077f43 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 14 Sep 2006 13:57:38 -0400 Subject: [PATCH 0263/1619] [GFS2] Fix glock hash clearing A one liner bug fix to prevent the return value being wrong when more than one superblock is mounted. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 2316490723c..64a1676e5f4 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1892,7 +1892,6 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, /* Can't use hlist_for_each_entry - don't want prefetch here */ if (hlist_empty(head)) goto out; - has_entries = 1; gl = list_entry(head->first, struct gfs2_glock, gl_list); while(1) { if (gl->gl_sbd == sdp) { @@ -1902,6 +1901,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, gfs2_glock_put(prev); prev = gl; examiner(gl); + has_entries = 1; read_lock(gl_lock_addr(hash)); } if (gl->gl_list.next == NULL) -- GitLab From 65952fb4e91c159d253bd28ceaf028a86dbb0b02 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 15 Sep 2006 13:09:11 -0500 Subject: [PATCH 0264/1619] [GFS2] print mount errors related to sysfs Print an error message if mount fails in setting up the sysfs files. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/sys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 88386d8dc05..c9b23084918 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -555,6 +555,7 @@ fail_lockstruct: fail_reg: kobject_unregister(&sdp->sd_kobj); fail: + fs_err(sdp, "error %d adding sysfs files", error); return error; } -- GitLab From 7a6bbacbb8dec6fbd1242c959250388f907d429e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 18 Sep 2006 17:18:23 -0400 Subject: [PATCH 0265/1619] [GFS2] Map multiple blocks at once where possible This is a tidy up of the GFS2 bmap code. The main change is that the bh is passed to gfs2_block_map allowing the flags to be set directly rather than having to repeat that code several times in ops_address.c. At the same time, the extent mapping code from gfs2_extent_map has been moved into gfs2_block_map. This allows all calls to gfs2_block_map to map extents in the case that no allocation is taking place. As a result reads and non-allocating writes should be faster. A quick test with postmark appears to support this. There is a limit on the number of blocks mapped in a single bmap call in that it will only ever map blocks which are pointed to from a single pointer block. So in other words, it will never try to do additional i/o in order to satisfy read-ahead. The maximum number of blocks is thus somewhat less than 512 (the GFS2 4k block size minus the header divided by sizeof(u64)). I've further limited the mapping of "normal" blocks to 32 blocks (to avoid extra work) since readpages() will currently read a maximum of 32 blocks ahead (128k). Some further work will probably be needed to set a suitable value for DIO as well, but for now thats left at the maximum 512 (see ops_address.c:gfs2_get_block_direct). There is probably a lot more that can be done to improve bmap for GFS2, but this is a good first step. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 131 +++++++++++++++++++++--------------------- fs/gfs2/bmap.h | 2 +- fs/gfs2/log.c | 14 ++--- fs/gfs2/ops_address.c | 68 +++++----------------- fs/gfs2/quota.c | 8 +-- fs/gfs2/recovery.c | 10 ++-- 6 files changed, 92 insertions(+), 141 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 57caad7bc0d..cc91e482eda 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -423,8 +423,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, * gfs2_block_pointers - Map a block from an inode to a disk block * @inode: The inode * @lblock: The logical block number - * @new: Value/Result argument (1 = may create/did create new blocks) - * @boundary: gets set if we've hit a block boundary + * @map_bh: The bh to be mapped * @mp: metapath to use * * Find the block number on the current device which corresponds to an @@ -433,37 +432,35 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, * Returns: errno */ -static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, - int *new, u64 *dblock, - int *boundary, - struct metapath *mp) +static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, + struct buffer_head *bh_map, struct metapath *mp, + unsigned int maxlen) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *bh; - int create = *new; unsigned int bsize; unsigned int height; unsigned int end_of_metadata; unsigned int x; int error = 0; - - *new = 0; - *dblock = 0; + int new = 0; + u64 dblock = 0; + int boundary; if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) - goto out; + return 0; 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) { if (!create) - goto out; + return 0; error = build_height(inode, height); if (error) - goto out; + return error; } find_metapath(ip, lblock, mp); @@ -471,32 +468,54 @@ static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, error = gfs2_meta_inode_buffer(ip, &bh); if (error) - goto out; + return error; for (x = 0; x < end_of_metadata; x++) { - lookup_block(ip, bh, x, mp, create, new, dblock); + lookup_block(ip, bh, x, mp, create, &new, &dblock); brelse(bh); - if (!*dblock) - goto out; + if (!dblock) + return 0; - error = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &bh); + error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); if (error) - goto out; + return error; } - *boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock); - if (*new) { - struct buffer_head *dibh; - 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); - brelse(dibh); + boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock); + clear_buffer_mapped(bh_map); + clear_buffer_new(bh_map); + clear_buffer_boundary(bh_map); + + if (dblock) { + map_bh(bh_map, inode->i_sb, dblock); + if (boundary) + set_buffer_boundary(bh); + if (new) { + struct buffer_head *dibh; + 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); + brelse(dibh); + } + set_buffer_new(bh_map); + goto out_brelse; + } + while(--maxlen && !buffer_boundary(bh_map)) { + u64 eblock; + + mp->mp_list[end_of_metadata]++; + boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock); + if (eblock != ++dblock) + break; + bh_map->b_size += inode->i_blksize; + if (boundary) + set_buffer_boundary(bh_map); } } - return bh; -out: - return ERR_PTR(error); +out_brelse: + brelse(bh); + return 0; } @@ -518,30 +537,23 @@ static inline void bmap_unlock(struct inode *inode, int create) up_read(&ip->i_rw_mutex); } -int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary) +int gfs2_block_map(struct inode *inode, u64 lblock, int create, + struct buffer_head *bh, unsigned int maxlen) { struct metapath mp; - struct buffer_head *bh; - int create = *new; + int ret; bmap_lock(inode, create); - bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp); + ret = gfs2_block_pointers(inode, lblock, create, bh, &mp, maxlen); bmap_unlock(inode, create); - if (!bh) - return 0; - if (IS_ERR(bh)) - return PTR_ERR(bh); - brelse(bh); - return 0; + return ret; } int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) { - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_sbd *sdp = GFS2_SB(inode); struct metapath mp; - struct buffer_head *bh; - int boundary; + struct buffer_head bh = { .b_state = 0, .b_blocknr = 0, .b_size = 0 }; + int ret; int create = *new; BUG_ON(!extlen); @@ -549,30 +561,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!new); bmap_lock(inode, create); - bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp); - *extlen = 1; - - if (bh != NULL && !IS_ERR(bh) && *dblock != 0 && *new == 0) { - u64 tmp_dblock; - int tmp_new; - unsigned int nptrs; - unsigned end_of_metadata = ip->i_di.di_height - 1; - - 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; - } - } + ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, *extlen); bmap_unlock(inode, create); - if (!bh) - return 0; - if (IS_ERR(bh)) - return PTR_ERR(bh); - brelse(bh); - return 0; + *extlen = bh.b_size >> inode->i_blkbits; + *dblock = bh.b_blocknr; + if (buffer_new(&bh)) + *new = 1; + else + *new = 0; + return ret; } /** diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 503f1cdda29..0fd379b4cd9 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -15,7 +15,7 @@ struct gfs2_inode; struct page; int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); -int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); +int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh, unsigned int maxlen); int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); int gfs2_truncatei(struct gfs2_inode *ip, u64 size); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 50f88059c3d..ab341cd0a76 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -204,17 +204,15 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) { - int new = 0; - u64 dbn; int error; - int bdy; + struct buffer_head bh_map; - 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, (unsigned long long)dbn, lbn); - gfs2_assert_withdraw(sdp, !error && dbn); + error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, 0, &bh_map, 1); + if (error || !bh_map.b_blocknr) + printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, bh_map.b_blocknr, lbn); + gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr); - return dbn; + return bh_map.b_blocknr; } /** diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index d44d42fb416..6f9ac5e6e3f 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -65,29 +65,11 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - int new = create; - u64 dblock; - int error; - int boundary; - - error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); - if (error) - return error; - - if (!dblock) - return 0; - - map_bh(bh_result, inode->i_sb, dblock); - if (new) - set_buffer_new(bh_result); - if (boundary) - set_buffer_boundary(bh_result); - - return 0; + return gfs2_block_map(inode, lblock, create, bh_result, 32); } /** - * get_block_noalloc - Fills in a buffer head with details about a block + * gfs2_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 @@ -96,47 +78,25 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, * Returns: errno */ -static int get_block_noalloc(struct inode *inode, sector_t lblock, - struct buffer_head *bh_result, int create) +static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) { - int new = 0; - u64 dblock; int error; - int boundary; - error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); + error = gfs2_block_map(inode, lblock, 0, bh_result, 1); if (error) return error; - - if (dblock) - map_bh(bh_result, inode->i_sb, dblock); - else if (gfs2_assert_withdraw(GFS2_SB(inode), !create)) - error = -EIO; - if (boundary) - set_buffer_boundary(bh_result); - - return error; + if (bh_result->b_blocknr == 0) + return -EIO; + return 0; } -static int get_block_direct(struct inode *inode, sector_t lblock, - struct buffer_head *bh_result, int create) +static int gfs2_get_block_direct(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) { - int new = 0; - u64 dblock; - int error, boundary; - - error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); - if (error) - return error; - - if (dblock) { - map_bh(bh_result, inode->i_sb, dblock); - if (boundary) - set_buffer_boundary(bh_result); - } - - return 0; + return gfs2_block_map(inode, lblock, 0, bh_result, 512); } + /** * gfs2_writepage - Write complete page * @page: Page to write @@ -184,7 +144,7 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) 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); + error = block_write_full_page(page, gfs2_get_block_noalloc, wbc); if (done_trans) gfs2_trans_end(sdp); gfs2_meta_cache_flush(ip); @@ -680,7 +640,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, rv = blockdev_direct_IO_own_locking(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, - get_block_direct, NULL); + gfs2_get_block_direct, NULL); out: gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index fe1828ffebf..bc9ad058d20 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -248,11 +248,9 @@ static int bh_get(struct gfs2_quota_data *qd) struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); unsigned int block, offset; - u64 dblock; - int new = 0; struct buffer_head *bh; int error; - int boundary; + struct buffer_head bh_map; mutex_lock(&sdp->sd_quota_mutex); @@ -264,10 +262,10 @@ 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_inode, block, &new, &dblock, &boundary); + error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map, 1); if (error) goto fail; - error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_START | DIO_WAIT, &bh); if (error) goto fail; error = -EIO; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index a27569c5d85..130e9fbf969 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -369,25 +369,23 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); unsigned int lblock; - int new = 0; - u64 dblock; struct gfs2_log_header *lh; u32 hash; struct buffer_head *bh; int error; - int boundary; + struct buffer_head bh_map; lblock = head->lh_blkno; gfs2_replay_incr_blk(sdp, &lblock); - error = gfs2_block_map(&ip->i_inode, lblock, &new, &dblock, &boundary); + error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map, 1); if (error) return error; - if (!dblock) { + if (!bh_map.b_blocknr) { gfs2_consist_inode(ip); return -EIO; } - bh = sb_getblk(sdp->sd_vfs, dblock); + bh = sb_getblk(sdp->sd_vfs, bh_map.b_blocknr); lock_buffer(bh); memset(bh->b_data, 0, bh->b_size); set_buffer_uptodate(bh); -- GitLab From dc41aeedef6b776583064be8abe6813159b4901d Mon Sep 17 00:00:00 2001 From: Russell Cattelan Date: Mon, 18 Sep 2006 17:26:48 -0400 Subject: [PATCH 0266/1619] [GFS2] Fix for mmap() bug in readpage Fix for Red Hat bz 205307. Don't need to lock in readpage if the higher level code has already grabbed the lock. Signed-off-by: Russell Cattelan Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 6f9ac5e6e3f..25d7025e43c 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -218,14 +218,16 @@ static int gfs2_readpage(struct file *file, struct page *page) { struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); + struct gfs2_file *gf = NULL; struct gfs2_holder gh; int error; int do_unlock = 0; if (likely(file != &gfs2_internal_file_sentinel)) { if (file) { - struct gfs2_file *gf = file->private_data; + gf = file->private_data; if (test_bit(GFF_EXLOCK, &gf->f_flags)) + /* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */ goto skip_lock; } gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); @@ -245,7 +247,8 @@ skip_lock: if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = -EIO; - if (file != &gfs2_internal_file_sentinel) { + if (gf && !test_bit(GFF_EXLOCK, &gf->f_flags) && + file != &gfs2_internal_file_sentinel) { gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); } -- GitLab From 07903c02d056452da369595f00eac078bf4c7ef0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 18 Sep 2006 17:30:05 -0400 Subject: [PATCH 0267/1619] [GFS2] Tweek unlock test in readpage() This make the unlock test a bit simpler. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 25d7025e43c..7cd53d118c8 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -247,8 +247,7 @@ skip_lock: if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = -EIO; - if (gf && !test_bit(GFF_EXLOCK, &gf->f_flags) && - file != &gfs2_internal_file_sentinel) { + if (do_unlock) { gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); } -- GitLab From f3b30912e0eab0e4160c7649a5f2b10be68027b9 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Mon, 18 Sep 2006 22:16:03 -0700 Subject: [PATCH 0268/1619] [GFS2] inode-diet-eliminate-i_blksize-and-use-a-per-superblock-default-vs-gfs2 i_blksize got removed in -mm. Cc: Steven Whitehouse Signed-off-by: Andrew Morton Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cc91e482eda..bd5bc887ef9 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -508,7 +508,7 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock); if (eblock != ++dblock) break; - bh_map->b_size += inode->i_blksize; + bh_map->b_size += (1 << inode->i_blkbits); if (boundary) set_buffer_boundary(bh_map); } -- GitLab From 7d308590ae60d1f038a54a94e78a385c5c163452 Mon Sep 17 00:00:00 2001 From: Fabio Massimo Di Nitto Date: Tue, 19 Sep 2006 07:56:29 +0200 Subject: [PATCH 0269/1619] [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/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 +++--- {fs/gfs2 => include/linux}/lm_interface.h | 0 35 files changed, 36 insertions(+), 38 deletions(-) rename {fs/gfs2 => include/linux}/lm_interface.h (100%) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index d846b5ad1d8..3123fc07123 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 bd5bc887ef9..19b9bfc1034 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 a2a07c41845..a9908cd78cd 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 f3dbda216ca..73902868827 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 adb898ceaa1..1a7877fe739 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 d7b92fba699..698942ec7c9 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 64a1676e5f4..f98694e7d66 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 d3aef74ea5d..9c046dbf472 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 0d010f0654d..b9e4bcb3bf1 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 4e23aa5ef75..2109fc4791d 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/locking.c b/fs/gfs2/locking.c index 65eca48b2ea..663fee72878 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 3a45c020d01..33af707a4d3 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 7b263fc6c27..acfbc941f31 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 ab341cd0a76..08b80b263ad 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 f8f6d4b56a0..e44d245d51d 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 d2867988cc3..7903be735fe 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 6af3521339f..a5630ec6c04 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 257c4a179dc..ef3092e2960 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 7cd53d118c8..91ec8080eeb 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 fa6ceffc7d8..00041b1b802 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 470e8829e7f..86127d93bd3 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 b551074a3c9..80f3ff0bba7 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 e8b7a1ae163..e32a6b242e0 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 2f38313b4bd..bb2ef6a8653 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 975e93b7992..f9538849c41 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 3b346314412..5453d2947ab 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 bc9ad058d20..c5eb6c64617 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 130e9fbf969..518f9128137 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 7a5ab817ad9..113b4ace689 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 f1d07d987c7..fe207a3e206 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 c9b23084918..0e0ec988f73 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 acf840160d5..f8dabf8446b 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 d72eb8addc7..196c604faad 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 2121cde187d..d8e720f9c21 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/fs/gfs2/lm_interface.h b/include/linux/lm_interface.h similarity index 100% rename from fs/gfs2/lm_interface.h rename to include/linux/lm_interface.h -- GitLab From 74669416f747363c14dba2ee6137540ae5a6834f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 19 Sep 2006 11:17:38 -0400 Subject: [PATCH 0270/1619] [GFS2] Use list_for_each_entry_safe_reverse in gfs2_ail1_start() This is an attempt to fix Red Hat bz 204364. I don't hit it all the time, but with these changes, running postmark which used to trigger it on a regular basis no longer appears to. So I'm not saying that its 100% certain that its fixed, but it does look promising at the moment. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 08b80b263ad..6112d648b7e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -62,8 +62,9 @@ void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) { struct list_head *head = &sdp->sd_ail1_list; u64 sync_gen; - struct list_head *first, *tmp; - struct gfs2_ail *first_ai, *ai; + struct list_head *first; + struct gfs2_ail *first_ai, *ai, *tmp; + int done = 0; gfs2_log_lock(sdp); if (list_empty(head)) { @@ -75,27 +76,25 @@ void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) 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); + gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */ if (flags & DIO_ALL) first = NULL; - for (;;) { + while(!done) { 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); + done = 1; + list_for_each_entry_safe_reverse(ai, tmp, head, ai_list) { if (ai->ai_sync_gen >= sync_gen) continue; ai->ai_sync_gen = sync_gen; - gfs2_ail1_start_one(sdp, ai); + gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */ + done = 0; break; } - - if (tmp == head) - break; } gfs2_log_unlock(sdp); -- GitLab From f0e522a901f209d55992a20f4e30123b43af37dd Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 19 Sep 2006 16:41:11 -0400 Subject: [PATCH 0271/1619] [GFS2] Remove "NFS only" readdir path This code path shouldn't be needed, so remove it for now. This tidys things up. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 187 +++------------------------------------------ 1 file changed, 9 insertions(+), 178 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 80f3ff0bba7..372dbcb3f7f 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -43,27 +43,6 @@ #include "util.h" #include "eaops.h" -/* "bad" is for NFS support */ -struct filldir_bad_entry { - char *fbe_name; - unsigned int fbe_length; - u64 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; @@ -149,7 +128,7 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) } /** - * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() + * filldir_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 @@ -160,9 +139,9 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) * Returns: 0 on success, 1 if buffer full */ -static int filldir_reg_func(void *opaque, const char *name, unsigned int length, - u64 offset, struct gfs2_inum *inum, - unsigned int type) +static int filldir_func(void *opaque, const char *name, unsigned int length, + u64 offset, struct gfs2_inum *inum, + unsigned int type) { struct filldir_reg *fdr = (struct filldir_reg *)opaque; struct gfs2_sbd *sdp = fdr->fdr_sbd; @@ -174,11 +153,9 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, return 1; if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { - gfs2_glock_prefetch_num(sdp, - inum->no_addr, &gfs2_inode_glops, + 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, + gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops, LM_ST_SHARED, LM_FLAG_TRY); } @@ -186,7 +163,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, } /** - * readdir_reg - Read directory entries from a directory + * 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 @@ -194,7 +171,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, * Returns: errno */ -static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) +static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) { struct inode *dir = file->f_mapping->host; struct gfs2_inode *dip = GFS2_I(dir); @@ -215,7 +192,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) return error; } - error = gfs2_dir_read(dir, &offset, &fdr, filldir_reg_func); + error = gfs2_dir_read(dir, &offset, &fdr, filldir_func); gfs2_glock_dq_uninit(&d_gh); @@ -224,152 +201,6 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) 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, - u64 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 inode *dir = file->f_mapping->host; - 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; - struct gfs2_holder d_gh; - u64 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(dir, &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; - - if (strcmp(current->comm, "nfsd") != 0) - error = readdir_reg(file, dirent, filldir); - else - error = readdir_bad(file, dirent, filldir); - - return error; -} static const u32 iflags_to_gfs2[32] = { [iflag_Sync] = GFS2_DIF_SYNC, -- GitLab From 56965536b8056f57830219efbba4b85218d96d6c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 20 Sep 2006 15:48:09 -0400 Subject: [PATCH 0272/1619] [GFS2] Remove unused constants Three of the DIO constants were not being used, so remove them. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 3 --- fs/gfs2/meta_io.c | 6 +----- fs/gfs2/ops_address.c | 4 ++-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 89df68b32fc..7183dcf0356 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -12,9 +12,6 @@ #include -#define DIO_FORCE 0x00000001 -#define DIO_CLEAN 0x00000002 -#define DIO_DIRTY 0x00000004 #define DIO_START 0x00000008 #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index a5630ec6c04..6b52aacb073 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -120,8 +120,7 @@ void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) gfs2_io_error_bh(sdp, bh); gfs2_log_lock(sdp); } - list_move(&bd->bd_ail_st_list, - &ai->ai_ail2_list); + list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); continue; } @@ -411,9 +410,6 @@ 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); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 91ec8080eeb..3f9da7ce5dd 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -65,7 +65,7 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, create, bh_result, 32); + return gfs2_block_map(inode, lblock, create, bh_result, 4); } /** @@ -94,7 +94,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, static int gfs2_get_block_direct(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, 0, bh_result, 512); + return gfs2_block_map(inode, lblock, 0, bh_result, 32); } /** -- GitLab From 7276b3b0c77101f8b3f4e45e89a29cf9045e831a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 21 Sep 2006 17:05:23 -0400 Subject: [PATCH 0273/1619] [GFS2] Tidy up meta_io code Fix a bug in the directory reading code, where we might have dereferenced a NULL pointer in case of OOM. Updated the directory code to use the new & improved version of gfs2_meta_ra() which now returns the first block that was being read. Previously it was releasing it requiring following code to grab the block again at each point it was called. Also turned off readahead on directory lookups since we are reading a hash table, and therefore reading the entries in order is very unlikely. Readahead is still used for all other calls to the directory reading function (e.g. when growing the hash table). Removed the DIO_START constant. Everywhere this was used, it was used to unconditionally start i/o aside from a couple of places, so I've removed it and made the couple of exceptions to this rule into separate functions. Also hunted through the other DIO flags and removed them as arguments from functions which were always called with the same combination of arguments. Updated gfs2_meta_indirect_buffer to be a bit more efficient and hopefully also be a bit easier to read. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 4 +- fs/gfs2/dir.c | 56 +++++++------- fs/gfs2/eattr.c | 23 +++--- fs/gfs2/glops.c | 55 ++++++++------ fs/gfs2/incore.h | 1 - fs/gfs2/lops.c | 9 +-- fs/gfs2/meta_io.c | 173 +++++++++++++++++++----------------------- fs/gfs2/meta_io.h | 6 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/quota.c | 16 ++-- fs/gfs2/recovery.c | 3 +- fs/gfs2/rgrp.c | 5 +- 12 files changed, 163 insertions(+), 190 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 19b9bfc1034..3fb9a26b6f5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -448,6 +448,8 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, u64 dblock = 0; int boundary; + BUG_ON(maxlen == 0); + if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) return 0; @@ -561,7 +563,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!new); bmap_lock(inode, create); - ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, *extlen); + ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, 32); bmap_unlock(inode, create); *extlen = bh.b_size >> inode->i_blkbits; *dblock = bh.b_blocknr; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 73902868827..40e94ac0b93 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -106,7 +106,7 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head *bh; int error; - error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh); if (error) return error; if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { @@ -246,7 +246,7 @@ fail: } static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, - unsigned int offset, unsigned int size) + u64 offset, unsigned int size) { struct buffer_head *dibh; int error; @@ -271,8 +271,8 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, * * Returns: The amount of data actually copied or the error */ -static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, - u64 offset, unsigned int size) +static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, + unsigned int size, unsigned ra) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); u64 lblock, dblock; @@ -291,8 +291,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, return 0; if (gfs2_is_stuffed(ip)) - return gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset, - size); + return gfs2_dir_read_stuffed(ip, buf, offset, size); if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; @@ -313,34 +312,31 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, new = 0; error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); - if (error) + if (error || !dblock) goto fail; + BUG_ON(extlen < 1); + if (!ra) + extlen = 1; + bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); } - - if (extlen > 1) - gfs2_meta_ra(ip->i_gl, dblock, extlen); - - if (dblock) { - if (new) - error = gfs2_dir_get_new_buffer(ip, dblock, &bh); - else - error = gfs2_dir_get_existing_buffer(ip, dblock, &bh); + if (!bh) { + error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); if (error) goto fail; - dblock++; - extlen--; - } else - bh = NULL; - + } + error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD); + if (error) { + brelse(bh); + goto fail; + } + dblock++; + extlen--; memcpy(buf, bh->b_data + o, amount); brelse(bh); - if (error) - goto fail; - + bh = NULL; buf += amount; copied += amount; lblock++; - o = sizeof(struct gfs2_meta_header); } @@ -701,7 +697,7 @@ static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, { int error; - error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp); + error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); 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; @@ -727,7 +723,7 @@ static int get_leaf_nr(struct gfs2_inode *dip, u32 index, error = gfs2_dir_read_data(dip, (char *)&leaf_no, index * sizeof(u64), - sizeof(u64)); + sizeof(u64), 0); if (error != sizeof(u64)) return (error < 0) ? error : -EIO; @@ -1095,7 +1091,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { error = gfs2_dir_read_data(dip, (char *)buf, block * sdp->sd_hash_bsize, - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1375,7 +1371,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, ht_offset * sizeof(u64), - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1745,7 +1741,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, ht_offset * sizeof(u64), - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 698942ec7c9..bd5ca602f9f 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -115,7 +115,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) u64 *eablk, *end; int error; - error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &bh); if (error) return error; @@ -139,7 +139,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) break; bn = be64_to_cpu(*eablk); - error = gfs2_meta_read(ip->i_gl, bn, DIO_START | DIO_WAIT, &eabh); + error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh); if (error) break; error = ea_foreach_i(ip, eabh, ea_call, data); @@ -453,8 +453,8 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, return -ENOMEM; for (x = 0; x < nptrs; x++) { - error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), - DIO_START, bh + x); + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, + bh + x); if (error) { while (x--) brelse(bh[x]); @@ -464,7 +464,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, } for (x = 0; x < nptrs; x++) { - error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT); + error = gfs2_meta_wait(sdp, bh[x]); if (error) { for (; x < nptrs; x++) brelse(bh[x]); @@ -938,8 +938,8 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { u64 *end; - error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, - DIO_START | DIO_WAIT, &indbh); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, + &indbh); if (error) return error; @@ -1215,8 +1215,8 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, goto out; for (x = 0; x < nptrs; x++) { - error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), - DIO_START, bh + x); + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, + bh + x); if (error) { while (x--) brelse(bh[x]); @@ -1226,7 +1226,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, } for (x = 0; x < nptrs; x++) { - error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT); + error = gfs2_meta_wait(sdp, bh[x]); if (error) { for (; x < nptrs; x++) brelse(bh[x]); @@ -1310,8 +1310,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) 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); + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh); if (error) return error; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 9c046dbf472..ef1492e2d44 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -77,32 +77,24 @@ static void gfs2_page_inval(struct gfs2_glock *gl) } /** - * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock + * gfs2_page_wait - Wait for writeback of data * @gl: the glock - * @flags: DIO_START | DIO_WAIT * * Syncs data (not metadata) for a regular file. * No-op for all other types. */ -static void gfs2_page_sync(struct gfs2_glock *gl, int flags) +static void gfs2_page_wait(struct gfs2_glock *gl) { - struct gfs2_inode *ip; - struct inode *inode; - struct address_space *mapping; - int error = 0; + struct gfs2_inode *ip = gl->gl_object; + struct inode *inode = &ip->i_inode; + struct address_space *mapping = inode->i_mapping; + int error; - ip = gl->gl_object; - inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) + if (!S_ISREG(ip->i_di.di_mode)) return; - mapping = inode->i_mapping; - - if (flags & DIO_START) - filemap_fdatawrite(mapping); - if (!error && (flags & DIO_WAIT)) - error = filemap_fdatawait(mapping); + error = filemap_fdatawait(mapping); /* Put back any errors cleared by filemap_fdatawait() so they can be caught by someone who can pass them @@ -115,6 +107,18 @@ static void gfs2_page_sync(struct gfs2_glock *gl, int flags) } +static void gfs2_page_writeback(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip = gl->gl_object; + struct inode *inode = &ip->i_inode; + struct address_space *mapping = inode->i_mapping; + + if (!S_ISREG(ip->i_di.di_mode)) + return; + + filemap_fdatawrite(mapping); +} + /** * meta_go_sync - sync out the metadata for this glock * @gl: the glock @@ -132,7 +136,7 @@ static void meta_go_sync(struct gfs2_glock *gl, int flags) if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); + gfs2_meta_sync(gl); if (flags & DIO_RELEASE) gfs2_ail_empty_gl(gl); } @@ -185,8 +189,7 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl) 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); + error = gfs2_meta_read(gl, gl->gl_name.ln_number, 0, &bh); if (!error) brelse(bh); } @@ -221,16 +224,18 @@ static void inode_go_sync(struct gfs2_glock *gl, int flags) if (test_bit(GLF_DIRTY, &gl->gl_flags)) { if (meta && data) { - gfs2_page_sync(gl, flags | DIO_START); + gfs2_page_writeback(gl); gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); - gfs2_page_sync(gl, flags | DIO_WAIT); + gfs2_meta_sync(gl); + gfs2_page_wait(gl); clear_bit(GLF_DIRTY, &gl->gl_flags); } else if (meta) { gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); - } else if (data) - gfs2_page_sync(gl, flags | DIO_START | DIO_WAIT); + gfs2_meta_sync(gl); + } else if (data) { + gfs2_page_writeback(gl); + gfs2_page_wait(gl); + } if (flags & DIO_RELEASE) gfs2_ail_empty_gl(gl); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 7183dcf0356..118dc693d11 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -12,7 +12,6 @@ #include -#define DIO_START 0x00000008 #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 #define DIO_DATA 0x00000040 diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index e44d245d51d..2a98cbe3290 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -248,13 +248,13 @@ static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { - gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); return; } if (pass != 1) return; - gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); @@ -726,15 +726,14 @@ static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { - gfs2_meta_sync(ip->i_gl, - DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); return; } if (pass != 1) return; /* data sync? */ - gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl); 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/meta_io.c b/fs/gfs2/meta_io.c index 6b52aacb073..d3708af0a4d 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -273,19 +273,16 @@ void gfs2_meta_inval(struct gfs2_glock *gl) /** * 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) +void gfs2_meta_sync(struct gfs2_glock *gl) { struct address_space *mapping = gl->gl_aspace->i_mapping; - int error = 0; + int error; - if (flags & DIO_START) - filemap_fdatawrite(mapping); - if (!error && (flags & DIO_WAIT)) - error = filemap_fdatawait(mapping); + filemap_fdatawrite(mapping); + error = filemap_fdatawait(mapping); if (error) gfs2_io_error(gl->gl_sbd); @@ -377,7 +374,7 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) * gfs2_meta_read - Read a block from disk * @gl: The glock covering the block * @blkno: The block number - * @flags: flags to gfs2_dreread() + * @flags: flags * @bhp: the place where the buffer is returned (NULL on failure) * * Returns: errno @@ -386,45 +383,43 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) int gfs2_meta_read(struct gfs2_glock *gl, u64 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); + if (!buffer_uptodate(*bhp)) + ll_rw_block(READ, 1, bhp); + if (flags & DIO_WAIT) { + int error = gfs2_meta_wait(gl->gl_sbd, *bhp); + if (error) { + brelse(*bhp); + return error; + } + } - return error; + return 0; } /** - * gfs2_meta_reread - Reread a block from disk + * gfs2_meta_wait - Reread a block from disk * @sdp: the filesystem - * @bh: The block to read - * @flags: Flags that control the read + * @bh: The block to wait for * * Returns: errno */ -int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) +int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) { if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) return -EIO; - if ((flags & DIO_START) && !buffer_uptodate(bh)) - ll_rw_block(READ, 1, &bh); - - if (flags & DIO_WAIT) { - wait_on_buffer(bh); + wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - struct gfs2_trans *tr = current->journal_info; - if (tr && tr->tr_touched) - gfs2_io_error_bh(sdp, bh); - return -EIO; - } - if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - return -EIO; + if (!buffer_uptodate(bh)) { + struct gfs2_trans *tr = current->journal_info; + 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; } @@ -635,67 +630,57 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, int new, struct buffer_head **bhp) { - struct buffer_head *bh, **bh_slot = ip->i_cache + height; - int error; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct gfs2_glock *gl = ip->i_gl; + struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height; + int in_cache = 0; spin_lock(&ip->i_spin); - bh = *bh_slot; - if (bh) { - if (bh->b_blocknr == num) - get_bh(bh); - else - bh = NULL; + if (*bh_slot && (*bh_slot)->b_blocknr == num) { + bh = *bh_slot; + get_bh(bh); + in_cache = 1; } spin_unlock(&ip->i_spin); - if (bh) { - if (new) - meta_prep_new(bh); - else { - error = gfs2_meta_reread(GFS2_SB(&ip->i_inode), 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; - } + if (!bh) + bh = getbuf(gl->gl_sbd, gl->gl_aspace, num, CREATE); - spin_lock(&ip->i_spin); - if (*bh_slot != bh) { - brelse(*bh_slot); - *bh_slot = bh; - get_bh(bh); - } - spin_unlock(&ip->i_spin); - } + if (!bh) + return -ENOBUFS; if (new) { - if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), height)) { - brelse(bh); - return -EIO; - } + if (gfs2_assert_warn(sdp, height)) + goto err; + meta_prep_new(bh); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); + } else { + u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; + if (!buffer_uptodate(bh)) { + ll_rw_block(READ, 1, &bh); + if (gfs2_meta_wait(sdp, bh)) + goto err; + } + if (gfs2_metatype_check(sdp, bh, mtype)) + goto err; + } - } else if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, - (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) { - brelse(bh); - return -EIO; + if (!in_cache) { + spin_lock(&ip->i_spin); + if (*bh_slot) + brelse(*bh_slot); + *bh_slot = bh; + get_bh(bh); + spin_unlock(&ip->i_spin); } *bhp = bh; - return 0; +err: + brelse(bh); + return -EIO; } /** @@ -704,19 +689,21 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, * @dblock: the starting disk block * @extlen: the number of blocks in the extent * + * returns: the first buffer in the extent */ -void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) +struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) { struct gfs2_sbd *sdp = gl->gl_sbd; struct inode *aspace = gl->gl_aspace; struct buffer_head *first_bh, *bh; u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; - int error; - if (!extlen || !max_ra) - return; + BUG_ON(!extlen); + + if (max_ra < 1) + max_ra = 1; if (extlen > max_ra) extlen = max_ra; @@ -724,11 +711,8 @@ void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) 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; - } + if (!buffer_locked(first_bh)) + ll_rw_block(READ, 1, &first_bh); dblock++; extlen--; @@ -736,23 +720,18 @@ void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 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); - + if (!buffer_uptodate(bh) && !buffer_locked(bh)) + ll_rw_block(READA, 1, &bh); + brelse(bh); dblock++; extlen--; - - if (buffer_uptodate(first_bh)) - break; + if (!buffer_locked(first_bh) && buffer_uptodate(first_bh)) + goto out; } + wait_on_buffer(first_bh); out: - brelse(first_bh); + return first_bh; } /** diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 086a472df3f..3323e6d0ed8 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -46,12 +46,12 @@ 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); +void gfs2_meta_sync(struct gfs2_glock *gl); struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp); -int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags); +int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); @@ -71,7 +71,7 @@ static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp); } -void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); +struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); #endif /* __DIO_DOT_H__ */ diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 3f9da7ce5dd..8b18e974fa4 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -65,7 +65,7 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, create, bh_result, 4); + return gfs2_block_map(inode, lblock, create, bh_result, 32); } /** diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c5eb6c64617..da46e14388f 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -265,7 +265,7 @@ static int bh_get(struct gfs2_quota_data *qd) error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map, 1); if (error) goto fail; - error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh); if (error) goto fail; error = -EIO; @@ -1059,8 +1059,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) u32 extlen = 0; int error; - if (!ip->i_di.di_size || - ip->i_di.di_size > (64 << 20) || + 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; @@ -1091,19 +1090,16 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) 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; + bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); + if (!bh) + goto fail; 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; + 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; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 518f9128137..4d4ea7e66ed 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -47,8 +47,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, return -EIO; } - gfs2_meta_ra(gl, dblock, extlen); - error = gfs2_meta_read(gl, dblock, DIO_START | DIO_WAIT, bh); + *bh = gfs2_meta_ra(gl, dblock, extlen); return error; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 113b4ace689..5f8e225c549 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -575,15 +575,14 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) 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); + error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, 0, &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); + error = gfs2_meta_wait(sdp, bi->bi_bh); if (error) goto fail; if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB : -- GitLab From 0889a9441d98af7951c5377647413d79c84c9efa Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 23 Sep 2006 22:11:07 +0000 Subject: [PATCH 0274/1619] CIFS: Use SEEK_END instead of hardcoded value Signed-off-by: Josef 'Jeff' Sipek Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c3ef1c0d0e6..f5ba4113248 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -508,7 +508,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { /* origin == SEEK_END => we must revalidate the cached file length */ - if (origin == 2) { + if (origin == SEEK_END) { int retval = cifs_revalidate(file->f_dentry); if (retval < 0) return (loff_t)retval; -- GitLab From ef26a46f8c501f6888cc78bcc4a2dc1efea1e733 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 13:27:17 +1000 Subject: [PATCH 0275/1619] [POWERPC] iSeries: set FW_FEATURE_ISERIES earlier This will help in the combined kernel as some really early things depend on being able to check this. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/setup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 7f1953066ff..7cb6b5f7c59 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -655,9 +655,6 @@ static int __init iseries_probe(void) if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) return 0; - powerpc_firmware_features |= FW_FEATURE_ISERIES; - powerpc_firmware_features |= FW_FEATURE_LPAR; - hpte_init_iSeries(); return 1; @@ -687,6 +684,9 @@ void * __init iSeries_early_setup(void) { unsigned long phys_mem_size; + powerpc_firmware_features |= FW_FEATURE_ISERIES; + powerpc_firmware_features |= FW_FEATURE_LPAR; + iSeries_fixup_klimit(); /* -- GitLab From de0138da0f8cf406c096daec7494a5cbebce2e5c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 13:30:51 +1000 Subject: [PATCH 0276/1619] [POWERPC] The two vio HVC backends clash Make sure only one of them actually registers as a driver. Also, remove cast from get_property(). Signed-off-by: Stephen Rothwell --- drivers/char/hvc_iseries.c | 8 ++++++-- drivers/char/hvc_vio.c | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index 4747729459c..ea362011bd5 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -493,6 +494,9 @@ static int hvc_vio_init(void) atomic_t wait_flag; int rc; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -EIO; + /* +2 for fudge */ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), viomajorsubtype_chario, VIOCHAR_WINDOW + 2); @@ -567,7 +571,7 @@ static int hvc_find_vtys(void) for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; vty = of_find_node_by_name(vty, "vty")) { - uint32_t *vtermno; + const uint32_t *vtermno; /* We have statically defined space for only a certain number * of console adapters. @@ -576,7 +580,7 @@ static int hvc_find_vtys(void) (num_found >= VTTY_PORTS)) break; - vtermno = (uint32_t *)get_property(vty, "reg", NULL); + vtermno = get_property(vty, "reg", NULL); if (!vtermno) continue; diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index cc95941148f..f9c00844d2b 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "hvc_console.h" @@ -120,6 +121,9 @@ static int hvc_vio_init(void) { int rc; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return -EIO; + /* Register as a vio device to receive callbacks */ rc = vio_register_driver(&hvc_vio_driver); -- GitLab From eecba334bdef03ce4918c3193f9b81791a715fb9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 13:35:09 +1000 Subject: [PATCH 0277/1619] [POWERPC] modify PCI code for a merged kernel Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/pci_64.c | 58 ++++++++++++++-------------- arch/powerpc/platforms/iseries/pci.c | 4 -- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index c1b1e14775e..78d3c0fc8df 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef DEBUG #include @@ -209,7 +210,6 @@ void pcibios_free_controller(struct pci_controller *phb) kfree(phb); } -#ifndef CONFIG_PPC_ISERIES void __devinit pcibios_claim_one_bus(struct pci_bus *b) { struct pci_dev *dev; @@ -238,10 +238,12 @@ static void __init pcibios_claim_of_setup(void) { struct pci_bus *b; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return; + list_for_each_entry(b, &pci_root_buses, node) pcibios_claim_one_bus(b); } -#endif #ifdef CONFIG_PPC_MULTIPLATFORM static u32 get_int_prop(struct device_node *np, const char *name, u32 def) @@ -554,9 +556,8 @@ static int __init pcibios_init(void) */ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; -#ifdef CONFIG_PPC_ISERIES - iSeries_pcibios_init(); -#endif + if (firmware_has_feature(FW_FEATURE_ISERIES)) + iSeries_pcibios_init(); printk(KERN_DEBUG "PCI: Probing PCI hardware\n"); @@ -566,15 +567,15 @@ static int __init pcibios_init(void) pci_bus_add_devices(hose->bus); } -#ifndef CONFIG_PPC_ISERIES - if (pci_probe_only) - pcibios_claim_of_setup(); - else - /* FIXME: `else' will be removed when - pci_assign_unassigned_resources() is able to work - correctly with [partially] allocated PCI tree. */ - pci_assign_unassigned_resources(); -#endif /* !CONFIG_PPC_ISERIES */ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) { + if (pci_probe_only) + pcibios_claim_of_setup(); + else + /* FIXME: `else' will be removed when + pci_assign_unassigned_resources() is able to work + correctly with [partially] allocated PCI tree. */ + pci_assign_unassigned_resources(); + } /* Call machine dependent final fixup */ if (ppc_md.pcibios_fixup) @@ -586,8 +587,9 @@ static int __init pcibios_init(void) printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); #ifdef CONFIG_PPC_MULTIPLATFORM - /* map in PCI I/O space */ - phbs_remap_io(); + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + /* map in PCI I/O space */ + phbs_remap_io(); #endif printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); @@ -637,13 +639,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) */ int pci_domain_nr(struct pci_bus *bus) { -#ifdef CONFIG_PPC_ISERIES - return 0; -#else - struct pci_controller *hose = pci_bus_to_host(bus); + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + else { + struct pci_controller *hose = pci_bus_to_host(bus); - return hose->global_number; -#endif + return hose->global_number; + } } EXPORT_SYMBOL(pci_domain_nr); @@ -651,12 +653,12 @@ EXPORT_SYMBOL(pci_domain_nr); /* Decide whether to display the domain number in /proc */ int pci_proc_domain(struct pci_bus *bus) { -#ifdef CONFIG_PPC_ISERIES - return 0; -#else - struct pci_controller *hose = pci_bus_to_host(bus); - return hose->buid; -#endif + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + else { + struct pci_controller *hose = pci_bus_to_host(bus); + return hose->buid; + } } /* diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 3eb12065df2..e904b3609c6 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -262,10 +262,6 @@ void __init iSeries_pci_final_fixup(void) mf_display_src(0xC9000200); } -void pcibios_fixup_bus(struct pci_bus *PciBus) -{ -} - void pcibios_fixup_resources(struct pci_dev *pdev) { } -- GitLab From 5e203d686277d87f0a6c9521a3a099ca10ee808d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 13:36:31 +1000 Subject: [PATCH 0278/1619] [POWERPC] fix ioremap for a combined kernel Signed-off-by: Stephen Rothwell --- arch/powerpc/mm/pgtable_64.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index b1da0316549..ac64f4aaa50 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -63,32 +63,13 @@ #include #include #include +#include #include "mmu_decl.h" unsigned long ioremap_bot = IMALLOC_BASE; static unsigned long phbs_io_bot = PHBS_IO_BASE; -#ifdef CONFIG_PPC_ISERIES - -void __iomem *ioremap(unsigned long addr, unsigned long size) -{ - return (void __iomem *)addr; -} - -extern void __iomem *__ioremap(unsigned long addr, unsigned long size, - unsigned long flags) -{ - return (void __iomem *)addr; -} - -void iounmap(volatile void __iomem *addr) -{ - return; -} - -#else - /* * map_io_page currently only called by __ioremap * map_io_page adds an entry to the ioremap page table @@ -161,6 +142,9 @@ void __iomem * __ioremap(unsigned long addr, unsigned long size, unsigned long pa, ea; void __iomem *ret; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return (void __iomem *)addr; + /* * Choose an address to map it to. * Once the imalloc system is running, we use it. @@ -255,6 +239,9 @@ void iounmap(volatile void __iomem *token) { void *addr; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return; + if (!mem_init_done) return; @@ -315,8 +302,6 @@ int iounmap_explicit(volatile void __iomem *start, unsigned long size) return 0; } -#endif - EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -- GitLab From 907b9bceb41fa46beae93f79cc4a2247df502c0f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 25 Sep 2006 09:26:04 -0400 Subject: [PATCH 0279/1619] [GFS2/DLM] Fix trailing whitespace As per Andrew Morton's request, removed trailing whitespace. Cc: Andrew Morton Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 2 +- fs/gfs2/acl.c | 2 +- fs/gfs2/bmap.c | 4 ++-- fs/gfs2/daemon.c | 2 +- fs/gfs2/dir.c | 13 ++++++------- fs/gfs2/eaops.c | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/glock.c | 12 ++++++------ fs/gfs2/inode.c | 5 ++--- fs/gfs2/inode.h | 2 +- fs/gfs2/lm.c | 2 +- fs/gfs2/locking/dlm/thread.c | 4 ++-- fs/gfs2/lops.c | 2 +- fs/gfs2/main.c | 2 +- fs/gfs2/ops_address.c | 4 ++-- fs/gfs2/ops_file.c | 6 +++--- fs/gfs2/ops_fstype.c | 18 +++++++++--------- fs/gfs2/ops_inode.c | 2 +- fs/gfs2/ops_super.c | 2 +- fs/gfs2/quota.c | 6 +++--- fs/gfs2/recovery.c | 4 ++-- fs/gfs2/rgrp.c | 2 +- fs/gfs2/super.c | 5 ++--- 23 files changed, 51 insertions(+), 54 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index af2f2f01bd5..3f2befa4797 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -1757,7 +1757,7 @@ static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) skip the queue_cast(ECANCEL). It indicates that the request/convert completed (and queued a normal ast) just before the cancel; we don't want to clobber the sb_result for the normal ast with ECANCEL. */ - + static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb) { revert_lock(r, lkb); diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 3123fc07123..5f959b8ce40 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -181,7 +181,7 @@ int gfs2_check_acl(struct inode *inode, int mask) error = gfs2_check_acl_locked(inode, mask); gfs2_glock_dq_uninit(&i_gh); } - + return error; } diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 3fb9a26b6f5..92eef825167 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -130,7 +130,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) 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 */ @@ -246,7 +246,7 @@ static int build_height(struct inode *inode, unsigned height) blocks[n] = gfs2_meta_new(ip->i_gl, bn); gfs2_trans_add_bh(ip->i_gl, blocks[n], 1); } - + n = 0; bn = blocks[0]->b_blocknr; if (new_height > 1) { diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index a9908cd78cd..cab1f68d468 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -30,7 +30,7 @@ /* 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. */ /** diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 40e94ac0b93..459498cac93 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -81,7 +81,7 @@ #define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) -typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len, +typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len, u64 leaf_no, void *data); typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); @@ -119,7 +119,6 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, unsigned int offset, unsigned int size) - { struct buffer_head *dibh; int error; @@ -685,7 +684,7 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, const struct qstr *name) { struct gfs2_dirent *dent; - dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_find_space, name, NULL); if (!dent || IS_ERR(dent)) return dent; @@ -764,7 +763,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) @@ -779,14 +778,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); @@ -810,7 +809,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; diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 1a7877fe739..92c54e9b0dc 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -146,7 +146,7 @@ static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) if (error == -ENODATA) error = 0; } - return error; + return error; } return -EPERM; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index bd5ca602f9f..a65a4ccfd4d 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -1133,7 +1133,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); - } + } gfs2_trans_end(GFS2_SB(&ip->i_inode)); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f98694e7d66..78fe0fae23f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -371,7 +371,7 @@ fail_aspace: if (gl->gl_aspace) gfs2_aspace_put(gl->gl_aspace); fail: - kmem_cache_free(gfs2_glock_cachep, gl); + kmem_cache_free(gfs2_glock_cachep, gl); return error; } @@ -614,7 +614,7 @@ static int rq_greedy(struct gfs2_holder *gh) gfs2_holder_uninit(gh); kfree(container_of(gh, struct greedy, gr_gh)); - spin_lock(&gl->gl_spin); + spin_lock(&gl->gl_spin); return 0; } @@ -1184,11 +1184,11 @@ static void add_to_queue(struct gfs2_holder *gh) if (existing) { print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid); - printk(KERN_INFO "lock type : %d lock state : %d\n", + printk(KERN_INFO "lock type : %d lock state : %d\n", existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state); print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid); - printk(KERN_INFO "lock type : %d lock state : %d\n", + printk(KERN_INFO "lock type : %d lock state : %d\n", gl->gl_name.ln_type, gl->gl_state); BUG(); } @@ -1203,7 +1203,7 @@ static void add_to_queue(struct gfs2_holder *gh) 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); + list_add_tail(&gh->gh_list, &gl->gl_waiters3); } /** @@ -2003,7 +2003,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) for (;;) { cont = 0; for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { - if (examine_bucket(clear_glock, sdp, x)) + if (examine_bucket(clear_glock, sdp, x)) cont = 1; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index b9e4bcb3bf1..ac9535be304 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -386,7 +386,6 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) 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 *dip = GFS2_I(dir); @@ -491,7 +490,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino) 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) { @@ -769,7 +768,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_ri.ri_length + - 2 * RES_DINODE + + 2 * RES_DINODE + RES_STATFS + RES_QUOTA, 0); if (error) goto fail_ipreserv; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 32015d89f24..f5d86176057 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -34,7 +34,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip); 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, const 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); diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 2109fc4791d..effe4a337c1 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -106,7 +106,7 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) fs_err(sdp, "about to withdraw from the cluster\n"); BUG_ON(sdp->sd_args.ar_debug); - + fs_err(sdp, "waiting for outstanding I/O\n"); diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 554bf882a4c..9cf1f168eaf 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -54,7 +54,7 @@ static void process_complete(struct gdlm_lock *lp) if (lp->lksb.sb_status == -DLM_ECANCEL) { log_info("complete dlm cancel %x,%llx flags %lx", - lp->lockname.ln_type, + lp->lockname.ln_type, (unsigned long long)lp->lockname.ln_number, lp->flags); @@ -102,7 +102,7 @@ static void process_complete(struct gdlm_lock *lp) if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) { log_info("complete internal cancel %x,%llx", - lp->lockname.ln_type, + lp->lockname.ln_type, (unsigned long long)lp->lockname.ln_number); lp->req = lp->cur; acb.lc_ret |= LM_OUT_CANCELED; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 2a98cbe3290..881e337b6a7 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -420,7 +420,7 @@ static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_log_lock(sdp); sdp->sd_log_num_rg++; list_add(&le->le_list, &sdp->sd_log_le_rg); - gfs2_log_unlock(sdp); + gfs2_log_unlock(sdp); } static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 7903be735fe..21508a13bb7 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -77,7 +77,7 @@ static int __init init_gfs2_fs(void) error = -ENOMEM; gfs2_glock_cachep = kmem_cache_create("gfs2_glock", sizeof(struct gfs2_glock), - 0, 0, + 0, 0, gfs2_init_glock_once, NULL); if (!gfs2_glock_cachep) goto fail; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 8b18e974fa4..811f4ada2a0 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -296,7 +296,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh); do_unlock = 1; ret = gfs2_glock_nq_m_atime(1, &gh); - if (ret == GLR_TRYFAILED) + if (ret == GLR_TRYFAILED) goto out_noerror; if (unlikely(ret)) goto out_unlock; @@ -681,7 +681,7 @@ static unsigned limit = 0; gl = bd->bd_gl; - fs_warn(sdp, "gl = (%u, %llu)\n", + 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", diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 372dbcb3f7f..a9ac1358ce2 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -236,7 +236,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) 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)) error = -EFAULT; @@ -299,7 +299,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) goto out; if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY)) goto out; - if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) && + if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) && !capable(CAP_LINUX_IMMUTABLE)) goto out; if (!IS_IMMUTABLE(inode)) { @@ -541,7 +541,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) goto out; gfs2_glock_hold(gl); flock_lock_file_wait(file, - &(struct file_lock){.fl_type = F_UNLCK}); + &(struct file_lock){.fl_type = F_UNLCK}); gfs2_glock_dq_uninit(fl_gh); } else { error = gfs2_glock_get(GFS2_SB(&ip->i_inode), diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index e32a6b242e0..a9aa2edd756 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -146,7 +146,7 @@ static int init_names(struct gfs2_sbd *sdp, int silent) brelse(bh); return -ENOMEM; } - gfs2_sb_in(sb, bh->b_data); + gfs2_sb_in(sb, bh->b_data); brelse(bh); error = gfs2_check_sb(sdp, sb, silent); @@ -272,7 +272,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, LM_ST_SHARED, 0, &sb_gh); if (error) { @@ -358,7 +358,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) error = -EINVAL; if (!gfs2_jindex_size(sdp)) { fs_err(sdp, "no journals!\n"); - goto fail_jindex; + goto fail_jindex; } if (sdp->sd_args.ar_spectator) { @@ -789,7 +789,7 @@ out: return error; } -static int fill_super_meta(struct super_block *sb, struct super_block *new, +static int fill_super_meta(struct super_block *sb, struct super_block *new, void *data, int silent) { struct gfs2_sbd *sdp = sb->s_fs_info; @@ -821,7 +821,7 @@ static int set_bdev_super(struct super_block *s, void *data) s->s_dev = s->s_bdev->bd_dev; return 0; } - + static int test_bdev_super(struct super_block *s, void *data) { return s->s_bdev == data; @@ -835,10 +835,10 @@ static struct super_block* get_gfs2_sb(const char *dev_name) struct super_block *sb = NULL, *s; struct list_head *l; int error; - + error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); if (error) { - printk(KERN_WARNING "GFS2: path_lookup on %s returned error\n", + printk(KERN_WARNING "GFS2: path_lookup on %s returned error\n", dev_name); goto out; } @@ -900,9 +900,9 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, deactivate_super(new); goto error; } - + new->s_flags |= MS_ACTIVE; - + /* Grab a reference to the gfs2 mount point */ atomic_inc(&sdp->sd_gfs2mnt->mnt_count); return simple_set_mnt(mnt, new); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index bb2ef6a8653..57af0192b24 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -522,7 +522,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, case S_IFSOCK: break; default: - return -EOPNOTSUPP; + return -EOPNOTSUPP; }; gfs2_holder_init(dip->i_gl, 0, 0, ghs); diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index f9538849c41..8cfda645213 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -367,7 +367,7 @@ 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 diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index da46e14388f..c0a3c9a2a59 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -556,7 +556,7 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) qd_hold(qd); slot_hold(qd); } - + mutex_unlock(&sdp->sd_quota_mutex); } @@ -777,7 +777,7 @@ restart: gfs2_glock_dq_uninit(&i_gh); - + gfs2_quota_in(&q, buf); qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); @@ -1062,7 +1062,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) 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; + return -EIO; } sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block; sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 4d4ea7e66ed..0a8a4b87dcc 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -444,11 +444,11 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) switch (error) { case 0: break; - + case GLR_TRYFAILED: fs_info(sdp, "jid=%u: Busy\n", jd->jd_jid); error = 0; - + default: goto fail; }; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 5f8e225c549..b261385c006 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -896,7 +896,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); while (rgd) { - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY, &al->al_rgd_gh); switch (error) { case 0: diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index fe207a3e206..f6ce5e4eaf7 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -650,8 +650,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, 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)); + gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode)); spin_unlock(&sdp->sd_statfs_spin); brelse(l_bh); @@ -678,7 +677,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) spin_lock(&sdp->sd_statfs_spin); gfs2_statfs_change_in(m_sc, m_bh->b_data + - sizeof(struct gfs2_dinode)); + 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; -- GitLab From 8aee918a1cff2a3722ce76fc6fa5abe09aa98d1b Mon Sep 17 00:00:00 2001 From: James Smart Date: Thu, 31 Aug 2006 12:27:57 -0400 Subject: [PATCH 0280/1619] [SCSI] lpfc: don't free mempool if mailbox is busy Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4cdf3464267..a5723ad0a09 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -389,7 +389,8 @@ lpfc_config_port_post(struct lpfc_hba * phba) lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) { + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -406,7 +407,8 @@ lpfc_config_port_post(struct lpfc_hba * phba) readl(phba->HAregaddr); /* flush */ phba->hba_state = LPFC_HBA_ERROR; - mempool_free(pmb, phba->mbox_mem_pool); + if (rc != MBX_BUSY) + mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } /* MBOX buffer will be freed in mbox compl */ -- GitLab From 6460e75a104d10458817d2f5b2fbff775bf0b43a Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Wed, 20 Sep 2006 18:20:49 -0400 Subject: [PATCH 0281/1619] [SCSI] sg: fixes for large page_size This sg driver patch addresses the problem with larger page sizes reported by Brian King in this post: http://marc.theaimsgroup.com/?l=linux-scsi&m=115867718623631&w=2 Some other related matters are also addressed. Some of these prevent oopses when the SG_SCATTER_SZ or scatter_elem_sz are set to inappropriate values. The scatter_elem_sz has been tested up to 4 MB which should make the largest data transfer with one SCSI command, 32 MB less one block, achievable with a relatively small number of elements in the scatter gather list. ChangeLog: - add scatter_elem_sz boot time parameter and sysfs module parameter that is initialized to SG_SCATTER_SZ - the driver will then adjust scatter_elem_sz to be the max(given(scatter_elem_sz), PAGE_SIZE) It will also round it up, if necessary, to be a power of two - clean up sg.h header, correct bad urls and some statements that are no longer valid - make the def_reserved_size sysfs module attribute writable Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 53 ++++++++++++++++++++++++++++++---------- include/scsi/sg.h | 61 ++++++++++++++++------------------------------- 2 files changed, 61 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 34f9343ed0a..3f8b9318856 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20060818"; +static char *sg_version_date = "20060920"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -94,6 +94,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE; static int def_reserved_size = -1; /* picks up init parameter */ static int sg_allow_dio = SG_ALLOW_DIO_DEF; +static int scatter_elem_sz = SG_SCATTER_SZ; +static int scatter_elem_sz_prev = SG_SCATTER_SZ; + #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) @@ -1537,11 +1540,9 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) msleep(10); /* dirty detach so delay device destruction */ } -/* Set 'perm' (4th argument) to 0 to disable module_param's definition - * of sysfs parameters (which module_param doesn't yet support). - * Sysfs parameters defined explicitly below. - */ -module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO); +module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +module_param_named(def_reserved_size, def_reserved_size, int, + S_IRUGO | S_IWUSR); module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); MODULE_AUTHOR("Douglas Gilbert"); @@ -1550,6 +1551,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(SG_VERSION_STR); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); +MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element " + "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); @@ -1558,8 +1561,14 @@ init_sg(void) { int rc; + if (scatter_elem_sz < PAGE_SIZE) { + scatter_elem_sz = PAGE_SIZE; + scatter_elem_sz_prev = scatter_elem_sz; + } if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; + else + def_reserved_size = sg_big_buff; rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS, "sg"); @@ -1842,15 +1851,30 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) if (mx_sc_elems < 0) return mx_sc_elems; /* most likely -ENOMEM */ + num = scatter_elem_sz; + if (unlikely(num != scatter_elem_sz_prev)) { + if (num < PAGE_SIZE) { + scatter_elem_sz = PAGE_SIZE; + scatter_elem_sz_prev = PAGE_SIZE; + } else + scatter_elem_sz_prev = num; + } for (k = 0, sg = schp->buffer, rem_sz = blk_size; (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sg) { - num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; + num = (rem_sz > scatter_elem_sz_prev) ? + scatter_elem_sz_prev : rem_sz; p = sg_page_malloc(num, sfp->low_dma, &ret_sz); if (!p) return -ENOMEM; + if (num == scatter_elem_sz_prev) { + if (unlikely(ret_sz > scatter_elem_sz_prev)) { + scatter_elem_sz = ret_sz; + scatter_elem_sz_prev = ret_sz; + } + } sg->page = p; sg->length = ret_sz; @@ -2341,6 +2365,9 @@ sg_add_sfp(Sg_device * sdp, int dev) } write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); + if (unlikely(sg_big_buff != def_reserved_size)) + sg_big_buff = def_reserved_size; + sg_build_reserve(sfp, sg_big_buff); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); @@ -2437,16 +2464,16 @@ sg_res_in_use(Sg_fd * sfp) return srp ? 1 : 0; } -/* If retSzp==NULL want exact size or fail */ +/* The size fetched (value output via retSzp) set when non-NULL return */ static struct page * sg_page_malloc(int rqSz, int lowDma, int *retSzp) { struct page *resp = NULL; gfp_t page_mask; int order, a_size; - int resSz = rqSz; + int resSz; - if (rqSz <= 0) + if ((rqSz <= 0) || (NULL == retSzp)) return resp; if (lowDma) @@ -2456,8 +2483,9 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp) for (order = 0, a_size = PAGE_SIZE; a_size < rqSz; order++, a_size <<= 1) ; + resSz = a_size; /* rounded up if necessary */ resp = alloc_pages(page_mask, order); - while ((!resp) && order && retSzp) { + while ((!resp) && order) { --order; a_size >>= 1; /* divide by 2, until PAGE_SIZE */ resp = alloc_pages(page_mask, order); /* try half */ @@ -2466,8 +2494,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp) if (resp) { if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) memset(page_address(resp), 0, resSz); - if (retSzp) - *retSzp = resSz; + *retSzp = resSz; } return resp; } diff --git a/include/scsi/sg.h b/include/scsi/sg.h index 0a487fe26d4..519c49a0fc1 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h @@ -11,26 +11,10 @@ Original driver (sg.h): * Copyright (C) 1992 Lawrence Foard Version 2 and 3 extensions to driver: -* Copyright (C) 1998 - 2003 Douglas Gilbert - - Version: 3.5.29 (20030529) - This version is for 2.5 series kernels. - - Changes since 3.5.28 (20030308) - - fix bug introduced in version 3.1.24 (last segment of sgat list) - Changes since 3.5.27 (20020812) - - remove procfs entries: hosts, host_hdr + host_strs (now in sysfs) - - add sysfs sg driver params: def_reserved_size, allow_dio, version - - new boot option: "sg_allow_dio" and module parameter: "allow_dio" - - multiple internal changes due to scsi subsystem rework - Changes since 3.5.26 (20020708) - - re-add direct IO using Kai Makisara's work - - re-tab to 8, start using C99-isms - - simplify memory management - Changes since 3.5.25 (20020504) - - driverfs additions - - copy_to/from_user() fixes [William Stinson] - - disable kiobufs support +* Copyright (C) 1998 - 2006 Douglas Gilbert + + Version: 3.5.34 (20060920) + This version is for 2.6 series kernels. For a full changelog see http://www.torque.net/sg @@ -40,7 +24,7 @@ Map of SG verions to the Linux kernels in which they appear: 2.1.40 2.2.20 3.0.x optional version 3 sg driver for 2.2 series 3.1.17++ 2.4.0++ - 3.5.23++ 2.5.0++ + 3.5.30++ 2.6.0++ Major new features in SG 3.x driver (cf SG 2.x drivers) - SG_IO ioctl() combines function if write() and read() @@ -51,14 +35,15 @@ Major new features in SG 3.x driver (cf SG 2.x drivers) data into kernel buffers and then use the CPU to copy the data into the user space (vice versa for writes). That is called "indirect" IO due to the double handling of data. There are two methods offered to remove the - redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and - 2) using the mmap() system call to map the reserve buffer (this driver has - one reserve buffer per fd) into the user space. Both have their advantages. + redundant copy: 1) direct IO and 2) using the mmap() system call to map + the reserve buffer (this driver has one reserve buffer per fd) into the + user space. Both have their advantages. In terms of absolute speed mmap() is faster. If speed is not a concern, indirect IO should be fine. Read the documentation for more information. - ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be - needed. That pseudo file's content is defaulted to 0. ** + ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or + 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed. + That attribute is 0 by default. ** Historical note: this SCSI pass-through driver has been known as "sg" for a decade. In broader kernel discussions "sg" is used to refer to scatter @@ -72,20 +57,17 @@ Major new features in SG 3.x driver (cf SG 2.x drivers) http://www.torque.net/sg/p/sg_v3_ho.html This is a rendering from DocBook source [change the extension to "sgml" or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). + The SG_IO ioctl is now found in other parts kernel (e.g. the block layer). + For more information see http://www.torque.net/sg/sg_io.html The older, version 2 documents discuss the original sg interface in detail: http://www.torque.net/sg/p/scsi-generic.txt http://www.torque.net/sg/p/scsi-generic_long.txt - A version of this document (potentially out of date) may also be found in - the kernel source tree, probably at: - Documentation/scsi/scsi-generic.txt . + Also available: /Documentation/scsi/scsi-generic.txt Utility and test programs are available at the sg web site. They are - bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the - lk 2.4 series). - - There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at: - http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO + packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils + (for the lk 2.2 series). */ @@ -238,13 +220,12 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ #define SG_GET_ACCESS_COUNT 0x2289 -#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */ +#define SG_SCATTER_SZ (8 * 4096) /* Largest size (in bytes) a single scatter-gather list element can have. - The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on - i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported - by adapter then this value is the largest data block that can be - read/written by a single scsi command. The user can find the value of - PAGE_SIZE by calling getpagesize() defined in unistd.h . */ + The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'. + This value should be a power of 2 (and may be rounded up internally). + If scatter-gather is not supported by adapter then this value is the + largest data block that can be read/written by a single scsi command. */ #define SG_DEFAULT_RETRIES 0 -- GitLab From bc54ec6b0782979a440603beeed349b2eac39a59 Mon Sep 17 00:00:00 2001 From: Muli Ben-Yehuda Date: Mon, 25 Sep 2006 17:10:19 +0300 Subject: [PATCH 0282/1619] [SCSI] aic94xx: require firmware loader aic94xx relies on external firmware and thus requires FW_LOADER. Signed-off-by: Muli Ben-Yehuda Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig index 0ed391d8ee8..c83fe751d0b 100644 --- a/drivers/scsi/aic94xx/Kconfig +++ b/drivers/scsi/aic94xx/Kconfig @@ -28,6 +28,7 @@ config SCSI_AIC94XX tristate "Adaptec AIC94xx SAS/SATA support" depends on PCI select SCSI_SAS_LIBSAS + select FW_LOADER help This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X AIC94xx chip based host adapters. -- GitLab From 15d1f53fc7654d62af7e9b23049ae3b71f5b161c Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 25 Sep 2006 05:44:57 -0400 Subject: [PATCH 0283/1619] [SCSI] qla1280 command timeout Original patch from Ian Dall in bugzilla. Set command timeout as specified by the SCSI layer rather than hardcode it to 30 seconds. I have received a couple of reports of people hitting this one with various tape configurations and the patch looks obviously correct. - Jes From http://bugzilla.kernel.org/show_bug.cgi?id=6275 ian@beware.dropbear.id.au (Ian Dall): The command sent to the card was using a 30second timeout regardless of the timeout requested in the scsi command passed down from higher levels. Signed-off-by: Jes Sorensen Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 8953991462d..2747c8e02f8 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); /* Set ISP command timeout. */ - pkt->timeout = cpu_to_le16(30); + pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ); /* Set device target ID and LUN */ pkt->lun = SCSI_LUN_32(cmd); @@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); /* Set ISP command timeout. */ - pkt->timeout = cpu_to_le16(30); + pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ); /* Set device target ID and LUN */ pkt->lun = SCSI_LUN_32(cmd); -- GitLab From d7694f8c0bb61829b1bd4d5543a51c66f04a6c3e Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Fri, 15 Sep 2006 18:50:34 +0200 Subject: [PATCH 0284/1619] [SCSI] seagate: remove header and convert to struct scsi_cmnd Signed-off-by: Henrik Kretzschmar Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 4 ++-- drivers/scsi/seagate.c | 17 +++++++++-------- drivers/scsi/seagate.h | 19 ------------------- 3 files changed, 11 insertions(+), 29 deletions(-) delete mode 100644 drivers/scsi/seagate.h diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index c4dfcc91ddd..d76c8697913 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1260,8 +1260,8 @@ config SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by this driver. It is explained in section 3.9 of the SCSI-HOWTO, available from . If it - doesn't work out of the box, you may have to change some settings in - . + doesn't work out of the box, you may have to change some macros at + compiletime, which are described in . To compile this driver as a module, choose M here: the module will be called seagate. diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 2679ea8bff1..e8f146d361c 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -106,7 +106,6 @@ #include "scsi.h" #include #include -#include "seagate.h" #include @@ -322,6 +321,7 @@ 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 int seagate_st0x_bus_reset(struct scsi_cmnd *); #ifdef FAST static int fast = 1; @@ -585,8 +585,8 @@ static int linked_connected = 0; static unsigned char linked_target, linked_lun; #endif -static void (*done_fn) (Scsi_Cmnd *) = NULL; -static Scsi_Cmnd *SCint = NULL; +static void (*done_fn) (struct scsi_cmnd *) = NULL; +static struct scsi_cmnd *SCint = NULL; /* * These control whether or not disconnect / reconnect will be attempted, @@ -633,7 +633,7 @@ static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id, static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs) { int temp; - Scsi_Cmnd *SCtmp; + struct scsi_cmnd *SCtmp; DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno); @@ -675,10 +675,11 @@ static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs) static int recursion_depth = 0; -static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt, + void (*done) (struct scsi_cmnd *)) { int result, reconnect; - Scsi_Cmnd *SCtmp; + struct scsi_cmnd *SCtmp; DANY ("seagate: que_command"); done_fn = done; @@ -1609,7 +1610,7 @@ connect_loop: return retcode (st0x_aborted); } /* end of internal_command */ -static int seagate_st0x_abort (Scsi_Cmnd * SCpnt) +static int seagate_st0x_abort(struct scsi_cmnd * SCpnt) { st0x_aborted = DID_ABORT; return SUCCESS; @@ -1624,7 +1625,7 @@ static int seagate_st0x_abort (Scsi_Cmnd * SCpnt) * May be called with SCpnt = NULL */ -static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt) +static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt) { /* No timeouts - this command is going to fail because it was reset. */ DANY ("scsi%d: Reseting bus... ", hostno); diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h deleted file mode 100644 index fb5f380fa4b..00000000000 --- a/drivers/scsi/seagate.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * seagate.h Copyright (C) 1992 Drew Eckhardt - * low level scsi driver header for ST01/ST02 by - * Drew Eckhardt - * - * - */ - -#ifndef _SEAGATE_H -#define SEAGATE_H - -static int seagate_st0x_detect(struct scsi_host_template *); -static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - -static int seagate_st0x_abort(Scsi_Cmnd *); -static const char *seagate_st0x_info(struct Scsi_Host *); -static int seagate_st0x_bus_reset(Scsi_Cmnd *); - -#endif /* _SEAGATE_H */ -- GitLab From 35a39691e4daa3c371c265e4cb8356c67ded45ec Mon Sep 17 00:00:00 2001 From: Brian King Date: Mon, 25 Sep 2006 12:39:20 -0500 Subject: [PATCH 0285/1619] [SCSI] ipr: Support attaching SATA devices Adds support to attach SATA devices to ipr SAS adapters. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 2 +- drivers/scsi/ipr.c | 683 +++++++++++++++++++++++++++++++++++++++++-- drivers/scsi/ipr.h | 18 +- 3 files changed, 681 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d76c8697913..8a22a71280a 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1014,7 +1014,7 @@ config SCSI_SYM53C8XX_MMIO config SCSI_IPR tristate "IBM Power Linux RAID adapter support" - depends on PCI && SCSI + depends on PCI && SCSI && ATA select FW_LOADER ---help--- This driver supports the IBM Power Linux family RAID adapters. diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 7ed4eef8347..e1e3a0cb88e 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ #include #include #include +#include #include "ipr.h" /* @@ -199,6 +201,8 @@ struct ipr_error_table_t ipr_error_table[] = { "FFFA: Undefined device response recovered by the IOA"}, {0x014A0000, 1, 1, "FFF6: Device bus error, message or command phase"}, + {0x014A8000, 0, 1, + "FFFE: Task Management Function failed"}, {0x015D0000, 0, 1, "FFF6: Failure prediction threshold exceeded"}, {0x015D9200, 0, 1, @@ -261,6 +265,8 @@ struct ipr_error_table_t ipr_error_table[] = { "Device bus status error"}, {0x04448600, 0, 1, "8157: IOA error requiring IOA reset to recover"}, + {0x04448700, 0, 0, + "ATA device status error"}, {0x04490000, 0, 0, "Message reject received from the device"}, {0x04449200, 0, 1, @@ -273,6 +279,8 @@ struct ipr_error_table_t ipr_error_table[] = { "9082: IOA detected device error"}, {0x044A0000, 1, 1, "3110: Device bus error, message or command phase"}, + {0x044A8000, 1, 1, + "3110: SAS Command / Task Management Function failed"}, {0x04670400, 0, 1, "9091: Incorrect hardware configuration change has been detected"}, {0x04678000, 0, 1, @@ -453,7 +461,8 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, trace_entry->time = jiffies; trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; trace_entry->type = type; - trace_entry->cmd_index = ipr_cmd->cmd_index; + trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command; + trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff; trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; trace_entry->u.add_data = add_data; } @@ -480,8 +489,10 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) ioarcb->read_ioadl_len = 0; ioasa->ioasc = 0; ioasa->residual_data_len = 0; + ioasa->u.gata.status = 0; ipr_cmd->scsi_cmd = NULL; + ipr_cmd->qc = NULL; ipr_cmd->sense_buffer[0] = 0; ipr_cmd->dma_use_sg = 0; } @@ -625,6 +636,28 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) return 0; } +/** + * ipr_sata_eh_done - done function for aborted SATA commands + * @ipr_cmd: ipr command struct + * + * This function is invoked for ops generated to SATA + * devices which are being aborted. + * + * Return value: + * none + **/ +static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ata_queued_cmd *qc = ipr_cmd->qc; + struct ipr_sata_port *sata_port = qc->ap->private_data; + + qc->err_mask |= AC_ERR_OTHER; + sata_port->ioasa.status |= ATA_BUSY; + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + ata_qc_complete(qc); +} + /** * ipr_scsi_eh_done - mid-layer done function for aborted ops * @ipr_cmd: ipr command struct @@ -669,6 +702,8 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) if (ipr_cmd->scsi_cmd) ipr_cmd->done = ipr_scsi_eh_done; + else if (ipr_cmd->qc) + ipr_cmd->done = ipr_sata_eh_done; ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); del_timer(&ipr_cmd->timer); @@ -825,6 +860,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res) res->del_from_ml = 0; res->resetting_device = 0; res->sdev = NULL; + res->sata_port = NULL; } /** @@ -1316,7 +1352,7 @@ static u32 ipr_get_error(u32 ioasc) int i; for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++) - if (ipr_error_table[i].ioasc == ioasc) + if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK)) return i; return 0; @@ -3051,6 +3087,17 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; **/ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth) { + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *)sdev->hostdata; + + if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN) + qdepth = IPR_MAX_CMD_PER_ATA_LUN; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); return sdev->queue_depth; } @@ -3165,6 +3212,122 @@ static int ipr_biosparam(struct scsi_device *sdev, return 0; } +/** + * ipr_find_starget - Find target based on bus/target. + * @starget: scsi target struct + * + * Return value: + * resource entry pointer if found / NULL if not found + **/ +static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; + struct ipr_resource_entry *res; + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if ((res->cfgte.res_addr.bus == starget->channel) && + (res->cfgte.res_addr.target == starget->id) && + (res->cfgte.res_addr.lun == 0)) { + return res; + } + } + + return NULL; +} + +static struct ata_port_info sata_port_info; + +/** + * ipr_target_alloc - Prepare for commands to a SCSI target + * @starget: scsi target struct + * + * If the device is a SATA device, this function allocates an + * ATA port with libata, else it does nothing. + * + * Return value: + * 0 on success / non-0 on failure + **/ +static int ipr_target_alloc(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; + struct ipr_sata_port *sata_port; + struct ata_port *ap; + struct ipr_resource_entry *res; + unsigned long lock_flags; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = ipr_find_starget(starget); + starget->hostdata = NULL; + + if (res && ipr_is_gata(res)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL); + if (!sata_port) + return -ENOMEM; + + ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost); + if (ap) { + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + sata_port->ioa_cfg = ioa_cfg; + sata_port->ap = ap; + sata_port->res = res; + + res->sata_port = sata_port; + ap->private_data = sata_port; + starget->hostdata = sata_port; + } else { + kfree(sata_port); + return -ENOMEM; + } + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + return 0; +} + +/** + * ipr_target_destroy - Destroy a SCSI target + * @starget: scsi target struct + * + * If the device was a SATA device, this function frees the libata + * ATA port, else it does nothing. + * + **/ +static void ipr_target_destroy(struct scsi_target *starget) +{ + struct ipr_sata_port *sata_port = starget->hostdata; + + if (sata_port) { + starget->hostdata = NULL; + ata_sas_port_destroy(sata_port->ap); + kfree(sata_port); + } +} + +/** + * ipr_find_sdev - Find device based on bus/target/lun. + * @sdev: scsi device struct + * + * Return value: + * resource entry pointer if found / NULL if not found + **/ +static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct ipr_resource_entry *res; + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if ((res->cfgte.res_addr.bus == sdev->channel) && + (res->cfgte.res_addr.target == sdev->id) && + (res->cfgte.res_addr.lun == sdev->lun)) + return res; + } + + return NULL; +} + /** * ipr_slave_destroy - Unconfigure a SCSI device * @sdev: scsi device struct @@ -3183,8 +3346,11 @@ static void ipr_slave_destroy(struct scsi_device *sdev) spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *) sdev->hostdata; if (res) { + if (res->sata_port) + ata_port_disable(res->sata_port->ap); sdev->hostdata = NULL; res->sdev = NULL; + res->sata_port = NULL; } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); } @@ -3219,12 +3385,44 @@ static int ipr_slave_configure(struct scsi_device *sdev) } if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) sdev->allow_restart = 1; - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + if (ipr_is_gata(res) && res->sata_port) { + scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN); + ata_sas_slave_configure(sdev, res->sata_port->ap); + } else { + scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + } } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return 0; } +/** + * ipr_ata_slave_alloc - Prepare for commands to a SATA device + * @sdev: scsi device struct + * + * This function initializes an ATA port so that future commands + * sent through queuecommand will work. + * + * Return value: + * 0 on success + **/ +static int ipr_ata_slave_alloc(struct scsi_device *sdev) +{ + struct ipr_sata_port *sata_port = NULL; + int rc = -ENXIO; + + ENTER; + if (sdev->sdev_target) + sata_port = sdev->sdev_target->hostdata; + if (sata_port) + rc = ata_sas_port_init(sata_port->ap); + if (rc) + ipr_slave_destroy(sdev); + + LEAVE; + return rc; +} + /** * ipr_slave_alloc - Prepare for commands to a device. * @sdev: scsi device struct @@ -3248,18 +3446,18 @@ static int ipr_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if ((res->cfgte.res_addr.bus == sdev->channel) && - (res->cfgte.res_addr.target == sdev->id) && - (res->cfgte.res_addr.lun == sdev->lun)) { - res->sdev = sdev; - res->add_to_ml = 0; - res->in_erp = 0; - sdev->hostdata = res; - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - rc = 0; - break; + res = ipr_find_sdev(sdev); + if (res) { + res->sdev = sdev; + res->add_to_ml = 0; + res->in_erp = 0; + sdev->hostdata = res; + if (!ipr_is_naca_model(res)) + res->needs_sync_complete = 1; + rc = 0; + if (ipr_is_gata(res)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return ipr_ata_slave_alloc(sdev); } } @@ -3314,7 +3512,8 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd) * This function issues a device reset to the affected device. * If the device is a SCSI device, a LUN reset will be sent * to the device first. If that does not work, a target reset - * will be sent. + * will be sent. If the device is a SATA device, a PHY reset will + * be sent. * * Return value: * 0 on success / non-zero on failure @@ -3325,25 +3524,78 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, struct ipr_cmnd *ipr_cmd; struct ipr_ioarcb *ioarcb; struct ipr_cmd_pkt *cmd_pkt; + struct ipr_ioarcb_ata_regs *regs; u32 ioasc; ENTER; ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ioarcb = &ipr_cmd->ioarcb; cmd_pkt = &ioarcb->cmd_pkt; + regs = &ioarcb->add_data.u.regs; ioarcb->res_handle = res->cfgte.res_handle; cmd_pkt->request_type = IPR_RQTYPE_IOACMD; cmd_pkt->cdb[0] = IPR_RESET_DEVICE; + if (ipr_is_gata(res)) { + cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET; + ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags)); + regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; + } ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET) + memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata, + sizeof(struct ipr_ioasa_gata)); LEAVE; return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0); } +/** + * ipr_sata_reset - Reset the SATA port + * @ap: SATA port to reset + * @classes: class of the attached device + * + * This function issues a SATA phy reset to the affected ATA port. + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes) +{ + struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + int rc = -ENXIO; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = sata_port->res; + if (res) { + rc = ipr_device_reset(ioa_cfg, res); + switch(res->cfgte.proto) { + case IPR_PROTO_SATA: + case IPR_PROTO_SAS_STP: + *classes = ATA_DEV_ATA; + break; + case IPR_PROTO_SATA_ATAPI: + case IPR_PROTO_SAS_STP_ATAPI: + *classes = ATA_DEV_ATAPI; + break; + default: + *classes = ATA_DEV_UNKNOWN; + break; + }; + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + LEAVE; + return rc; +} + /** * ipr_eh_dev_reset - Reset the device * @scsi_cmd: scsi command struct @@ -3360,7 +3612,8 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) struct ipr_cmnd *ipr_cmd; struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; - int rc; + struct ata_port *ap; + int rc = 0; ENTER; ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; @@ -3388,7 +3641,14 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) res->resetting_device = 1; scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); - rc = ipr_device_reset(ioa_cfg, res); + + if (ipr_is_gata(res) && res->sata_port) { + ap = res->sata_port->ap; + spin_unlock_irq(scsi_cmd->device->host->host_lock); + ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL); + spin_lock_irq(scsi_cmd->device->host->host_lock); + } else + rc = ipr_device_reset(ioa_cfg, res); res->resetting_device = 0; LEAVE; @@ -4300,6 +4560,9 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, return 0; } + if (ipr_is_gata(res) && res->sata_port) + return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap); + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ioarcb = &ipr_cmd->ioarcb; list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); @@ -4344,6 +4607,26 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, return 0; } +/** + * ipr_ioctl - IOCTL handler + * @sdev: scsi device struct + * @cmd: IOCTL cmd + * @arg: IOCTL arg + * + * Return value: + * 0 on success / other on failure + **/ +int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +{ + struct ipr_resource_entry *res; + + res = (struct ipr_resource_entry *)sdev->hostdata; + if (res && ipr_is_gata(res)) + return ata_scsi_ioctl(sdev, cmd, arg); + + return -EINVAL; +} + /** * ipr_info - Get information about the card/driver * @scsi_host: scsi host struct @@ -4366,10 +4649,45 @@ static const char * ipr_ioa_info(struct Scsi_Host *host) return buffer; } +/** + * ipr_scsi_timed_out - Handle scsi command timeout + * @scsi_cmd: scsi command struct + * + * Return value: + * EH_NOT_HANDLED + **/ +enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg; + struct ipr_cmnd *ipr_cmd; + unsigned long flags; + + ENTER; + spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); + ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; + + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) { + ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; + ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; + break; + } + } + + spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); + LEAVE; + return EH_NOT_HANDLED; +} + +static struct scsi_transport_template ipr_transport_template = { + .eh_timed_out = ipr_scsi_timed_out +}; + static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "IPR", .info = ipr_ioa_info, + .ioctl = ipr_ioctl, .queuecommand = ipr_queuecommand, .eh_abort_handler = ipr_eh_abort, .eh_device_reset_handler = ipr_eh_dev_reset, @@ -4377,6 +4695,8 @@ static struct scsi_host_template driver_template = { .slave_alloc = ipr_slave_alloc, .slave_configure = ipr_slave_configure, .slave_destroy = ipr_slave_destroy, + .target_alloc = ipr_target_alloc, + .target_destroy = ipr_target_destroy, .change_queue_depth = ipr_change_queue_depth, .change_queue_type = ipr_change_queue_type, .bios_param = ipr_biosparam, @@ -4391,6 +4711,330 @@ static struct scsi_host_template driver_template = { .proc_name = IPR_NAME }; +/** + * ipr_ata_phy_reset - libata phy_reset handler + * @ap: ata port to reset + * + **/ +static void ipr_ata_phy_reset(struct ata_port *ap) +{ + unsigned long flags; + struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_resource_entry *res = sata_port->res; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + int rc; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + } + + if (!ioa_cfg->allow_cmds) + goto out_unlock; + + rc = ipr_device_reset(ioa_cfg, res); + + if (rc) { + ap->ops->port_disable(ap); + goto out_unlock; + } + + switch(res->cfgte.proto) { + case IPR_PROTO_SATA: + case IPR_PROTO_SAS_STP: + ap->device[0].class = ATA_DEV_ATA; + break; + case IPR_PROTO_SATA_ATAPI: + case IPR_PROTO_SAS_STP_ATAPI: + ap->device[0].class = ATA_DEV_ATAPI; + break; + default: + ap->device[0].class = ATA_DEV_UNKNOWN; + ap->ops->port_disable(ap); + break; + }; + +out_unlock: + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + LEAVE; +} + +/** + * ipr_ata_post_internal - Cleanup after an internal command + * @qc: ATA queued command + * + * Return value: + * none + **/ +static void ipr_ata_post_internal(struct ata_queued_cmd *qc) +{ + struct ipr_sata_port *sata_port = qc->ap->private_data; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + struct ipr_cmnd *ipr_cmd; + unsigned long flags; + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->qc == qc) { + ipr_device_reset(ioa_cfg, sata_port->res); + break; + } + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); +} + +/** + * ipr_tf_read - Read the current ATA taskfile for the ATA port + * @ap: ATA port + * @tf: destination ATA taskfile + * + * Return value: + * none + **/ +static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_ioasa_gata *g = &sata_port->ioasa; + + tf->feature = g->error; + tf->nsect = g->nsect; + tf->lbal = g->lbal; + tf->lbam = g->lbam; + tf->lbah = g->lbah; + tf->device = g->device; + tf->command = g->status; + tf->hob_nsect = g->hob_nsect; + tf->hob_lbal = g->hob_lbal; + tf->hob_lbam = g->hob_lbam; + tf->hob_lbah = g->hob_lbah; + tf->ctl = g->alt_status; +} + +/** + * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure + * @regs: destination + * @tf: source ATA taskfile + * + * Return value: + * none + **/ +static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs, + struct ata_taskfile *tf) +{ + regs->feature = tf->feature; + regs->nsect = tf->nsect; + regs->lbal = tf->lbal; + regs->lbam = tf->lbam; + regs->lbah = tf->lbah; + regs->device = tf->device; + regs->command = tf->command; + regs->hob_feature = tf->hob_feature; + regs->hob_nsect = tf->hob_nsect; + regs->hob_lbal = tf->hob_lbal; + regs->hob_lbam = tf->hob_lbam; + regs->hob_lbah = tf->hob_lbah; + regs->ctl = tf->ctl; +} + +/** + * ipr_sata_done - done function for SATA commands + * @ipr_cmd: ipr command struct + * + * This function is invoked by the interrupt handler for + * ops generated by the SCSI mid-layer to SATA devices + * + * Return value: + * none + **/ +static void ipr_sata_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ata_queued_cmd *qc = ipr_cmd->qc; + struct ipr_sata_port *sata_port = qc->ap->private_data; + struct ipr_resource_entry *res = sata_port->res; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata, + sizeof(struct ipr_ioasa_gata)); + ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); + + if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET) + scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus, + res->cfgte.res_addr.target); + + if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) + qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status); + else + qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + ata_qc_complete(qc); +} + +/** + * ipr_build_ata_ioadl - Build an ATA scatter/gather list + * @ipr_cmd: ipr command struct + * @qc: ATA queued command + * + **/ +static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, + struct ata_queued_cmd *qc) +{ + u32 ioadl_flags = 0; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + int len = qc->nbytes + qc->pad_len; + struct scatterlist *sg; + + if (len == 0) + return; + + if (qc->dma_dir == DMA_TO_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_WRITE; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->write_data_transfer_length = cpu_to_be32(len); + ioarcb->write_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } else if (qc->dma_dir == DMA_FROM_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_READ; + ioarcb->read_data_transfer_length = cpu_to_be32(len); + ioarcb->read_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } + + ata_for_each_sg(sg, qc) { + ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); + ioadl->address = cpu_to_be32(sg_dma_address(sg)); + if (ata_sg_is_last(sg, qc)) + ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); + else + ioadl++; + } +} + +/** + * ipr_qc_issue - Issue a SATA qc to a device + * @qc: queued command + * + * Return value: + * 0 if success + **/ +static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_resource_entry *res = sata_port->res; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + struct ipr_cmnd *ipr_cmd; + struct ipr_ioarcb *ioarcb; + struct ipr_ioarcb_ata_regs *regs; + + if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead)) + return -EIO; + + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ioarcb = &ipr_cmd->ioarcb; + regs = &ioarcb->add_data.u.regs; + + memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data)); + ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs)); + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); + ipr_cmd->qc = qc; + ipr_cmd->done = ipr_sata_done; + ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; + ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem; + + ipr_build_ata_ioadl(ipr_cmd, qc); + regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; + ipr_copy_sata_tf(regs, &qc->tf); + memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN); + ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr)); + + switch (qc->tf.protocol) { + case ATA_PROT_NODATA: + case ATA_PROT_PIO: + break; + + case ATA_PROT_DMA: + regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; + break; + + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: + regs->flags |= IPR_ATA_FLAG_PACKET_CMD; + break; + + case ATA_PROT_ATAPI_DMA: + regs->flags |= IPR_ATA_FLAG_PACKET_CMD; + regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; + break; + + default: + WARN_ON(1); + return -1; + } + + mb(); + writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr), + ioa_cfg->regs.ioarrin_reg); + return 0; +} + +/** + * ipr_ata_check_status - Return last ATA status + * @ap: ATA port + * + * Return value: + * ATA status + **/ +static u8 ipr_ata_check_status(struct ata_port *ap) +{ + struct ipr_sata_port *sata_port = ap->private_data; + return sata_port->ioasa.status; +} + +/** + * ipr_ata_check_altstatus - Return last ATA altstatus + * @ap: ATA port + * + * Return value: + * Alt ATA status + **/ +static u8 ipr_ata_check_altstatus(struct ata_port *ap) +{ + struct ipr_sata_port *sata_port = ap->private_data; + return sata_port->ioasa.alt_status; +} + +static struct ata_port_operations ipr_sata_ops = { + .port_disable = ata_port_disable, + .check_status = ipr_ata_check_status, + .check_altstatus = ipr_ata_check_altstatus, + .dev_select = ata_noop_dev_select, + .phy_reset = ipr_ata_phy_reset, + .post_internal_cmd = ipr_ata_post_internal, + .tf_read = ipr_tf_read, + .qc_prep = ata_noop_qc_prep, + .qc_issue = ipr_qc_issue, + .port_start = ata_sas_port_start, + .port_stop = ata_sas_port_stop +}; + +static struct ata_port_info sata_port_info = { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, + .pio_mask = 0x10, /* pio4 */ + .mwdma_mask = 0x07, + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &ipr_sata_ops +}; + #ifdef CONFIG_PPC_PSERIES static const u16 ipr_blocked_processors[] = { PV_NORTHSTAR, @@ -6374,6 +7018,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); + host->transportt = &ipr_transport_template; + ata_host_init(&ioa_cfg->ata_host, &pdev->dev, + sata_port_info.flags, &ipr_sata_ops); ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 11eaff52432..6d035283af0 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -36,8 +37,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.1.4" -#define IPR_DRIVER_DATE "(August 2, 2006)" +#define IPR_DRIVER_VERSION "2.2.0" +#define IPR_DRIVER_DATE "(September 25, 2006)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -849,6 +850,13 @@ struct ipr_bus_attributes { u32 max_xfer_rate; }; +struct ipr_sata_port { + struct ipr_ioa_cfg *ioa_cfg; + struct ata_port *ap; + struct ipr_resource_entry *res; + struct ipr_ioasa_gata ioasa; +}; + struct ipr_resource_entry { struct ipr_config_table_entry cfgte; u8 needs_sync_complete:1; @@ -858,6 +866,7 @@ struct ipr_resource_entry { u8 resetting_device:1; struct scsi_device *sdev; + struct ipr_sata_port *sata_port; struct list_head queue; }; @@ -928,10 +937,11 @@ struct ipr_trace_entry { u32 time; u8 op_code; + u8 ata_op_code; u8 type; #define IPR_TRACE_START 0x00 #define IPR_TRACE_FINISH 0xff - u16 cmd_index; + u8 cmd_index; __be32 res_handle; union { @@ -1073,6 +1083,7 @@ struct ipr_ioa_cfg { struct ipr_cmnd *reset_cmd; + struct ata_host ata_host; char ipr_cmd_label[8]; #define IPR_CMD_LABEL "ipr_cmnd" struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS]; @@ -1085,6 +1096,7 @@ struct ipr_cmnd { struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES]; struct list_head queue; struct scsi_cmnd *scsi_cmd; + struct ata_queued_cmd *qc; struct completion completion; struct timer_list timer; void (*done) (struct ipr_cmnd *); -- GitLab From 76be12de87c4601cf35a88f83d199b940d995c62 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 25 Sep 2006 16:58:56 -0700 Subject: [PATCH 0286/1619] [SCSI] dc395x: fix printk format warning drivers/scsi/dc395x.c:1224: warning: format '%i' expects type 'int', but argument 5 has type 'size_t' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/dc395x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index ff2b1796fa3..9d7048176e7 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1219,7 +1219,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb, srb, srb->cmd, srb->cmd->pid, srb->cmd->cmnd[0], srb->cmd->device->id, srb->cmd->device->lun); - printk(" sglist=%p cnt=%i idx=%i len=%i\n", + printk(" sglist=%p cnt=%i idx=%i len=%Zd\n", srb->segment_x, srb->sg_count, srb->sg_index, srb->total_xfer_length); printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", -- GitLab From 16c8729a46b599bca647839556a33d0b59522e94 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Mon, 25 Sep 2006 16:59:04 -0700 Subject: [PATCH 0287/1619] [SCSI] drivers/scsi/nsp32.h: removal of old scsi code Signed-off-by: Michal Piotrowski Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/nsp32.h | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h index 5addf9fb1e1..a976e8193d1 100644 --- a/drivers/scsi/nsp32.h +++ b/drivers/scsi/nsp32.h @@ -619,47 +619,5 @@ typedef struct _nsp32_hw_data { #define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion or negation, 10000us == 10ms */ -/************************************************************************** - * Compatibility functions - */ - -/* for Kernel 2.4 */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) -# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template) -# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template) -# define scsi_host_put(host) scsi_unregister(host) -# define pci_name(pci_dev) ((pci_dev)->slot_name) - -typedef void irqreturn_t; -# define IRQ_NONE /* */ -# define IRQ_HANDLED /* */ -# define IRQ_RETVAL(x) /* */ - -/* This is ad-hoc version of scsi_host_get_next() */ -static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host) -{ - if (host == NULL) { - return scsi_hostlist; - } else { - return host->next; - } -} - -/* This is ad-hoc version of scsi_host_hn_get() */ -static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno) -{ - struct Scsi_Host *host; - - for (host = scsi_host_get_next(NULL); host != NULL; - host = scsi_host_get_next(host)) { - if (host->host_no == hostno) { - break; - } - } - - return host; -} -#endif - #endif /* _NSP32_H */ /* end */ -- GitLab From d41ba22a6d330ab1e8d3adde7d2ce9349d4e4dc7 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 25 Sep 2006 16:59:11 -0700 Subject: [PATCH 0288/1619] [SCSI] 3w-xxxx: fix "ATA UDMA upgrade" message number sparse "defined twice" warning Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/3w-xxxx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 31fe5ea1592..bbd654a2b9b 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -74,7 +74,7 @@ static char *tw_aen_string[] = { [0x00D] = "ERROR: Logical unit deleted: Unit #", [0x00F] = "WARNING: SMART threshold exceeded: Port #", [0x021] = "WARNING: ATA UDMA downgrade: Port #", - [0x021] = "WARNING: ATA UDMA upgrade: Port #", + [0x022] = "WARNING: ATA UDMA upgrade: Port #", [0x023] = "WARNING: Sector repair occurred: Port #", [0x024] = "ERROR: SBUF integrity check failure", [0x025] = "ERROR: Lost cached write: Port #", -- GitLab From f5ebbeb57e4b57ac44f29ff9ec2ebde1401999d1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 25 Sep 2006 16:59:01 -0700 Subject: [PATCH 0289/1619] [SCSI] megaraid: Use the proper type to hold the irq number. When testing on a Unisys machine it was discovered that the megaraid driver would not initialize as it was requesting irq 162 instead of irq 1442 it was assigned. The problem was the irq number had been truncated by being stored in an unsigned char. This patches fixes that problem and the driver now appears to work. The ioctl interface appears fundamentally broken as it exports the irq number to user space in an unsigned char. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/megaraid/mega_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index 8cd0bd1d0f7..b50e27e6602 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h @@ -175,7 +175,7 @@ typedef struct { uint8_t max_lun; uint32_t unique_id; - uint8_t irq; + int irq; uint8_t ito; caddr_t ibuf; dma_addr_t ibuf_dma_h; -- GitLab From 288777f89a63ca0bece7b5e082ce9beebacfb8fd Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Mon, 25 Sep 2006 16:59:02 -0700 Subject: [PATCH 0290/1619] [SCSI] drivers/scsi/dpt/dpti_i2o.h: removal of old scsi code Signed-off-by: Michal Piotrowski Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/dpt/dpti_i2o.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h index d84a281ad94..b3fa7ed71fa 100644 --- a/drivers/scsi/dpt/dpti_i2o.h +++ b/drivers/scsi/dpt/dpti_i2o.h @@ -47,21 +47,11 @@ * I2O Interface Objects */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - -#define DECLARE_MUTEX(name) struct semaphore name=MUTEX - -typedef struct wait_queue *adpt_wait_queue_head_t; -#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) adpt_wait_queue_head_t wait = NULL -typedef struct wait_queue adpt_wait_queue_t; -#else - #include typedef wait_queue_head_t adpt_wait_queue_head_t; #define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait) typedef wait_queue_t adpt_wait_queue_t; -#endif /* * message structures */ -- GitLab From c03d10ab6aafe6706520e1595d6e91d0e50ac5ad Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Mon, 25 Sep 2006 16:59:03 -0700 Subject: [PATCH 0291/1619] [SCSI] drivers/scsi/gdth.h: removal of old scsi code Signed-off-by: Michal Piotrowski Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/gdth.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 47eae029975..8c29eafd51c 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -936,18 +936,12 @@ typedef struct { gdth_binfo_str binfo; /* controller info */ gdth_evt_data dvr; /* event structure */ spinlock_t smp_lock; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) struct pci_dev *pdev; -#endif char oem_name[8]; #ifdef GDTH_DMA_STATISTICS ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) struct scsi_device *sdev; -#else - struct scsi_device sdev; -#endif } gdth_ha_str; /* structure for scsi_register(), SCSI bus != 0 */ @@ -1029,10 +1023,6 @@ typedef struct { /* function prototyping */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int); -#else -int gdth_proc_info(char *,char **,off_t,int,int,int); -#endif #endif -- GitLab From 20a2460b4dd07fe7dc74b281fcbe18bac03830aa Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Mon, 25 Sep 2006 16:59:06 -0700 Subject: [PATCH 0292/1619] [SCSI] drivers/message/fusion/linux_compat.h Removal of old code Signed-off-by: Michal Piotrowski Acked-by: "Moore, Eric Dean" Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/message/fusion/linux_compat.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h index 048b5b8610e..bb2bf5aa0b6 100644 --- a/drivers/message/fusion/linux_compat.h +++ b/drivers/message/fusion/linux_compat.h @@ -6,13 +6,4 @@ #include #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)) -static int inline scsi_device_online(struct scsi_device *sdev) -{ - return sdev->online; -} -#endif - - -/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ -- GitLab From 53aefd3fc31f08487f6941282ef6611413e02e43 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 25 Sep 2006 16:59:12 -0700 Subject: [PATCH 0293/1619] [SCSI] scsi: included header cleanup Free seagate.h from obsolete drivers/scsi.h, remove a double inclusion od linux/delay.h and remove the unneeded scsi/scsi_ioctl.h Signed-off-by: Henrik Kretzschmar Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/seagate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index e8f146d361c..4e6666ceae2 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -94,7 +94,6 @@ #include #include #include -#include #include #include #include @@ -103,11 +102,13 @@ #include #include -#include "scsi.h" +#include +#include +#include + #include #include -#include #ifdef DEBUG #define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0) -- GitLab From 45223fd77c2b39d05dd7f1aaabf614abb1770bbe Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 25 Sep 2006 16:59:08 -0700 Subject: [PATCH 0294/1619] [SCSI] Signdness issue in drivers/scsi/osst.c another signdness warning from gcc 4.1 drivers/scsi/osst.c:5154: warning: comparison of unsigned expression < 0 is always false The problem is that blk is defined as unsigned, but all usages of it are normal int cases. osst_get_frame_position() and osst_get_sector() return ints and can return negative values. If blk stays an unsigned int, the error check is useless. Signed-off-by: Eric Sesterhenn Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/osst.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 4a2fed350d4..9ecb323ebae 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -4843,8 +4843,7 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp) static int osst_ioctl(struct inode * inode,struct file * file, unsigned int cmd_in, unsigned long arg) { - int i, cmd_nr, cmd_type, retval = 0; - unsigned int blk; + int i, cmd_nr, cmd_type, blk, retval = 0; struct st_modedef * STm; struct st_partstat * STps; struct osst_request * SRpnt = NULL; -- GitLab From dcbccbde00b85b4d4a1c206b419e7a3d2ab2b1cd Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Mon, 25 Sep 2006 16:58:58 -0700 Subject: [PATCH 0295/1619] [SCSI] pci_module_init conversion in scsi subsystem Converts pci_module_init() to pci_register_driver() in the scsi subsys on 23 drivers which only return the value of pci_module_init(). Signed-off-by: Henrik Kretzschmar Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/3w-9xxx.c | 2 +- drivers/scsi/3w-xxxx.c | 2 +- drivers/scsi/a100u2w.c | 2 +- drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 2 +- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 3 +-- drivers/scsi/dc395x.c | 2 +- drivers/scsi/dmx3191d.c | 2 +- drivers/scsi/ipr.c | 2 +- drivers/scsi/nsp32.c | 2 +- drivers/scsi/qla1280.c | 2 +- 10 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 5a9475e56d0..da173159ced 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -2211,7 +2211,7 @@ static int __init twa_init(void) { printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); - return pci_module_init(&twa_driver); + return pci_register_driver(&twa_driver); } /* End twa_init() */ /* This function is called on driver exit */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index f3a5f422a8e..2d4cb6721fa 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2486,7 +2486,7 @@ static int __init tw_init(void) { printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); - return pci_module_init(&tw_driver); + return pci_register_driver(&tw_driver); } /* End tw_init() */ /* This function is called on driver exit */ diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index d7e9fab54c6..2684150917e 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1187,7 +1187,7 @@ static struct pci_driver inia100_pci_driver = { static int __init inia100_init(void) { - return pci_module_init(&inia100_pci_driver); + return pci_register_driver(&inia100_pci_driver); } static void __exit inia100_exit(void) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 50a41eda580..4b535420180 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -198,7 +198,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int ahd_linux_pci_init(void) { - return (pci_module_init(&aic79xx_pci_driver)); + return pci_register_driver(&aic79xx_pci_driver); } void diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 7e42f07a27f..d20ca514e9f 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -246,8 +246,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int ahc_linux_pci_init(void) { - /* Translate error or zero return into zero or one */ - return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1; + return pci_register_driver(&aic7xxx_pci_driver); } void diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 9d7048176e7..c6118d99385 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4949,7 +4949,7 @@ static struct pci_driver dc395x_driver = { **/ static int __init dc395x_module_init(void) { - return pci_module_init(&dc395x_driver); + return pci_register_driver(&dc395x_driver); } diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c index 879a2665767..fa738ec8692 100644 --- a/drivers/scsi/dmx3191d.c +++ b/drivers/scsi/dmx3191d.c @@ -155,7 +155,7 @@ static struct pci_driver dmx3191d_pci_driver = { static int __init dmx3191d_init(void) { - return pci_module_init(&dmx3191d_pci_driver); + return pci_register_driver(&dmx3191d_pci_driver); } static void __exit dmx3191d_exit(void) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e1e3a0cb88e..2e21e162056 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7396,7 +7396,7 @@ static int __init ipr_init(void) ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", IPR_DRIVER_VERSION, IPR_DRIVER_DATE); - return pci_module_init(&ipr_driver); + return pci_register_driver(&ipr_driver); } /** diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index bfb4f49e125..1c624ce8189 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -3581,7 +3581,7 @@ static struct pci_driver nsp32_driver = { */ static int __init init_nsp32(void) { nsp32_msg(KERN_INFO, "loading..."); - return pci_module_init(&nsp32_driver); + return pci_register_driver(&nsp32_driver); } static void __exit exit_nsp32(void) { diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 2747c8e02f8..bdecde1c515 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4484,7 +4484,7 @@ qla1280_init(void) qla1280_setup(qla1280); #endif - return pci_module_init(&qla1280_pci_driver); + return pci_register_driver(&qla1280_pci_driver); } static void __exit -- GitLab From a2a65a3ecb54ecd1a8f0409f11cb82ae083c6964 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 25 Sep 2006 16:59:07 -0700 Subject: [PATCH 0296/1619] [SCSI] Signedness issue in drivers/scsi/ipr.c gcc 4.1 with some extra warnings show the following: drivers/scsi/ipr.c:6361: warning: comparison of unsigned expression < 0 is always false drivers/scsi/ipr.c:6385: warning: comparison of unsigned expression < 0 is always false drivers/scsi/ipr.c:6415: warning: comparison of unsigned expression < 0 is always false The problem is that rc is of the type u32, which can never be smaller than zero, therefore all three error handling checks get useless. This patch changes it to a normal int, because all usages / all functions it get used with expect an int. Signed-off-by: Eric Sesterhenn Acked-by: Brian King Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2e21e162056..e1fe9494125 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6996,7 +6996,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, struct Scsi_Host *host; unsigned long ipr_regs_pci; void __iomem *ipr_regs; - u32 rc = PCIBIOS_SUCCESSFUL; + int rc = PCIBIOS_SUCCESSFUL; volatile u32 mask, uproc; ENTER; -- GitLab From 5e96f59f9b20373014abd5e30fba4805c5d4f53f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 26 Sep 2006 17:14:02 -0400 Subject: [PATCH 0297/1619] [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(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 48f982100f5..1d3e601ece7 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); -- GitLab From 7e18c02be7c83a8cfd1319f0117f63509c20aa8e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 27 Sep 2006 12:20:06 -0400 Subject: [PATCH 0298/1619] [GFS2] Fix bug in Makefiles for lock modules The Makefile had the wrong CONFIG_ variable in it so that in case GFS2 was y and the lock modules were m, they were not getting built properly. Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/Makefile | 2 +- fs/gfs2/locking/nolock/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile index a9733ff8037..89b93b6b45c 100644 --- a/fs/gfs2/locking/dlm/Makefile +++ b/fs/gfs2/locking/dlm/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_GFS2_FS) += lock_dlm.o +obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o diff --git a/fs/gfs2/locking/nolock/Makefile b/fs/gfs2/locking/nolock/Makefile index cdadf956c83..35e9730bc3a 100644 --- a/fs/gfs2/locking/nolock/Makefile +++ b/fs/gfs2/locking/nolock/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_GFS2_FS) += lock_nolock.o +obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += lock_nolock.o lock_nolock-y := main.o -- GitLab From 0e0bcae3bfb3c88dbe14735fa69d7d88794dc73a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 27 Sep 2006 14:45:07 -0400 Subject: [PATCH 0299/1619] [GFS2] Fix direct i/o logic in filemap.c We shouldn't mark the file accessed in the case that it wasn't accessed. Signed-off-by: Steven Whitehouse --- mm/filemap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index d9bbea1e87d..91a741ddd49 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1180,9 +1180,10 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (retval > 0) *ppos = pos + retval; } - file_accessed(filp); - if (retval != 0) + if (likely(retval != 0)) { + file_accessed(flip); goto out; + } } retval = 0; -- GitLab From 3f1a9aaeffd8d1cbc5ab9776c45cbd66af1c9699 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 27 Sep 2006 14:52:48 -0400 Subject: [PATCH 0300/1619] [GFS2] Fix typo in last patch Signed-off-by: Steven Whitehouse --- mm/filemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/filemap.c b/mm/filemap.c index 91a741ddd49..3195806d78e 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1181,7 +1181,7 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, *ppos = pos + retval; } if (likely(retval != 0)) { - file_accessed(flip); + file_accessed(filp); goto out; } } -- GitLab From 8350a348e97c2f8aa3e91c025c0e040c90146414 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 25 Sep 2006 16:59:15 -0700 Subject: [PATCH 0301/1619] [SCSI] scsi: device_reprobe() can fail device_reprobe() should return an error code. When it does so, scsi_device_reprobe() should propagate it back. Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- include/scsi/scsi_device.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 895d212864c..b401c82036b 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -298,9 +298,9 @@ extern int scsi_execute_async(struct scsi_device *sdev, void (*done)(void *, char *, int, int), gfp_t gfp); -static inline void scsi_device_reprobe(struct scsi_device *sdev) +static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) { - device_reprobe(&sdev->sdev_gendev); + return device_reprobe(&sdev->sdev_gendev); } static inline unsigned int sdev_channel(struct scsi_device *sdev) -- GitLab From c38778c3a9aeadcd1ee319cfc8ea5a9cbf8cdafa Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 26 Sep 2006 23:52:50 -0700 Subject: [PATCH 0302/1619] [PATCH] Fix reference of uninitialised memory in ata_device_add() ata_device_add fails, calls ata_host_remove with pointers to unitialized memory. Signed-off-by: Dave Jones Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b4abd685036..396493cc98c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5478,11 +5478,10 @@ int ata_device_add(const struct ata_probe_ent *ent) int irq_line = ent->irq; ap = ata_port_add(ent, host, i); + host->ports[i] = ap; if (!ap) goto err_out; - host->ports[i] = ap; - /* dummy? */ if (ent->dummy_port_mask & (1 << i)) { ata_port_printk(ap, KERN_INFO, "DUMMY\n"); -- GitLab From 54bb3a94b192be09feb85993b664ff118d6433d0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 27 Sep 2006 22:20:11 -0400 Subject: [PATCH 0303/1619] [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(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1aabc81d82f..54e1f38ce30 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 0e23ecb77bc..81f3d219e70 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 8cd730fe5dd..bbf29595a00 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 d627812ea73..15c9437710f 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 c63dbabc0cd..3d9fa1cc834 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 39cb07baeba..a951f40c2f2 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 18d49fff8dc..8e8dc3f2215 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 091867e10ea..2b3d44bf495 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 dd76f37be18..c2e6b7e59f0 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 d6a3d4b345f..df44b09fbae 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; -- GitLab From 1bd5bbcb6531776a8f73e2cc6287fc4dd542e1c7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 03:35:57 +0000 Subject: [PATCH 0304/1619] [CIFS] Legacy time handling for Win9x and OS/2 part 1 Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 3 +++ fs/cifs/cifssmb.c | 10 ++++++++- fs/cifs/inode.c | 7 +++++-- fs/cifs/link.c | 6 +++++- fs/cifs/netmisc.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/readdir.c | 7 +++++++ 6 files changed, 80 insertions(+), 4 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b35c55c3c8b..2fbc982aa13 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -80,6 +80,9 @@ extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, extern void DeleteOplockQEntry(struct oplock_q_entry *); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(struct timespec); +extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); +extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); + extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO * pfile_info, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 075d8fb3d37..2851d6e0d82 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2856,7 +2856,6 @@ qsec_out: return rc; } - /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, @@ -2898,7 +2897,16 @@ QInfRetry: if (rc) { cFYI(1, ("Send error in QueryInfo = %d", rc)); } else if (pFinfo) { /* decode response */ + struct timespec ts; + __u32 time = le32_to_cpu(pSMBr->last_write_time); + /* BB FIXME - add time zone adjustment BB */ memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); + ts.tv_nsec = 0; + ts.tv_sec = time; + /* decode time fields */ + pFinfo->ChangeTime = cifs_UnixTimeToNT(ts); + pFinfo->LastWriteTime = pFinfo->ChangeTime; + pFinfo->LastAccessTime = 0; pFinfo->AllocationSize = cpu_to_le64(le32_to_cpu(pSMBr->size)); pFinfo->EndOfFile = pFinfo->AllocationSize; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index b88147c1dc2..06dbce3a181 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -432,8 +432,11 @@ int cifs_get_inode_info(struct inode **pinode, (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ /* Linux can not store file creation time so ignore it */ - inode->i_atime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + if(pfindData->LastAccessTime) + inode->i_atime = cifs_NTtimeToUnix + (le64_to_cpu(pfindData->LastAccessTime)); + else /* do not need to use current_fs_time - time not stored */ + inode->i_atime = CURRENT_TIME; inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = diff --git a/fs/cifs/link.c b/fs/cifs/link.c index a57f5d6e621..0bee8b7e521 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -254,7 +254,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) tmpbuffer, len - 1, cifs_sb->local_nls); - else { + else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + cERROR(1,("SFU style symlinks not implemented yet")); + /* add open and read as in fs/cifs/inode.c */ + + } else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls, diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index ce87550e918..fa5124d9af1 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -909,3 +909,54 @@ cifs_UnixTimeToNT(struct timespec t) /* Convert to 100ns intervals and then add the NTFS time offset. */ return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; } + +static int total_days_of_prev_months[] = +{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + +__le64 cnvrtDosCifsTm(__u16 date, __u16 time) +{ + return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time))); +} +struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) +{ + __u8 dt[2]; + __u8 tm[2]; + struct timespec ts; + int sec,min, days, month, year; + struct timespec removeme; /* BB removeme BB */ +/* SMB_TIME * st = (SMB_TIME *)&time;*/ + + cFYI(1,("date %d time %d",date, time)); + + dt[0] = date & 0xFF; + dt[1] = (date & 0xFF00) >> 8; + tm[0] = time & 0xFF; + tm[1] = (time & 0xFF00) >> 8; + + sec = tm[0] & 0x1F; + sec = 2 * sec; + min = ((tm[0] >>5)&0xFF) + ((tm[1] & 0x7)<<3); + + sec += (min * 60); + sec += 60 * 60 * ((tm[1] >> 3) &0xFF) /* hours */; + days = (dt[0] & 0x1F) - 1; + month = ((dt[0] >> 5) & 0xFF) + ((dt[1] & 0x1) <<3); + if(month > 12) + cERROR(1,("illegal month %d in date", month)); + month -= 1; + days += total_days_of_prev_months[month]; + days += 3653; /* account for difference in days between 1980 and 1970 */ + year = (dt[1]>>1) & 0xFF; + days += year * 365; + days += (year/4); /* leap year */ + /* adjust for leap year where we are still before leap day */ + days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); + sec += 24 * 60 * 60 * days; + + removeme = CURRENT_TIME; /* BB removeme BB */ + ts.tv_sec = sec; + + ts.tv_nsec = 0; + return ts; +} diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9aeb58a7d36..71e86c38e63 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -135,12 +135,19 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, tmp_inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); } else { /* legacy, OS2 and DOS style */ +/* struct timespec ts;*/ FIND_FILE_STANDARD_INFO * pfindData = (FIND_FILE_STANDARD_INFO *)buf; +/* ts = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastWriteDate), + le16_to_cpu(pfindData->LastWriteTime));*/ attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); + /* do not need to use current_fs_time helper function since + time not stored for this case so atime can not "go backwards" + by pulling newer older from disk when inode refrenshed */ tmp_inode->i_atime = CURRENT_TIME; /* tmp_inode->i_mtime = BB FIXME - add dos time handling tmp_inode->i_ctime = 0; BB FIXME */ -- GitLab From c791c30670ea61f19eec390124128bf278e854fe Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 28 Sep 2006 03:40:11 -0400 Subject: [PATCH 0305/1619] [libata] minor PCI IDE probe fixes and cleanups * Replace needless 'n_ports > 2' check with a simple BUG_ON(). No existing driver ever wants more than 2 ports. * Delete ATA_FLAG_NO_LEGACY check. No current driver uses ata_pci_init_one(), that sets this flag. * Move PCI_CLASS_PROG register read below pci_enable_device() * Handle ata_device_add() failure Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 08b3a407473..a620e235ccc 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -946,35 +946,21 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, { struct ata_probe_ent *probe_ent = NULL; struct ata_port_info *port[2]; - u8 tmp8, mask; + u8 mask; unsigned int legacy_mode = 0; int disable_dev_on_err = 1; int rc; DPRINTK("ENTER\n"); + BUG_ON(n_ports < 1 || n_ports > 2); + port[0] = port_info[0]; if (n_ports > 1) port[1] = port_info[1]; else port[1] = port[0]; - if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0 - && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - /* TODO: What if one channel is in native mode ... */ - pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); - mask = (1 << 2) | (1 << 0); - if ((tmp8 & mask) != mask) - legacy_mode = (1 << 3); - } - - /* FIXME... */ - if ((!legacy_mode) && (n_ports > 2)) { - printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n"); - n_ports = 2; - /* For now */ - } - /* FIXME: Really for ATA it isn't safe because the device may be multi-purpose and we want to leave it alone if it was already enabled. Secondly for shared use as Arjan says we want refcounting @@ -987,6 +973,16 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if (rc) return rc; + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u8 tmp8; + + /* TODO: What if one channel is in native mode ... */ + pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); + mask = (1 << 2) | (1 << 0); + if ((tmp8 & mask) != mask) + legacy_mode = (1 << 3); + } + rc = pci_request_regions(pdev, DRV_NAME); if (rc) { disable_dev_on_err = 0; @@ -1039,7 +1035,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out_regions; } - /* FIXME: If we get no DMA mask we should fall back to PIO */ + /* TODO: If we get no DMA mask we should fall back to PIO */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; @@ -1062,13 +1058,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, pci_set_master(pdev); - /* FIXME: check ata_device_add return */ - ata_device_add(probe_ent); + if (!ata_device_add(probe_ent)) { + rc = -ENODEV; + goto err_out_ent; + } kfree(probe_ent); return 0; +err_out_ent: + kfree(probe_ent); err_out_regions: if (legacy_mode & ATA_PORT_PRIMARY) release_region(ATA_PRIMARY_CMD, 8); -- GitLab From d639ca94188fedbd8cfde1ab4ed9e9878ab2f01e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 28 Sep 2006 03:48:18 -0400 Subject: [PATCH 0306/1619] [libata] init probe_ent->private_data in a common location Don't write the same code twice, in two different functions, when they both call the same initialization function, with the same private_data pointer info. Also, note a bug found with a FIXME. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-sff.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 396493cc98c..72644bdecbb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5785,6 +5785,7 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) probe_ent->mwdma_mask = port->mwdma_mask; probe_ent->udma_mask = port->udma_mask; probe_ent->port_ops = port->port_ops; + probe_ent->private_data = port->private_data; return probe_ent; } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index a620e235ccc..06daaa3736a 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -828,7 +828,6 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->private_data = port[0]->private_data; if (ports & ATA_PORT_PRIMARY) { probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); @@ -878,7 +877,6 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, return NULL; probe_ent->n_ports = 2; - probe_ent->private_data = port[0]->private_data; if (port_mask & ATA_PORT_PRIMARY) { probe_ent->irq = ATA_PRIMARY_IRQ; @@ -908,6 +906,8 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[1]); + + /* FIXME: could be pointing to stack area; must copy */ probe_ent->pinfo2 = port[1]; } else probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY; -- GitLab From 35aa7a436c0901fd6f352eff347f58448c141a25 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 28 Sep 2006 06:50:24 -0400 Subject: [PATCH 0307/1619] [libata] Print out Status register, if a BSY-sleep takes too long We have the info stored in an ata_busy_sleep() variable, so might as well print it, and provide some additional diagnostic info. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 72644bdecbb..7ab45f42ae7 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2340,7 +2340,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap, if (status & ATA_BUSY) ata_port_printk(ap, KERN_WARNING, - "port is slow to respond, please be patient\n"); + "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))) { @@ -2350,7 +2351,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap, if (status & ATA_BUSY) { ata_port_printk(ap, KERN_ERR, "port failed to respond " - "(%lu secs)\n", tmout / HZ); + "(%lu secs, Status 0x%x)\n", + tmout / HZ, status); return 1; } -- GitLab From bba9dfd83587017de1c55a94c077983e0dfa0251 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:31 -0700 Subject: [PATCH 0308/1619] [GFS2] inode_diet: Replace inode.u.generic_ip with inode.i_private (gfs) 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. Signed-off-by: "Theodore Ts'o" Cc: Steven Whitehouse Signed-off-by: Andrew Morton --- fs/dlm/debug_fs.c | 4 ++-- fs/gfs2/inode.c | 2 +- fs/gfs2/meta_io.c | 2 +- fs/gfs2/ops_super.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 9c3aeddc866..ca94a837a5b 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -282,7 +282,7 @@ static int rsb_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; } @@ -301,7 +301,7 @@ static struct file_operations rsb_fops = { static int waiters_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/fs/gfs2/inode.c b/fs/gfs2/inode.c index ac9535be304..784d145058c 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -160,7 +160,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, 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_private = ip; inode->i_mode = mode; if (S_ISREG(mode)) { diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index d3708af0a4d..73179915318 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -78,7 +78,7 @@ struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS); aspace->i_mapping->a_ops = &aspace_aops; aspace->i_size = ~0ULL; - aspace->u.generic_ip = NULL; + aspace->i_private = NULL; insert_inode_hash(aspace); } return aspace; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 8cfda645213..06f06f7773d 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -53,7 +53,7 @@ static int gfs2_write_inode(struct inode *inode, int sync) struct gfs2_inode *ip = GFS2_I(inode); /* Check this is a "normal" inode */ - if (inode->u.generic_ip) { + if (inode->i_private) { if (current->flags & PF_MEMALLOC) return 0; if (sync) @@ -280,7 +280,7 @@ static void gfs2_clear_inode(struct inode *inode) * 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) { + if (inode->i_private) { 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); @@ -381,7 +381,7 @@ static void gfs2_delete_inode(struct inode *inode) struct gfs2_holder gh; int error; - if (!inode->u.generic_ip) + if (!inode->i_private) goto out; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &gh); -- GitLab From 825f9075d74028d11d7f5932f04e1b5db3022b51 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:32 -0700 Subject: [PATCH 0309/1619] [GFS2] 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. Signed-off-by: "Theodore Ts'o" Cc: Steven Whitehouse Signed-off-by: Andrew Morton --- fs/gfs2/inode.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 784d145058c..57a4c8b6858 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -72,7 +72,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) 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 = di->di_blocks << (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); -- GitLab From 2cd646a2d1d5e0e46aa4bb55b1847b0cb35bd855 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 19:43:08 +0000 Subject: [PATCH 0310/1619] [CIFS] Remove static and unused symbols Most cases of the ones found by Shaggy by "make namespacecheck" could be removed or made static Ack: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/cifsacl.h | 4 ++-- fs/cifs/cifsencrypt.h | 2 -- fs/cifs/cifsfs.c | 5 +++-- fs/cifs/cifsfs.h | 2 +- fs/cifs/cifsglob.h | 4 ++-- fs/cifs/cifsproto.h | 6 ++---- fs/cifs/cifssmb.c | 6 ++++-- fs/cifs/connect.c | 20 ++++++++++++-------- fs/cifs/md5.c | 4 ++-- fs/cifs/md5.h | 8 ++++---- fs/cifs/misc.c | 2 +- fs/cifs/smbdes.c | 4 ++-- fs/cifs/smbencrypt.c | 4 ++-- 13 files changed, 37 insertions(+), 34 deletions(-) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index d0776ac2b80..5eff35d6e56 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -31,8 +31,8 @@ struct cifs_sid { } __attribute__((packed)); /* everyone */ -extern const struct cifs_sid sid_everyone; +/* extern const struct cifs_sid sid_everyone;*/ /* group users */ -extern const struct cifs_sid sid_user; +/* extern const struct cifs_sid sid_user;*/ #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h index 03e359b3286..152fa2dcfc6 100644 --- a/fs/cifs/cifsencrypt.h +++ b/fs/cifs/cifsencrypt.h @@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); /* smbdes.c */ extern void E_P16(unsigned char *p14, unsigned char *p16); extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); -extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out); -extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f5ba4113248..cd17d4b7817 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -442,7 +442,7 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data) return 0; } -struct super_operations cifs_super_ops = { +static struct super_operations cifs_super_ops = { .read_inode = cifs_read_inode, .put_super = cifs_put_super, .statfs = cifs_statfs, @@ -930,7 +930,7 @@ init_cifs(void) #ifdef CONFIG_PROC_FS cifs_proc_init(); #endif - INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ +/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ INIT_LIST_HEAD(&GlobalSMBSessionList); INIT_LIST_HEAD(&GlobalTreeConnectionList); INIT_LIST_HEAD(&GlobalOplock_Q); @@ -958,6 +958,7 @@ init_cifs(void) GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; GlobalMaxActiveXid = 0; + memset(Local_System_Name, 0, 15); rwlock_init(&GlobalSMBSeslock); spin_lock_init(&GlobalMid_Lock); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index bea875d9a46..a243f779b36 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -36,7 +36,7 @@ extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to super block operations */ -extern struct super_operations cifs_super_ops; +/* extern struct super_operations cifs_super_ops;*/ extern void cifs_read_inode(struct inode *); extern void cifs_delete_inode(struct inode *); /* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b24006c47df..441f8d2514f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -512,7 +512,8 @@ require use of the stronger protocol */ * This list helps improve performance and eliminate the messages indicating * that we had a communications error talking to the server in this list. */ -GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ +/* Feature not supported */ +/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */ /* * The following is a hash table of all the users we know about. @@ -568,7 +569,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ -GLOBAL_EXTERN unsigned int secFlags; GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 2fbc982aa13..7dd2f48a407 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -50,11 +50,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, struct kvec *, int /* nvec to send */, int * /* type of buf returned */ , const int long_op); -extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, +extern int SendReceiveBlockingLock(const unsigned int /* xid */ , + struct cifsTconInfo *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , int * /* bytes returned */); -extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_size_safe_to_change(struct cifsInodeInfo *); @@ -282,8 +282,6 @@ extern void sesInfoFree(struct cifsSesInfo *); extern struct cifsTconInfo *tconInfoAlloc(void); extern void tconInfoFree(struct cifsTconInfo *); -extern int cifs_reconnect(struct TCP_Server_Info *server); - extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, __u32 *); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2851d6e0d82..dcd7087a1ae 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2773,9 +2773,11 @@ GetExtAttrOut: /* security id for everyone */ -const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; +const static struct cifs_sid sid_everyone = + {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; /* group users */ -const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; +const static struct cifs_sid sid_user = + {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; /* Convert CIFS ACL to POSIX form */ static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0e9ba0b9d71..b3268e53ab9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -109,7 +109,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server, * wake up waiters on reconnection? - (not needed currently) */ -int +static int cifs_reconnect(struct TCP_Server_Info *server) { int rc = 0; @@ -771,13 +771,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) separator[0] = ','; separator[1] = 0; - memset(vol->source_rfc1001_name,0x20,15); - for(i=0;i < strnlen(system_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]); + if(Local_System_Name[0] != 0) + memcpy(vol->source_rfc1001_name, Local_System_Name,15); + else { + memset(vol->source_rfc1001_name,0x20,15); + for(i=0;i < strnlen(system_utsname.nodename,15);i++) { + /* does not have to be perfect mapping since 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]); + } } vol->source_rfc1001_name[15] = 0; /* null target name indicates to use *SMBSERVR default called name diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c index 7aa23490541..273aa0383f2 100644 --- a/fs/cifs/md5.c +++ b/fs/cifs/md5.c @@ -255,7 +255,7 @@ MD5Transform(__u32 buf[4], __u32 const in[16]) /*********************************************************************** the rfc 2104 version of hmac_md5 initialisation. ***********************************************************************/ -void +static void hmac_md5_init_rfc2104(unsigned char *key, int key_len, struct HMACMD5Context *ctx) { @@ -350,7 +350,7 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) single function to calculate an HMAC MD5 digest from data. use the microsoft hmacmd5 init method because the key is 16 bytes. ************************************************************/ -void +static void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, unsigned char *digest) { diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h index 00e1c5394fe..f7d4f4197ba 100644 --- a/fs/cifs/md5.h +++ b/fs/cifs/md5.h @@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context); /* The following definitions come from lib/hmacmd5.c */ -void hmac_md5_init_rfc2104(unsigned char *key, int key_len, - struct HMACMD5Context *ctx); +/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len, + struct HMACMD5Context *ctx);*/ void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, struct HMACMD5Context *ctx); void hmac_md5_update(const unsigned char *text, int text_len, struct HMACMD5Context *ctx); void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); -void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, - unsigned char *digest); +/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, + unsigned char *digest);*/ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 22c937e5884..ca6e9b1413f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -389,7 +389,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , return; } -int +static int checkSMBhdr(struct smb_hdr *smb, __u16 mid) { /* Make sure that this really is an SMB, that it is a response, diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index efaa044523a..2b193e422f8 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -364,14 +364,14 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) smbhash(p24 + 16, c8, p21 + 14, 1); } -void +static void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) { smbhash(out, in, p14, 0); smbhash(out + 8, in + 8, p14 + 7, 0); } -void +static void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) { smbhash(out, in, p14, 1); diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index f518c5e4503..c7e55a940e2 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -145,7 +145,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) } /* Does both the NT and LM owfs of a user's password */ -void +static void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) { char passwd[514]; @@ -223,7 +223,7 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, } /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ -void +static void NTLMSSPOWFencrypt(unsigned char passwd[8], unsigned char *ntlmchalresp, unsigned char p24[24]) { -- GitLab From e33c74d06e2b46a5f187ec7f60248da774c84e72 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:35:48 +0000 Subject: [PATCH 0311/1619] [CIFS] Fix build break Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index cd17d4b7817..51e888fcef2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -63,6 +63,7 @@ extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; extern struct task_struct * dnotifyThread; /* remove sparse warning */ struct task_struct * dnotifyThread = NULL; +static struct super_operations cifs_super_ops; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; module_param(CIFSMaxBufSize, int, 0); MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); -- GitLab From 2eaf55862e8eb03999169d84f21eadffc88a36ce Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:41:48 +0000 Subject: [PATCH 0312/1619] [CIFS] Remove unused prototypes Signed-off-by: Steve French --- fs/cifs/smbencrypt.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index c7e55a940e2..48314e5e785 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -51,11 +51,8 @@ void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); void E_md4hash(const unsigned char *passwd, unsigned char *p16); -void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]); static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, unsigned char p24[24]); -void NTLMSSPOWFencrypt(unsigned char passwd[8], - unsigned char *ntlmchalresp, unsigned char p24[24]); void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); /* -- GitLab From e10847ed499cb86bf8ce12f3a686be8a98f8e140 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:49:01 +0000 Subject: [PATCH 0313/1619] [CIFS] More removing of unused functions Signed-off-by: Steve French --- fs/cifs/md5.c | 4 ++++ fs/cifs/smbdes.c | 2 +- fs/cifs/smbencrypt.c | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c index 273aa0383f2..e6a2097d836 100644 --- a/fs/cifs/md5.c +++ b/fs/cifs/md5.c @@ -252,6 +252,7 @@ MD5Transform(__u32 buf[4], __u32 const in[16]) buf[3] += d; } +#if 0 /* currently unused */ /*********************************************************************** the rfc 2104 version of hmac_md5 initialisation. ***********************************************************************/ @@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len, MD5Init(&ctx->ctx); MD5Update(&ctx->ctx, ctx->k_ipad, 64); } +#endif /*********************************************************************** the microsoft version of hmac_md5 initialisation. @@ -333,6 +335,7 @@ hmac_md5_update(const unsigned char *text, int text_len, /*********************************************************************** finish off hmac_md5 "inner" buffer and generate outer one. ***********************************************************************/ +#if 0 /* currently unused */ void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) { @@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len, } hmac_md5_final(digest, &ctx); } +#endif diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 2b193e422f8..7a1b2b961ec 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -364,6 +364,7 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) smbhash(p24 + 16, c8, p21 + 14, 1); } +#if 0 /* currently unsued */ static void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) { @@ -377,7 +378,6 @@ E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) smbhash(out, in, p14, 1); smbhash(out + 8, in + 8, p14 + 7, 1); } -#if 0 /* these routines are currently unneeded, but may be needed later */ void diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 48314e5e785..4b25ba92180 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -141,6 +141,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) memset(wpwd,0,129 * 2); } +#if 0 /* currently unused */ /* Does both the NT and LM owfs of a user's password */ static void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) @@ -168,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) /* clear out local copy of user's password (just being paranoid). */ memset(passwd, '\0', sizeof (passwd)); } +#endif /* Does the NTLMv2 owfs of a user's password */ #if 0 /* function not needed yet - but will be soon */ @@ -220,6 +222,7 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, } /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ +#if 0 /* currently unused */ static void NTLMSSPOWFencrypt(unsigned char passwd[8], unsigned char *ntlmchalresp, unsigned char p24[24]) @@ -232,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8], E_P24(p21, ntlmchalresp, p24); } +#endif /* Does the NT MD4 hash then des encryption. */ -- GitLab From a3ab41f10e2f5087e515da358680c88dd61d4832 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:52:08 +0000 Subject: [PATCH 0314/1619] [CIFS] Fix build break ifdef in wrong place Signed-off-by: Steve French --- fs/cifs/md5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c index e6a2097d836..ccebf9b7eb8 100644 --- a/fs/cifs/md5.c +++ b/fs/cifs/md5.c @@ -335,7 +335,6 @@ hmac_md5_update(const unsigned char *text, int text_len, /*********************************************************************** finish off hmac_md5 "inner" buffer and generate outer one. ***********************************************************************/ -#if 0 /* currently unused */ void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) { @@ -353,6 +352,7 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) single function to calculate an HMAC MD5 digest from data. use the microsoft hmacmd5 init method because the key is 16 bytes. ************************************************************/ +#if 0 /* currently unused */ static void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, unsigned char *digest) -- GitLab From bf97d28711e2dc4dc947faa6477cd1b36b91a2da Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 21:34:06 +0000 Subject: [PATCH 0315/1619] [CIFS] CIFS support for /proc//mountstats part 1 Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 51e888fcef2..7ecfcbf31e5 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -437,6 +437,14 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) return; } +#ifdef CONFIG_CIFS_STATS2 +static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt) +{ + /* BB FIXME */ + return 0; +} +#endif + static int cifs_remount(struct super_block *sb, int *flags, char *data) { *flags |= MS_NODIRATIME; @@ -456,6 +464,9 @@ static struct super_operations cifs_super_ops = { .show_options = cifs_show_options, .umount_begin = cifs_umount_begin, .remount_fs = cifs_remount, +#ifdef CONFIG_CIFS_STATS2 + cifs_show_stats, +#endif }; static int -- GitLab From 2d2744fc8be620a2dc469cf48349e3e704119f1b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 28 Sep 2006 20:21:59 -0400 Subject: [PATCH 0316/1619] [libata] PCI ID table cleanup in various drivers * Use PCI_VDEVICE() macro * const-ify pci_device_id table * standardize list terminator as "{ }" * convert spaces to tab in pci_driver struct (Alan-ism) * various minor whitespace cleanups Signed-off-by: Jeff Garzik --- drivers/ata/pata_ali.c | 9 ++++---- drivers/ata/pata_amd.c | 38 ++++++++++++++++----------------- drivers/ata/pata_artop.c | 12 +++++------ drivers/ata/pata_atiixp.c | 14 ++++++------ drivers/ata/pata_cmd64x.c | 17 +++++++-------- drivers/ata/pata_cs5520.c | 10 ++++----- drivers/ata/pata_cs5530.c | 11 +++++----- drivers/ata/pata_cs5535.c | 9 ++++---- drivers/ata/pata_cypress.c | 13 +++++------ drivers/ata/pata_efar.c | 4 ++-- drivers/ata/pata_hpt366.c | 9 ++++---- drivers/ata/pata_hpt37x.c | 19 ++++++++--------- drivers/ata/pata_hpt3x2n.c | 17 +++++++-------- drivers/ata/pata_hpt3x3.c | 9 ++++---- drivers/ata/pata_it821x.c | 13 ++++++----- drivers/ata/pata_jmicron.c | 11 +++++----- drivers/ata/pata_mpiix.c | 9 +++----- drivers/ata/pata_netcell.c | 3 ++- drivers/ata/pata_ns87410.c | 9 ++++---- drivers/ata/pata_oldpiix.c | 4 ++-- drivers/ata/pata_opti.c | 10 ++++----- drivers/ata/pata_optidma.c | 9 ++++---- drivers/ata/pata_pdc2027x.c | 15 +++++++------ drivers/ata/pata_pdc202xx_old.c | 19 ++++++++--------- drivers/ata/pata_radisys.c | 4 ++-- drivers/ata/pata_rz1000.c | 12 +++++------ drivers/ata/pata_sc1200.c | 11 +++++----- drivers/ata/pata_serverworks.c | 17 +++++++-------- drivers/ata/pata_sil680.c | 9 ++++---- drivers/ata/pata_sis.c | 6 +++--- drivers/ata/pata_sl82c105.c | 9 ++++---- drivers/ata/pata_triflex.c | 10 ++++----- drivers/ata/pata_via.c | 15 ++++++------- drivers/ata/sata_mv.c | 27 ++++++++++++----------- drivers/ata/sata_nv.c | 3 ++- drivers/ata/sata_qstor.c | 3 +-- drivers/ata/sata_sis.c | 2 +- drivers/ata/sata_svw.c | 15 ++++++------- drivers/ata/sata_sx4.c | 1 - drivers/ata/sata_uli.c | 1 - drivers/ata/sata_via.c | 6 +++--- drivers/ata/sata_vsc.c | 6 +----- 42 files changed, 215 insertions(+), 235 deletions(-) diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 87af3b5861a..3f49e38217d 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -644,10 +644,11 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } -static struct pci_device_id ali[] = { - { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), }, - { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), }, - { 0, }, +static const struct pci_device_id ali[] = { + { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, + { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, + + { }, }; static struct pci_driver ali_pci_driver = { diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 599ee266722..29234c89711 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -662,27 +662,28 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } static const struct pci_device_id amd[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, - { 0, }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 3 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 4 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 7 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 8 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 8 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 }, + + { }, }; static struct pci_driver amd_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = amd, .probe = amd_init_one, .remove = ata_pci_remove_one @@ -698,7 +699,6 @@ static void __exit amd_exit(void) pci_unregister_driver(&amd_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for AMD PATA IDE"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index c4ccb75a4f1..49565ef945f 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -475,11 +475,12 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) } static const struct pci_device_id artop_pci_tbl[] = { - { 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VDEVICE(ARTOP, 0x0005), 0 }, + { PCI_VDEVICE(ARTOP, 0x0006), 1 }, + { PCI_VDEVICE(ARTOP, 0x0007), 1 }, + { PCI_VDEVICE(ARTOP, 0x0008), 2 }, + { PCI_VDEVICE(ARTOP, 0x0009), 2 }, + { } /* terminate list */ }; @@ -500,7 +501,6 @@ static void __exit artop_exit(void) pci_unregister_driver(&artop_pci_driver); } - module_init(artop_init); module_exit(artop_exit); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 6c2269b6bd3..1ce28d2125f 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -267,12 +267,13 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static struct pci_device_id atiixp[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), }, - { 0, }, +static const struct pci_device_id atiixp[] = { + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), }, + + { }, }; static struct pci_driver atiixp_pci_driver = { @@ -293,7 +294,6 @@ static void __exit atiixp_exit(void) pci_unregister_driver(&atiixp_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index e92b0ef43ec..b9bbd1d454b 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -468,16 +468,17 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } -static struct pci_device_id cmd64x[] = { - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { 0, }, +static const struct pci_device_id cmd64x[] = { + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 }, + + { }, }; static struct pci_driver cmd64x_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = cmd64x, .probe = cmd64x_init_one, .remove = ata_pci_remove_one @@ -488,13 +489,11 @@ static int __init cmd64x_init(void) return pci_register_driver(&cmd64x_pci_driver); } - static void __exit cmd64x_exit(void) { pci_unregister_driver(&cmd64x_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index a6c6cebd0da..2cd3c0ff76d 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -299,10 +299,11 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev) /* For now keep DMA off. We can set it for all but A rev CS5510 once the core ATA code can handle it */ -static struct pci_device_id pata_cs5520[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), }, - { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), }, - { 0, }, +static const struct pci_device_id pata_cs5520[] = { + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), }, + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), }, + + { }, }; static struct pci_driver cs5520_pci_driver = { @@ -312,7 +313,6 @@ static struct pci_driver cs5520_pci_driver = { .remove = cs5520_remove_one }; - static int __init cs5520_init(void) { return pci_register_driver(&cs5520_pci_driver); diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 7bba4d954e9..a07cc81ef79 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -353,13 +353,14 @@ fail_put: return -ENODEV; } -static struct pci_device_id cs5530[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, - { 0, }, +static const struct pci_device_id cs5530[] = { + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, + + { }, }; static struct pci_driver cs5530_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = cs5530, .probe = cs5530_init_one, .remove = ata_pci_remove_one @@ -370,13 +371,11 @@ static int __init cs5530_init(void) return pci_register_driver(&cs5530_pci_driver); } - static void __exit cs5530_exit(void) { pci_unregister_driver(&cs5530_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index d64fcdceaf0..f8def3f9c61 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -257,9 +257,10 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, ports, 1); } -static struct pci_device_id cs5535[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), }, - { 0, }, +static const struct pci_device_id cs5535[] = { + { PCI_VDEVICE(NS, 0x002D), }, + + { }, }; static struct pci_driver cs5535_pci_driver = { @@ -274,13 +275,11 @@ static int __init cs5535_init(void) return pci_register_driver(&cs5535_pci_driver); } - static void __exit cs5535_exit(void) { pci_unregister_driver(&cs5535_pci_driver); } - MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch"); MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index dfa5ac53904..247b43608b1 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -184,8 +184,8 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i }; static struct ata_port_info *port_info[1] = { &info }; - /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the - moment we don't handle the secondary. FIXME */ + /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. + For the moment we don't handle the secondary. FIXME */ if (PCI_FUNC(pdev->devfn) != 1) return -ENODEV; @@ -193,13 +193,14 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i return ata_pci_init_one(pdev, port_info, 1); } -static struct pci_device_id cy82c693[] = { - { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, +static const struct pci_device_id cy82c693[] = { + { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), }, + + { }, }; static struct pci_driver cy82c693_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = cy82c693, .probe = cy82c693_init_one, .remove = ata_pci_remove_one diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 95cd1ca181f..ef18c60fe14 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -305,7 +305,8 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } static const struct pci_device_id efar_pci_tbl[] = { - { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VDEVICE(EFAR, 0x9130), }, + { } /* terminate list */ }; @@ -326,7 +327,6 @@ static void __exit efar_exit(void) pci_unregister_driver(&efar_pci_driver); } - module_init(efar_init); module_exit(efar_exit); diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index cf656ecbe50..68a0e572f80 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -444,13 +444,14 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static struct pci_device_id hpt36x[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), }, - { 0, }, +static const struct pci_device_id hpt36x[] = { + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, + + { }, }; static struct pci_driver hpt36x_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt36x, .probe = hpt36x_init_one, .remove = ata_pci_remove_one diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 10318c0012e..7350443948c 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -1219,17 +1219,18 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static struct pci_device_id hpt37x[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), }, - { 0, }, +static const struct pci_device_id hpt37x[] = { + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), }, + + { }, }; static struct pci_driver hpt37x_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt37x, .probe = hpt37x_init_one, .remove = ata_pci_remove_one @@ -1240,13 +1241,11 @@ static int __init hpt37x_init(void) return pci_register_driver(&hpt37x_pci_driver); } - static void __exit hpt37x_exit(void) { pci_unregister_driver(&hpt37x_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 5c5d4f6ab90..58cfb2bc809 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -560,16 +560,17 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static struct pci_device_id hpt3x2n[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), }, - { 0, }, +static const struct pci_device_id hpt3x2n[] = { + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), }, + + { }, }; static struct pci_driver hpt3x2n_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt3x2n, .probe = hpt3x2n_init_one, .remove = ata_pci_remove_one @@ -580,13 +581,11 @@ static int __init hpt3x2n_init(void) return pci_register_driver(&hpt3x2n_pci_driver); } - static void __exit hpt3x2n_exit(void) { pci_unregister_driver(&hpt3x2n_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 1f084ab1ccc..3334d72e251 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -192,13 +192,14 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static struct pci_device_id hpt3x3[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), }, - { 0, }, +static const struct pci_device_id hpt3x3[] = { + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), }, + + { }, }; static struct pci_driver hpt3x3_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt3x3, .probe = hpt3x3_init_one, .remove = ata_pci_remove_one diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 82a46ff4000..18ff3e59a89 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -808,14 +808,15 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } -static struct pci_device_id it821x[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), }, - { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), }, - { 0, }, +static const struct pci_device_id it821x[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), }, + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), }, + + { }, }; static struct pci_driver it821x_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = it821x, .probe = it821x_init_one, .remove = ata_pci_remove_one @@ -826,13 +827,11 @@ static int __init it821x_init(void) return pci_register_driver(&it821x_pci_driver); } - static void __exit it821x_exit(void) { pci_unregister_driver(&it821x_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index be3a866b111..52a2bdf3c38 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -229,11 +229,12 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i } static const struct pci_device_id jmicron_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368}, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361}, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363}, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365}, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366}, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368}, + { } /* terminate list */ }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 3c65393c1f0..9dfe3e9abea 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -274,11 +274,10 @@ static void __devexit mpiix_remove_one(struct pci_dev *pdev) dev_set_drvdata(dev, NULL); } - - static const struct pci_device_id mpiix[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), }, - { 0, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), }, + + { }, }; static struct pci_driver mpiix_pci_driver = { @@ -293,13 +292,11 @@ static int __init mpiix_init(void) return pci_register_driver(&mpiix_pci_driver); } - static void __exit mpiix_exit(void) { pci_unregister_driver(&mpiix_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Intel MPIIX"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 76eb9c90bee..f5672de99c2 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -142,7 +142,8 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e } static const struct pci_device_id netcell_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), }, + { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), }, + { } /* terminate list */ }; diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 2005a95f48f..2a3dbeed89b 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -200,12 +200,13 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) } static const struct pci_device_id ns87410[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), }, - { 0, }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), }, + + { }, }; static struct pci_driver ns87410_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = ns87410, .probe = ns87410_init_one, .remove = ata_pci_remove_one @@ -216,13 +217,11 @@ static int __init ns87410_init(void) return pci_register_driver(&ns87410_pci_driver); } - static void __exit ns87410_exit(void) { pci_unregister_driver(&ns87410_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Nat Semi 87410"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 31a285ca88d..fc947dfecd7 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -303,7 +303,8 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e } static const struct pci_device_id oldpiix_pci_tbl[] = { - { PCI_DEVICE(0x8086, 0x1230), }, + { PCI_VDEVICE(INTEL, 0x1230), }, + { } /* terminate list */ }; @@ -324,7 +325,6 @@ static void __exit oldpiix_exit(void) pci_unregister_driver(&oldpiix_pci_driver); } - module_init(oldpiix_init); module_exit(oldpiix_exit); diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 57fe21f3a97..a7320ba1557 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -256,13 +256,14 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) } static const struct pci_device_id opti[] = { - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0, }, + { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 }, + { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 }, + + { }, }; static struct pci_driver opti_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = opti, .probe = opti_init_one, .remove = ata_pci_remove_one @@ -273,7 +274,6 @@ static int __init opti_init(void) return pci_register_driver(&opti_pci_driver); } - static void __exit opti_exit(void) { pci_unregister_driver(&opti_pci_driver); diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 7296a20cd10..c6906b4215d 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -512,12 +512,13 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) } static const struct pci_device_id optidma[] = { - { PCI_DEVICE(0x1045, 0xD568), }, /* Opti 82C700 */ - { 0, }, + { PCI_VDEVICE(OPTI, 0xD568), }, /* Opti 82C700 */ + + { }, }; static struct pci_driver optidma_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = optidma, .probe = optidma_init_one, .remove = ata_pci_remove_one @@ -528,13 +529,11 @@ static int __init optidma_init(void) return pci_register_driver(&optidma_pci_driver); } - static void __exit optidma_exit(void) { pci_unregister_driver(&optidma_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index bd4ed6734ed..d894d9918b1 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -108,13 +108,14 @@ static struct pdc2027x_udma_timing { }; static const struct pci_device_id pdc2027x_pci_tbl[] = { - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 }, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 }, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), PDC_UDMA_133 }, + { } /* terminate list */ }; diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 48f43432764..5ba9eb20a6c 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -385,17 +385,18 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static struct pci_device_id pdc[] = { - { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0}, - { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1}, - { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1}, - { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2}, - { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2}, - { 0, }, +static const struct pci_device_id pdc[] = { + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 }, + + { }, }; static struct pci_driver pdc_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = pdc, .probe = pdc_init_one, .remove = ata_pci_remove_one @@ -406,13 +407,11 @@ static int __init pdc_init(void) return pci_register_driver(&pdc_pci_driver); } - static void __exit pdc_exit(void) { pci_unregister_driver(&pdc_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index c20bcf43ed6..1af83d7694d 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -300,7 +300,8 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e } static const struct pci_device_id radisys_pci_tbl[] = { - { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VDEVICE(RADISYS, 0x8201), }, + { } /* terminate list */ }; @@ -321,7 +322,6 @@ static void __exit radisys_exit(void) pci_unregister_driver(&radisys_pci_driver); } - module_init(radisys_init); module_exit(radisys_exit); diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index eccc6fd4503..4533b6357d9 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -170,20 +170,20 @@ fail: return -ENODEV; } -static struct pci_device_id pata_rz1000[] = { - { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), }, - { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), }, - { 0, }, +static const struct pci_device_id pata_rz1000[] = { + { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), }, + { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), }, + + { }, }; static struct pci_driver rz1000_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = pata_rz1000, .probe = rz1000_init_one, .remove = ata_pci_remove_one }; - static int __init rz1000_init(void) { return pci_register_driver(&rz1000_pci_driver); diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 107e6cd3dc0..067d9d223e3 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -253,13 +253,14 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 1); } -static struct pci_device_id sc1200[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), }, - { 0, }, +static const struct pci_device_id sc1200[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), }, + + { }, }; static struct pci_driver sc1200_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = sc1200, .probe = sc1200_init_one, .remove = ata_pci_remove_one @@ -270,13 +271,11 @@ static int __init sc1200_init(void) return pci_register_driver(&sc1200_pci_driver); } - static void __exit sc1200_exit(void) { pci_unregister_driver(&sc1200_pci_driver); } - MODULE_AUTHOR("Alan Cox, Mark Lord"); MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index a5c8d7e121d..5bbf76ec14a 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -553,13 +553,14 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id return ata_pci_init_one(pdev, port_info, ports); } -static struct pci_device_id serverworks[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2}, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2}, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2}, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2}, - { 0, }, +static const struct pci_device_id serverworks[] = { + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2}, + + { }, }; static struct pci_driver serverworks_pci_driver = { @@ -574,13 +575,11 @@ static int __init serverworks_init(void) return pci_register_driver(&serverworks_pci_driver); } - static void __exit serverworks_exit(void) { pci_unregister_driver(&serverworks_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index c8b2e26db70..4a2b72b4be8 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -348,12 +348,13 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } static const struct pci_device_id sil680[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), }, - { 0, }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), }, + + { }, }; static struct pci_driver sil680_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = sil680, .probe = sil680_init_one, .remove = ata_pci_remove_one @@ -364,13 +365,11 @@ static int __init sil680_init(void) return pci_register_driver(&sil680_pci_driver); } - static void __exit sil680_exit(void) { pci_unregister_driver(&sil680_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for SI680 PATA"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 17791e2785f..b9ffafb4198 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -988,8 +988,9 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } static const struct pci_device_id sis_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), }, /* SiS 5513 */ - { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), }, /* SiS 5518 */ + { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */ + { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */ + { } }; @@ -1010,7 +1011,6 @@ static void __exit sis_exit(void) pci_unregister_driver(&sis_pci_driver); } - module_init(sis_init); module_exit(sis_exit); diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 5b762acc568..08a6dc88676 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -351,9 +351,10 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id return ata_pci_init_one(dev, port_info, 1); /* For now */ } -static struct pci_device_id sl82c105[] = { - { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), }, - { 0, }, +static const struct pci_device_id sl82c105[] = { + { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), }, + + { }, }; static struct pci_driver sl82c105_pci_driver = { @@ -368,13 +369,11 @@ static int __init sl82c105_init(void) return pci_register_driver(&sl82c105_pci_driver); } - static void __exit sl82c105_exit(void) { pci_unregister_driver(&sl82c105_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Sl82c105"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index a954ed93a40..9640f80e8b0 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -248,13 +248,13 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) } static const struct pci_device_id triflex[] = { - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, }, + { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), }, + + { }, }; static struct pci_driver triflex_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = triflex, .probe = triflex_init_one, .remove = ata_pci_remove_one @@ -265,13 +265,11 @@ static int __init triflex_init(void) return pci_register_driver(&triflex_pci_driver); } - static void __exit triflex_exit(void) { pci_unregister_driver(&triflex_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Compaq Triflex"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 7b5dd2343b9..1e7be9eee9c 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -529,15 +529,16 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } static const struct pci_device_id via[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1), }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1), }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410), }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), }, - { 0, }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), }, + + { }, }; static struct pci_driver via_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = via, .probe = via_init_one, .remove = ata_pci_remove_one @@ -548,13 +549,11 @@ static int __init via_init(void) return pci_register_driver(&via_pci_driver); } - static void __exit via_exit(void) { pci_unregister_driver(&via_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for VIA PATA"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index c01496df4a9..e6aa1a86d5c 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -533,19 +533,20 @@ static const struct ata_port_info mv_port_info[] = { }; static const struct pci_device_id mv_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x}, - - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x}, - - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x}, - {} /* terminate list */ + { PCI_VDEVICE(MARVELL, 0x5040), chip_504x }, + { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, + { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, + { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, + + { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, + { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, + { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 }, + { PCI_VDEVICE(MARVELL, 0x6080), chip_608x }, + { PCI_VDEVICE(MARVELL, 0x6081), chip_608x }, + + { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, + + { } /* terminate list */ }; static struct pci_driver mv_pci_driver = { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index bbf29595a00..d09d20a1779 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -130,7 +130,8 @@ static const struct pci_device_id nv_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC }, - { 0, } /* terminate list */ + + { } /* terminate list */ }; static struct pci_driver nv_pci_driver = { diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index fa29dfe2a7b..7f6cc3c07de 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -185,8 +185,7 @@ static const struct ata_port_info qs_port_info[] = { }; static const struct pci_device_id qs_ata_pci_tbl[] = { - { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2068_idx }, + { PCI_VDEVICE(PDC, 0x2068), board_2068_idx }, { } /* terminate list */ }; diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 8e8dc3f2215..0738f52463a 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -70,10 +70,10 @@ static const struct pci_device_id sis_pci_tbl[] = { { PCI_VDEVICE(SI, 0x180), sis_180 }, { PCI_VDEVICE(SI, 0x181), sis_180 }, { PCI_VDEVICE(SI, 0x182), sis_180 }, + { } /* terminate list */ }; - static struct pci_driver sis_pci_driver = { .name = DRV_NAME, .id_table = sis_pci_tbl, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index d6d6658d832..84025a2fd5b 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -469,15 +469,15 @@ err_out: * controller * */ static const struct pci_device_id k2_sata_pci_tbl[] = { - { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { PCI_VDEVICE(SERVERWORKS, 0x0240), 4 }, + { PCI_VDEVICE(SERVERWORKS, 0x0241), 4 }, + { PCI_VDEVICE(SERVERWORKS, 0x0242), 8 }, + { PCI_VDEVICE(SERVERWORKS, 0x024a), 4 }, + { PCI_VDEVICE(SERVERWORKS, 0x024b), 4 }, + { } }; - static struct pci_driver k2_sata_pci_driver = { .name = DRV_NAME, .id_table = k2_sata_pci_tbl, @@ -485,19 +485,16 @@ static struct pci_driver k2_sata_pci_driver = { .remove = ata_pci_remove_one, }; - static int __init k2_sata_init(void) { return pci_register_driver(&k2_sata_pci_driver); } - static void __exit k2_sata_exit(void) { pci_unregister_driver(&k2_sata_pci_driver); } - MODULE_AUTHOR("Benjamin Herrenschmidt"); MODULE_DESCRIPTION("low-level driver for K2 SATA controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 2b3d44bf495..8c74f2ff434 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -235,7 +235,6 @@ static const struct pci_device_id pdc_sata_pci_tbl[] = { { } /* terminate list */ }; - static struct pci_driver pdc_sata_pci_driver = { .name = DRV_NAME, .id_table = pdc_sata_pci_tbl, diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index c2e6b7e59f0..5c603ca3a50 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -68,7 +68,6 @@ static const struct pci_device_id uli_pci_tbl[] = { { } /* terminate list */ }; - static struct pci_driver uli_pci_driver = { .name = DRV_NAME, .id_table = uli_pci_tbl, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index a72a2389a11..f4455a1efe2 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -77,9 +77,9 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void vt6420_error_handler(struct ata_port *ap); static const struct pci_device_id svia_pci_tbl[] = { - { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, - { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, - { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 }, + { PCI_VDEVICE(VIA, 0x0591), vt6420 }, + { PCI_VDEVICE(VIA, 0x3149), vt6420 }, + { PCI_VDEVICE(VIA, 0x3249), vt6421 }, { } /* terminate list */ }; diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index d0d92f33de5..273d88fcf98 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -442,16 +442,15 @@ err_out: return rc; } - static const struct pci_device_id vsc_sata_pci_tbl[] = { { PCI_VENDOR_ID_VITESSE, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, { PCI_VENDOR_ID_INTEL, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { } /* terminate list */ }; - static struct pci_driver vsc_sata_pci_driver = { .name = DRV_NAME, .id_table = vsc_sata_pci_tbl, @@ -459,19 +458,16 @@ static struct pci_driver vsc_sata_pci_driver = { .remove = ata_pci_remove_one, }; - static int __init vsc_sata_init(void) { return pci_register_driver(&vsc_sata_pci_driver); } - static void __exit vsc_sata_exit(void) { pci_unregister_driver(&vsc_sata_pci_driver); } - MODULE_AUTHOR("Jeremy Higdon"); MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller"); MODULE_LICENSE("GPL"); -- GitLab From 4f931374ecc599f6df7852509b6917abd5377205 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 29 Sep 2006 05:07:25 -0400 Subject: [PATCH 0317/1619] [libata] DocBook minor updates, fixes Update copyright year, fix minor stuff 'make xmldocs' complains about. Signed-off-by: Jeff Garzik --- Documentation/DocBook/libata.tmpl | 2 +- drivers/ata/libata-core.c | 2 +- drivers/ata/libata-scsi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl index 065e8dc23e3..f9a7c064aec 100644 --- a/Documentation/DocBook/libata.tmpl +++ b/Documentation/DocBook/libata.tmpl @@ -14,7 +14,7 @@ - 2003-2005 + 2003-2006 Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7ab45f42ae7..dce65651d85 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5741,7 +5741,7 @@ void ata_host_remove(struct ata_host *host) /** * ata_scsi_release - SCSI layer callback hook for host unload - * @host: libata host to be unloaded + * @shost: libata host to be unloaded * * Performs all duties necessary to shut down a libata port... * Kill port kthread, disable port, and release resources. diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3986ec8741b..b4a0246506e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3174,7 +3174,7 @@ void ata_scsi_dev_rescan(void *data) /** * ata_sas_port_alloc - Allocate port for a SAS attached SATA device - * @pdev: PCI device that the scsi device is attached to + * @host: ATA host container for all SAS ports * @port_info: Information from low-level host driver * @shost: SCSI host that the scsi device is attached to * -- GitLab From 25ee4a98c662317a7973f3053567d4ec51857511 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 00:54:23 +0000 Subject: [PATCH 0318/1619] [CIFS] Handle legacy servers which return undefined time zone Signed-off-by: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index dcd7087a1ae..99718591ea2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -447,6 +447,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if((pSMBr->hdr.WordCount == 13) && (pSMBr->DialectIndex == LANMAN_PROT)) { + int tmp, adjust; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; if((secFlags & CIFSSEC_MAY_LANMAN) || @@ -473,11 +474,36 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->capabilities = CAP_MPX_MODE; } server->timeZone = le16_to_cpu(rsp->ServerTimeZone); + tmp = le16_to_cpu(rsp->ServerTimeZone); + if (tmp == (int)0xffff) { + /* OS/2 often does not set timezone therefore + * we must use server time to calc time zone. + * Could deviate slightly from the right zone. Not easy + * to adjust, since timezones are not always a multiple + * of 60 (sometimes 30 minutes - are there smaller?) + */ + struct timespec ts, utc; + utc = CURRENT_TIME; + ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date), + le16_to_cpu(rsp->SrvTime.Time)); + cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d", + (int)ts.tv_sec, (int)utc.tv_sec, + (int)(utc.tv_sec - ts.tv_sec))); + tmp = (int)(utc.tv_sec - ts.tv_sec); + adjust = tmp < 0 ? -29 : 29; + tmp = ((tmp + adjust) / 60) * 60; + server->timeZone = tmp; + } else { + server->timeZone = tmp * 60; /* also in seconds */ + } + cFYI(1,("server->timeZone: %d seconds", server->timeZone)); + /* BB get server time for time conversions and add code to use it and timezone since this is not UTC */ - if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { + if (rsp->EncryptionKeyLength == + cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { memcpy(server->cryptKey, rsp->EncryptionKey, CIFS_CRYPTO_KEY_SIZE); } else if (server->secMode & SECMODE_PW_ENCRYPT) { -- GitLab From 175ec9e11cf18f8373b32f7a33e75a4cf7ce25e3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 01:07:38 +0000 Subject: [PATCH 0319/1619] [CIFS] Rename server time zone field Server time zone is not really a time zone, rather a time adjustement in seconds. CC: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 5 ++++- fs/cifs/cifssmb.c | 9 ++++----- fs/cifs/connect.c | 9 +++++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7ecfcbf31e5..e7641f9a13b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -465,7 +465,7 @@ static struct super_operations cifs_super_ops = { .umount_begin = cifs_umount_begin, .remount_fs = cifs_remount, #ifdef CONFIG_CIFS_STATS2 - cifs_show_stats, + .cifs_show_stats, #endif }; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 441f8d2514f..98eb5446e8c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -153,7 +153,7 @@ struct TCP_Server_Info { char sessid[4]; /* unique token id for this session */ /* (returned on Negotiate */ int capabilities; /* allow selective disabling of caps by smb sess */ - __u16 timeZone; + __u16 timeAdj; /* Adjust for difference in server time zone in sec */ __u16 CurrentMid; /* multiplex id - rotating counter */ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; /* 16th byte of RFC1001 workstation name is always null */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 81df2bf8e75..e5dd8708d63 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -417,7 +417,10 @@ typedef struct lanman_neg_rsp { __le16 MaxNumberVcs; __le16 RawMode; __le32 SessionKey; - __le32 ServerTime; + struct { + __le16 Time; + __le16 Date; + } __attribute__((packed)) SrvTime; __le16 ServerTimeZone; __le16 EncryptionKeyLength; __le16 Reserved; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 99718591ea2..6e004587fa4 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -473,7 +473,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->maxRw = 0;/* we do not need to use raw anyway */ server->capabilities = CAP_MPX_MODE; } - server->timeZone = le16_to_cpu(rsp->ServerTimeZone); tmp = le16_to_cpu(rsp->ServerTimeZone); if (tmp == (int)0xffff) { /* OS/2 often does not set timezone therefore @@ -492,11 +491,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) tmp = (int)(utc.tv_sec - ts.tv_sec); adjust = tmp < 0 ? -29 : 29; tmp = ((tmp + adjust) / 60) * 60; - server->timeZone = tmp; + server->timeAdj = tmp; } else { - server->timeZone = tmp * 60; /* also in seconds */ + server->timeAdj = tmp * 60; /* also in seconds */ } - cFYI(1,("server->timeZone: %d seconds", server->timeZone)); + cFYI(1,("server->timeAdj: %d seconds", server->timeAdj)); /* BB get server time for time conversions and add @@ -557,7 +556,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(0, ("Max buf = %d", ses->server->maxBuf)); GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); server->capabilities = le32_to_cpu(pSMBr->Capabilities); - server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); + server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60; if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { memcpy(server->cryptKey, pSMBr->u.EncryptionKey, CIFS_CRYPTO_KEY_SIZE); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b3268e53ab9..083b2b2c157 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3320,15 +3320,16 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, if(linuxExtEnabled == 0) pSesInfo->capabilities &= (~CAP_UNIX); /* pSesInfo->sequence_number = 0;*/ - cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", + cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", pSesInfo->server->secMode, pSesInfo->server->capabilities, - pSesInfo->server->timeZone)); + pSesInfo->server->timeAdj)); if(experimEnabled < 2) rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); else if (extended_security - && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->capabilities + & CAP_EXTENDED_SECURITY) && (pSesInfo->server->secType == NTLMSSP)) { rc = -EOPNOTSUPP; } else if (extended_security @@ -3342,7 +3343,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, if (!rc) { if(ntlmv2_flag) { char * v2_response; - cFYI(1,("Can use more secure NTLM version 2 password hash")); + cFYI(1,("more secure NTLM ver2 hash")); if(CalcNTLMv2_partial_mac_key(pSesInfo, nls_info)) { rc = -ENOMEM; -- GitLab From f46d3e11903e452924ef2996aa9aca2aae4427e2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 01:08:55 +0000 Subject: [PATCH 0320/1619] [CIFS] Fix typo in name of new cifs_show_stats Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e7641f9a13b..ca53720fa5b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -465,7 +465,7 @@ static struct super_operations cifs_super_ops = { .umount_begin = cifs_umount_begin, .remount_fs = cifs_remount, #ifdef CONFIG_CIFS_STATS2 - .cifs_show_stats, + .show_stats = cifs_show_stats, #endif }; -- GitLab From 9ac00b7d96045fa3ce573e0ad5cdc0350ad8e1d2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 04:13:17 +0000 Subject: [PATCH 0321/1619] [CIFS] Do not send newer QFSInfo to legacy servers which can not support it Fix dialect negotiation to save off when we have negotiated lanman. This allows us to avoid sending some somewhat newer requests that the server can not handle and go directly to the older version (infolevel) of the same call. Make sure we try to negotiate a level which allows us to get the server OS (which we check so we can detect Win9x vs. other legacy servers and eventually work around the Win9x DOS time bug (they reverse date/time fields). Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 8 +++++--- fs/cifs/cifsglob.h | 9 +++++++-- fs/cifs/cifspdu.h | 3 ++- fs/cifs/cifssmb.c | 8 +++++--- fs/cifs/connect.c | 1 + fs/cifs/sess.c | 23 ++++++++++++----------- 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ca53720fa5b..d6d226addde 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -199,10 +199,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) /* Only need to call the old QFSInfo if failed on newer one */ if(rc) - rc = CIFSSMBQFSInfo(xid, pTcon, buf); + if((pTcon->ses->flags & CIFS_SES_LANMAN) == 0) + rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ - /* Old Windows servers do not support level 103, retry with level - one if old server failed the previous call */ + /* Some old Windows servers also do not support level 103, retry with + older level one if old server failed the previous call or we + bypassed it because we detected that this was an older LANMAN sess */ if(rc) rc = SMBOldQFSInfo(xid, pTcon, buf); /* diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 98eb5446e8c..597afdf4c69 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -203,9 +203,14 @@ struct cifsSesInfo { char * domainName; char * password; }; -/* session flags */ +/* no more than one of the following three session flags may be set */ #define CIFS_SES_NT4 1 - +#define CIFS_SES_OS2 2 +#define CIFS_SES_W9X 4 +/* following flag is set for old servers such as OS2 (and Win95?) + which do not negotiate NTLM or POSIX dialects, but instead + negotiate one of the older LANMAN dialects */ +#define CIFS_SES_LANMAN 8 /* * there is one of these for each connection to a resource on a particular * session diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e5dd8708d63..50505422dbb 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -26,7 +26,8 @@ #ifdef CONFIG_CIFS_WEAK_PW_HASH #define LANMAN_PROT 0 -#define CIFS_PROT 1 +#define LANMAN2_PROT 1 +#define CIFS_PROT 2 #else #define CIFS_PROT 0 #endif diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6e004587fa4..f2fa05bbcb4 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -46,6 +46,7 @@ static struct { } protocols[] = { #ifdef CONFIG_CIFS_WEAK_PW_HASH {LANMAN_PROT, "\2LM1.2X002"}, + {LANMAN2_PROT, "\2LANMAN2.1"}, #endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {POSIX_PROT, "\2POSIX 2"}, @@ -67,13 +68,13 @@ static struct { /* define the number of elements in the cifs dialect array */ #ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 3 +#define CIFS_NUM_PROT 4 #else #define CIFS_NUM_PROT 2 #endif /* CIFS_WEAK_PW_HASH */ #else /* not posix */ #ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 2 +#define CIFS_NUM_PROT 3 #else #define CIFS_NUM_PROT 1 #endif /* CONFIG_CIFS_WEAK_PW_HASH */ @@ -446,7 +447,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if((pSMBr->hdr.WordCount == 13) - && (pSMBr->DialectIndex == LANMAN_PROT)) { + && ((pSMBr->DialectIndex == LANMAN_PROT) + || (pSMBr->DialectIndex == LANMAN2_PROT))) { int tmp, adjust; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 083b2b2c157..c96f3edf1b9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3316,6 +3316,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, first_time = 1; } if (!rc) { + pSesInfo->flags = 0; pSesInfo->capabilities = pSesInfo->server->capabilities; if(linuxExtEnabled == 0) pSesInfo->capabilities &= (~CAP_UNIX); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d1705ab8136..e4c4e466e32 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -268,6 +268,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if(ses->serverOS) strncpy(ses->serverOS, bcc_ptr, len); + if(strncmp(ses->serverOS, "OS/2",4) == 0) { + cFYI(1,("OS/2 server")); + ses->flags |= CIFS_SES_OS2; + } bcc_ptr += len + 1; bleft -= len + 1; @@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo if(len > bleft) return rc; - if(ses->serverDomain) - kfree(ses->serverDomain); - - ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); - if(ses->serverOS) - strncpy(ses->serverOS, bcc_ptr, len); - - bcc_ptr += len + 1; - bleft -= len + 1; - + /* No domain field in LANMAN case. Domain is + returned by old servers in the SMB negprot response */ + /* BB For newer servers which do not support Unicode, + but thus do return domain here we could add parsing + for it later, but it is not very important */ cFYI(1,("ascii: bytes left %d",bleft)); return rc; @@ -366,6 +365,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, str_area = kmalloc(2000, GFP_KERNEL); bcc_ptr = str_area; + ses->flags &= ~CIFS_SES_LANMAN; + if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH char lnm_session_key[CIFS_SESS_KEY_SIZE]; @@ -377,7 +378,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* and copy into bcc */ calc_lanman_hash(ses, lnm_session_key); - + ses->flags |= CIFS_SES_LANMAN; /* #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, CIFS_SESS_KEY_SIZE); -- GitLab From e5c9e081e9c980fa785cd9002c25a251cf3f090e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Sep 2006 19:44:39 +0900 Subject: [PATCH 0322/1619] [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(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index df44b09fbae..e54a5fd6a41 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), -- GitLab From 360f654e7cda850034f3f6252a7a7cff3fa77356 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Sep 2006 19:45:00 +0900 Subject: [PATCH 0323/1619] [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(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b4a0246506e..b0d0cc41f3e 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 e54a5fd6a41..d1af1dbeaeb 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, -- GitLab From de7ed55dbb2f2c44be669d56c4adf28cbffb26ce Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 13:25:52 +0000 Subject: [PATCH 0324/1619] [CIFS] Make use of newer QFSInfo dependent on capability bit instead of whether we negotiated legacy lanman dialect so we do not keep retrying for mount to WindowsME Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsglob.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d6d226addde..43364361276 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -199,7 +199,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) /* Only need to call the old QFSInfo if failed on newer one */ if(rc) - if((pTcon->ses->flags & CIFS_SES_LANMAN) == 0) + if(pTcon->ses->capabilities & CAP_NT_SMBS) rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ /* Some old Windows servers also do not support level 103, retry with diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 597afdf4c69..74d3ccbb103 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -153,7 +153,7 @@ struct TCP_Server_Info { char sessid[4]; /* unique token id for this session */ /* (returned on Negotiate */ int capabilities; /* allow selective disabling of caps by smb sess */ - __u16 timeAdj; /* Adjust for difference in server time zone in sec */ + int timeAdj; /* Adjust for difference in server time zone in sec */ __u16 CurrentMid; /* multiplex id - rotating counter */ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; /* 16th byte of RFC1001 workstation name is always null */ -- GitLab From 18f75ca0dc0d5b6a2ec15d89d517b3c67e0f1c87 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 1 Oct 2006 03:13:01 +0000 Subject: [PATCH 0325/1619] [CIFS] Allow LANMAN21 support even in both POSIX non-POSIX path Signed-off-by: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f2fa05bbcb4..75f060328e2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -59,6 +59,7 @@ static struct { } protocols[] = { #ifdef CONFIG_CIFS_WEAK_PW_HASH {LANMAN_PROT, "\2LM1.2X002"}, + {LANMAN2_PROT, "\2LANMAN2.1"}, #endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {BAD_PROT, "\2"} -- GitLab From 15a7c3bbe344d75e4891c7d30595899c12ccfaa1 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 1 Oct 2006 10:38:22 -0400 Subject: [PATCH 0326/1619] [libata] pata_artop: kill gcc warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc complains thusly: drivers/ata/pata_artop.c: In function ‘artop_init_one’: drivers/ata/pata_artop.c:429: warning: ‘info’ may be used uninitialized in this function While this warning is indeed bogus, even with improved static analysis and value range propagation, gcc will probably never be able to detect this. Add a BUG_ON() to trap invalid driver_data entries in the PCI table. Signed-off-by: Jeff Garzik --- drivers/ata/pata_artop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 49565ef945f..690828eb522 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -426,7 +426,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &artop6260_ops, }; struct ata_port_info *port_info[2]; - struct ata_port_info *info; + struct ata_port_info *info = NULL; int ports = 2; if (!printed_version++) @@ -470,6 +470,9 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80); } + + BUG_ON(info == NULL); + port_info[0] = port_info[1] = info; return ata_pci_init_one(pdev, port_info, ports); } -- GitLab From 02a0fa676cd453ce4254c2eee838307ffc5c37f4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 25 Sep 2006 23:45:51 +0100 Subject: [PATCH 0327/1619] [SCSI] Switch ips to pci_register from pci_module Signed-off-by: Alan Cox Signed-off-by: James Bottomley --- drivers/scsi/ips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 3c639286ec1..58065ff6936 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -7078,7 +7078,7 @@ ips_remove_device(struct pci_dev *pci_dev) static int __init ips_module_init(void) { - if (pci_module_init(&ips_pci_driver) < 0) + if (pci_register_driver(&ips_pci_driver) < 0) return -ENODEV; ips_driver_template.module = THIS_MODULE; ips_order_controllers(); -- GitLab From 203cf2fc13a5db1fb202c294948fa9cb43bf69fa Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 1 Oct 2006 19:59:41 +0000 Subject: [PATCH 0328/1619] [CIFS] Fix readdir of large directories for backlevel servers (were not setting all of resume key) Signed-off-by: Steve French --- fs/cifs/readdir.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 71e86c38e63..b0e5db10664 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -946,6 +946,7 @@ static int cifs_save_resume_key(const char *current_entry, filename = &pFindData->FileName[0]; /* one byte length, no name conversion */ len = (unsigned int)pFindData->FileNameLength; + cifsFile->srch_inf.resume_key = pFindData->ResumeKey; } else { cFYI(1,("Unknown findfirst level %d",level)); return -EINVAL; -- GitLab From 7b75b990e3cb33fd529640d589e77950e72a607c Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 25 Sep 2006 16:57:42 -0700 Subject: [PATCH 0329/1619] [SCSI] aic7xxx: fix byte I/O order in ahd_inw Comment says "Read high byte first as some registers increment..." but code doesn't guarantee that, I think: return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); Compiler can reorder it. Make the order explicit. Signed-off-by: Denis Vlasenko Signed-off-by: Andrew Morton Fixed rejections and added aic7xxx code Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_inline.h | 3 ++- drivers/scsi/aic7xxx/aic7xxx_inline.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h index 8ad3ce945b9..a3266e066c0 100644 --- a/drivers/scsi/aic7xxx/aic79xx_inline.h +++ b/drivers/scsi/aic7xxx/aic79xx_inline.h @@ -527,7 +527,8 @@ ahd_inw(struct ahd_softc *ahd, u_int port) * or have other side effects when the low byte is * read. */ - return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); + uint16_t r = ahd_inb(ahd, port+1) << 8; + return r | ahd_inb(ahd, port); } static __inline void diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h index 2cc8a17ed8b..8e1954cdd84 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_inline.h +++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h @@ -300,7 +300,8 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, static __inline uint16_t ahc_inw(struct ahc_softc *ahc, u_int port) { - return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port)); + uint16_t r = ahc_inb(ahc, port+1) << 8; + return r | ahc_inb(ahc, port); } static __inline void -- GitLab From 80c6e3c0b5eb855b69270658318f5ccf04d7b1ff Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Tue, 26 Sep 2006 13:22:13 +0200 Subject: [PATCH 0330/1619] [SCSI] fix scsi_device_types overrun in scsi.c this overrun was spotted by coverity (cid #1403). If type == ARRAY_SIZE(scsi_device_types), we are off by one. Signed-off-by: Eric Sesterhenn Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 7a054f9d1ee..a21642e32c4 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -128,7 +128,7 @@ const char * scsi_device_type(unsigned type) return "Well-known LUN "; if (type == 0x1f) return "No Device "; - if (type > ARRAY_SIZE(scsi_device_types)) + if (type >= ARRAY_SIZE(scsi_device_types)) return "Unknown "; return scsi_device_types[type]; } -- GitLab From f903d7b7a80b7c3103335d506533790a322da87b Mon Sep 17 00:00:00 2001 From: Ed Lin Date: Wed, 27 Sep 2006 19:23:33 +0800 Subject: [PATCH 0331/1619] [SCSI] stex: cancel unused field in struct req_msg The payload_sz field in struct req_msg is not big enough to indicate the size of req_msg, as its type is u8. It is confirmed that this field is not used by firmware, so cancel it here. Signed-off-by: Ed Lin Signed-off-by: James Bottomley --- drivers/scsi/stex.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 3cf3106a29b..cfb29716b5e 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -181,7 +181,7 @@ struct req_msg { u8 task_attr; u8 task_manage; u8 prd_entry; - u8 payload_sz; /* payload size in 4-byte */ + u8 payload_sz; /* payload size in 4-byte, not used */ u8 cdb[STEX_CDB_LENGTH]; u8 variable[REQ_VARIABLE_LEN]; }; @@ -489,7 +489,6 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) req->tag = cpu_to_le16(tag); req->task_attr = TASK_ATTRIBUTE_SIMPLE; req->task_manage = 0; /* not supported yet */ - req->payload_sz = (u8)(sizeof(struct req_msg)/sizeof(u32)); hba->ccb[tag].req = req; hba->out_req_cnt++; -- GitLab From fb4f66be59f3dcc66fda2e681f1fc77b5cc4508d Mon Sep 17 00:00:00 2001 From: Ed Lin Date: Wed, 27 Sep 2006 19:23:41 +0800 Subject: [PATCH 0332/1619] [SCSI] stex: add new device (id 0x8650) support A new device (id 0x8650, nickname 'yosemite') support is added. It's basically the same, except for following items: - mapping of id and lun by firmware - special handling for some commands in interrupt routine - change of internal copy function for these special commands - different reset handling code - different shutdown notification command Signed-off-by: Ed Lin Signed-off-by: James Bottomley --- drivers/scsi/stex.c | 194 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index cfb29716b5e..a54e6c1026b 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -11,7 +11,7 @@ * Written By: * Ed Lin * - * Version: 2.9.0.13 + * Version: 3.0.0.1 * */ @@ -37,11 +37,11 @@ #include #define DRV_NAME "stex" -#define ST_DRIVER_VERSION "2.9.0.13" -#define ST_VER_MAJOR 2 -#define ST_VER_MINOR 9 +#define ST_DRIVER_VERSION "3.0.0.1" +#define ST_VER_MAJOR 3 +#define ST_VER_MINOR 0 #define ST_OEM 0 -#define ST_BUILD_VER 13 +#define ST_BUILD_VER 1 enum { /* MU register offset */ @@ -120,12 +120,18 @@ enum { st_shasta = 0, st_vsc = 1, + st_yosemite = 2, PASSTHRU_REQ_TYPE = 0x00000001, PASSTHRU_REQ_NO_WAKEUP = 0x00000100, ST_INTERNAL_TIMEOUT = 30, + ST_TO_CMD = 0, + ST_FROM_CMD = 1, + /* vendor specific commands of Promise */ + MGT_CMD = 0xd8, + SINBAND_MGT_CMD = 0xd9, ARRAY_CMD = 0xe0, CONTROLLER_CMD = 0xe1, DEBUGGING_CMD = 0xe2, @@ -133,14 +139,48 @@ enum { PASSTHRU_GET_ADAPTER = 0x05, PASSTHRU_GET_DRVVER = 0x10, + + CTLR_CONFIG_CMD = 0x03, + CTLR_SHUTDOWN = 0x0d, + CTLR_POWER_STATE_CHANGE = 0x0e, CTLR_POWER_SAVING = 0x01, PASSTHRU_SIGNATURE = 0x4e415041, + MGT_CMD_SIGNATURE = 0xba, INQUIRY_EVPD = 0x01, }; +/* SCSI inquiry data */ +typedef struct st_inq { + u8 DeviceType :5; + u8 DeviceTypeQualifier :3; + u8 DeviceTypeModifier :7; + u8 RemovableMedia :1; + u8 Versions; + u8 ResponseDataFormat :4; + u8 HiSupport :1; + u8 NormACA :1; + u8 ReservedBit :1; + u8 AERC :1; + u8 AdditionalLength; + u8 Reserved[2]; + u8 SoftReset :1; + u8 CommandQueue :1; + u8 Reserved2 :1; + u8 LinkedCommands :1; + u8 Synchronous :1; + u8 Wide16Bit :1; + u8 Wide32Bit :1; + u8 RelativeAddressing :1; + u8 VendorId[8]; + u8 ProductId[16]; + u8 ProductRevisionLevel[4]; + u8 VendorSpecific[20]; + u8 Reserved3[40]; +} ST_INQ; + struct st_sgitem { u8 ctrl; /* SG_CF_xxx */ u8 reserved[3]; @@ -242,7 +282,8 @@ struct st_drvver { #define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg)) #define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg)) #define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE) -#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + sizeof(struct st_frame)) +#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ)) +#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE) struct st_ccb { struct req_msg *req; @@ -403,7 +444,7 @@ static int stex_map_sg(struct st_hba *hba, } static void stex_internal_copy(struct scsi_cmnd *cmd, - const void *src, size_t *count, int sg_count) + const void *src, size_t *count, int sg_count, int direction) { size_t lcount; size_t len; @@ -427,7 +468,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd, } else d = cmd->request_buffer; - memcpy(d, s, len); + if (direction == ST_TO_CMD) + memcpy(d, s, len); + else + memcpy(s, d, len); lcount -= len; if (cmd->use_sg) @@ -449,7 +493,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd, return 0; } - stex_internal_copy(cmd, src, &cp_len, n_elem); + stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD); if (cmd->use_sg) pci_unmap_sg(hba->pdev, cmd->request_buffer, @@ -480,7 +524,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) p->subid = hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; - stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count); + stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD); } static void @@ -594,8 +638,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) return SCSI_MLQUEUE_HOST_BUSY; req = stex_alloc_req(hba); - req->lun = lun; - req->target = id; + + if (hba->cardtype == st_yosemite) { + req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id; + req->target = 0; + } else { + req->lun = lun; + req->target = id; + } /* cdb */ memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); @@ -679,7 +729,51 @@ static void stex_copy_data(struct st_ccb *ccb, if (ccb->cmd == NULL) return; - stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count); + stex_internal_copy(ccb->cmd, + resp->variable, &count, ccb->sg_count, ST_TO_CMD); +} + +static void stex_ys_commands(struct st_hba *hba, + struct st_ccb *ccb, struct status_msg *resp) +{ + size_t count; + + if (ccb->cmd->cmnd[0] == MGT_CMD && + resp->scsi_status != SAM_STAT_CHECK_CONDITION) { + ccb->cmd->request_bufflen = + le32_to_cpu(*(__le32 *)&resp->variable[0]); + return; + } + + if (resp->srb_status != 0) + return; + + /* determine inquiry command status by DeviceTypeQualifier */ + if (ccb->cmd->cmnd[0] == INQUIRY && + resp->scsi_status == SAM_STAT_GOOD) { + ST_INQ *inq_data; + + count = STEX_EXTRA_SIZE; + stex_internal_copy(ccb->cmd, hba->copy_buffer, + &count, ccb->sg_count, ST_FROM_CMD); + inq_data = (ST_INQ *)hba->copy_buffer; + if (inq_data->DeviceTypeQualifier != 0) + ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT; + else + ccb->srb_status = SRB_STATUS_SUCCESS; + } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) { + u8 *report_lun_data = (u8 *)hba->copy_buffer; + + count = STEX_EXTRA_SIZE; + stex_internal_copy(ccb->cmd, report_lun_data, + &count, ccb->sg_count, ST_FROM_CMD); + if (report_lun_data[2] || report_lun_data[3]) { + report_lun_data[2] = 0x00; + report_lun_data[3] = 0x08; + stex_internal_copy(ccb->cmd, report_lun_data, + &count, ccb->sg_count, ST_TO_CMD); + } + } } static void stex_mu_intr(struct st_hba *hba, u32 doorbell) @@ -701,8 +795,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) return; } - if (unlikely(hba->mu_status != MU_STATE_STARTED || - hba->out_req_cnt <= 0)) { + /* + * it's not a valid status payload if: + * 1. there are no pending requests(e.g. during init stage) + * 2. there are some pending requests, but the controller is in + * reset status, and its type is not st_yosemite + * firmware of st_yosemite in reset status will return pending requests + * to driver, so we allow it to pass + */ + if (unlikely(hba->out_req_cnt <= 0 || + (hba->mu_status == MU_STATE_RESETTING && + hba->cardtype != st_yosemite))) { hba->status_tail = hba->status_head; goto update_status; } @@ -722,6 +825,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) if (unlikely(ccb->req == NULL)) { printk(KERN_WARNING DRV_NAME "(%s): lagging req\n", pci_name(hba->pdev)); + hba->out_req_cnt--; continue; } @@ -740,9 +844,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) ccb->scsi_status = resp->scsi_status; if (likely(ccb->cmd != NULL)) { + if (hba->cardtype == st_yosemite) + stex_ys_commands(hba, ccb, resp); + if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) stex_controller_info(hba, ccb); + stex_unmap_sg(hba, ccb->cmd); stex_scsi_done(ccb); hba->out_req_cnt--; @@ -947,6 +1055,7 @@ static int stex_reset(struct scsi_cmnd *cmd) { struct st_hba *hba; unsigned long flags; + unsigned long before; hba = (struct st_hba *) &cmd->device->host->hostdata[0]; hba->mu_status = MU_STATE_RESETTING; @@ -954,20 +1063,37 @@ static int stex_reset(struct scsi_cmnd *cmd) if (hba->cardtype == st_shasta) stex_hard_reset(hba); - if (stex_handshake(hba)) { - printk(KERN_WARNING DRV_NAME - "(%s): resetting: handshake failed\n", - pci_name(hba->pdev)); - return FAILED; + if (hba->cardtype != st_yosemite) { + if (stex_handshake(hba)) { + printk(KERN_WARNING DRV_NAME + "(%s): resetting: handshake failed\n", + pci_name(hba->pdev)); + return FAILED; + } + spin_lock_irqsave(hba->host->host_lock, flags); + hba->req_head = 0; + hba->req_tail = 0; + hba->status_head = 0; + hba->status_tail = 0; + hba->out_req_cnt = 0; + spin_unlock_irqrestore(hba->host->host_lock, flags); + return SUCCESS; } - spin_lock_irqsave(hba->host->host_lock, flags); - hba->req_head = 0; - hba->req_tail = 0; - hba->status_head = 0; - hba->status_tail = 0; - hba->out_req_cnt = 0; - spin_unlock_irqrestore(hba->host->host_lock, flags); + /* st_yosemite */ + writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL); + readl(hba->mmio_base + IDBL); /* flush */ + before = jiffies; + while (hba->out_req_cnt > 0) { + if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { + printk(KERN_WARNING DRV_NAME + "(%s): reset timeout\n", pci_name(hba->pdev)); + return FAILED; + } + msleep(1); + } + + hba->mu_status = MU_STATE_STARTED; return SUCCESS; } @@ -1155,9 +1281,16 @@ static void stex_hba_stop(struct st_hba *hba) req = stex_alloc_req(hba); memset(req->cdb, 0, STEX_CDB_LENGTH); - req->cdb[0] = CONTROLLER_CMD; - req->cdb[1] = CTLR_POWER_STATE_CHANGE; - req->cdb[2] = CTLR_POWER_SAVING; + if (hba->cardtype == st_yosemite) { + req->cdb[0] = MGT_CMD; + req->cdb[1] = MGT_CMD_SIGNATURE; + req->cdb[2] = CTLR_CONFIG_CMD; + req->cdb[3] = CTLR_SHUTDOWN; + } else { + req->cdb[0] = CONTROLLER_CMD; + req->cdb[1] = CTLR_POWER_STATE_CHANGE; + req->cdb[2] = CTLR_POWER_SAVING; + } hba->ccb[tag].cmd = NULL; hba->ccb[tag].sg_count = 0; @@ -1221,6 +1354,7 @@ static struct pci_device_id stex_pci_tbl[] = { { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, + { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite }, { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, stex_pci_tbl); -- GitLab From 6470f2ba641cf93d357854cdc63a65350352bb97 Mon Sep 17 00:00:00 2001 From: Arne Redlich Date: Sat, 30 Sep 2006 15:49:40 +0200 Subject: [PATCH 0333/1619] [SCSI] trivial scsi_execute_async fix In scsi_execute_async()'s error path, a struct scsi_io_context allocated with kmem_cache_alloc() is kfree()'d. Obviously kmem_cache_free() should be used instead. Signed-off-by: Arne Redlich Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d6743b959a7..8ada93ae34f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -424,7 +424,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, free_req: blk_put_request(req); free_sense: - kfree(sioc); + kmem_cache_free(scsi_io_context_cache, sioc); return DRIVER_ERROR << 24; } EXPORT_SYMBOL_GPL(scsi_execute_async); -- GitLab From 3441afc672bc9bfc137ae7717ac1db4b9c28cc8b Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 30 Sep 2006 20:42:28 -0400 Subject: [PATCH 0334/1619] [SCSI] scsi_devinfo: add EMC Invista This is from RHEL4. This box can support scsi2 and can also support BLIST_SPARSELUN | BLIST_LARGELUN. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 3d0429bc14a..cbf733b4e8a 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -150,6 +150,7 @@ static struct { {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ + {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, -- GitLab From 5f619c5ba509994c9203bfd18f5246b4457e2c22 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 30 Sep 2006 20:42:29 -0400 Subject: [PATCH 0335/1619] [SCSI] scsi_devinfo: add Tornado This is from RHEL4. I do not have any info from our bugzilla. All I could find was something like this thread http://lkml.org/lkml/2005/1/7/346 Report lun for linux does not work. It may be our lun format code or it may be the device. It is probably not worth it to add anything special for this device, so the patch just adds BLIST_NOREPORTLUN. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index cbf733b4e8a..f6aadbd9b95 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -211,6 +211,7 @@ static struct { {"SUN", "T300", "*", BLIST_SPARSELUN}, {"SUN", "T4", "*", BLIST_SPARSELUN}, {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, + {"Tornado-", "F4", "*", BLIST_NOREPORTLUN}, {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36}, -- GitLab From 12427d99489966185dc12a0b6f725d682a3277ca Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 30 Sep 2006 20:42:30 -0400 Subject: [PATCH 0336/1619] [SCSI] scsi_devinfo: add nec iStorage support the report luns opcode . Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index f6aadbd9b95..dc1e1eb8c52 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -189,6 +189,7 @@ static struct { {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NEC", "iStorage", NULL, BLIST_REPORTLUN2}, {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, -- GitLab From f70cfa9bef432d7aeb4e35c093ac27fd6f071d7e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 30 Sep 2006 20:42:31 -0400 Subject: [PATCH 0337/1619] [SCSI] scsi_devinfo: scsi2 HP and Hitachi entries When SCSI-2 they can support luns past 7 and sparse luns. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index dc1e1eb8c52..ce63044b1ec 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -162,6 +162,11 @@ static struct { {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, @@ -169,6 +174,14 @@ static struct { {"HP", "C1557A", NULL, BLIST_FORCELUN}, {"HP", "C3323-300", "4269", BLIST_NOTQ}, {"HP", "C5713A", NULL, BLIST_NOREPORTLUN}, + {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, -- GitLab From b815f1e559e7cbdf3e561cf0c7cffc4a4a57a013 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 2 Oct 2006 05:53:29 +0000 Subject: [PATCH 0338/1619] [CIFS] Allow for 15 minute TZs (e.g. Nepal) and be more explicit about not setting time on close Signed-off-by: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 4 +++- fs/cifs/cifssmb.c | 35 ++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 50505422dbb..6df9dadba64 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -409,6 +409,8 @@ typedef struct negotiate_req { /* Dialect index is 13 for LANMAN */ +#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ + typedef struct lanman_neg_rsp { struct smb_hdr hdr; /* wct = 13 */ __le16 DialectIndex; @@ -678,7 +680,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on typedef struct smb_com_close_req { struct smb_hdr hdr; /* wct = 3 */ __u16 FileID; - __u32 LastWriteTime; /* should be zero */ + __u32 LastWriteTime; /* should be zero or -1 */ __u16 ByteCount; /* 0 */ } __attribute__((packed)) CLOSE_REQ; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 75f060328e2..8d30a5c4f24 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -450,7 +450,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } else if((pSMBr->hdr.WordCount == 13) && ((pSMBr->DialectIndex == LANMAN_PROT) || (pSMBr->DialectIndex == LANMAN2_PROT))) { - int tmp, adjust; + __s16 tmp; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; if((secFlags & CIFSSEC_MAY_LANMAN) || @@ -476,14 +476,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->maxRw = 0;/* we do not need to use raw anyway */ server->capabilities = CAP_MPX_MODE; } - tmp = le16_to_cpu(rsp->ServerTimeZone); - if (tmp == (int)0xffff) { + tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); + if (tmp == 0xffff) { /* OS/2 often does not set timezone therefore * we must use server time to calc time zone. - * Could deviate slightly from the right zone. Not easy - * to adjust, since timezones are not always a multiple - * of 60 (sometimes 30 minutes - are there smaller?) + * Could deviate slightly from the right zone. + * Smallest defined timezone difference is 15 minutes + * (i.e. Nepal). Rounding up/down is done to match + * this requirement. */ + int val, seconds, remain, result; struct timespec ts, utc; utc = CURRENT_TIME; ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date), @@ -491,12 +493,18 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d", (int)ts.tv_sec, (int)utc.tv_sec, (int)(utc.tv_sec - ts.tv_sec))); - tmp = (int)(utc.tv_sec - ts.tv_sec); - adjust = tmp < 0 ? -29 : 29; - tmp = ((tmp + adjust) / 60) * 60; - server->timeAdj = tmp; + val = (int)(utc.tv_sec - ts.tv_sec); + seconds = val < 0 ? -val : val; + result = (seconds / IN_TZ_ADJ) * MIN_TZ_ADJ; + remain = seconds % MIN_TZ_ADJ; + if(remain >= (MIN_TZ_ADJ / 2)) + result += MIN_TZ_ADJ; + if(val < 0) + result = - result; + server->timeAdj = result; } else { - server->timeAdj = tmp * 60; /* also in seconds */ + server->timeAdj = (int)tmp; + server->timeAdj *= 60; /* also in seconds */ } cFYI(1,("server->timeAdj: %d seconds", server->timeAdj)); @@ -559,7 +567,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(0, ("Max buf = %d", ses->server->maxBuf)); GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); server->capabilities = le32_to_cpu(pSMBr->Capabilities); - server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60; + server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); + server->timeAdj *= 60; if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { memcpy(server->cryptKey, pSMBr->u.EncryptionKey, CIFS_CRYPTO_KEY_SIZE); @@ -1645,7 +1654,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ pSMB->FileID = (__u16) smb_file_id; - pSMB->LastWriteTime = 0; + pSMB->LastWriteTime = 0xFFFFFFFF; pSMB->ByteCount = 0; rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -- GitLab From 947a50679570ef7a66e3e3107e95943a1cb14d08 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 2 Oct 2006 05:55:25 +0000 Subject: [PATCH 0339/1619] [CIFS] Fix typo Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8d30a5c4f24..005fb315477 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -495,7 +495,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (int)(utc.tv_sec - ts.tv_sec))); val = (int)(utc.tv_sec - ts.tv_sec); seconds = val < 0 ? -val : val; - result = (seconds / IN_TZ_ADJ) * MIN_TZ_ADJ; + result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; remain = seconds % MIN_TZ_ADJ; if(remain >= (MIN_TZ_ADJ / 2)) result += MIN_TZ_ADJ; -- GitLab From 1a70d6529ad9f5978af846440f8a809784d6e813 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 2 Oct 2006 05:59:18 +0000 Subject: [PATCH 0340/1619] [CIFS] Fix compiler warning with previous patch Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 005fb315477..79a01d35a78 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->capabilities = CAP_MPX_MODE; } tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); - if (tmp == 0xffff) { + if (tmp == -1) { /* OS/2 often does not set timezone therefore * we must use server time to calc time zone. * Could deviate slightly from the right zone. -- GitLab From 9c9eb21eee1790804ce407fd820f65be0b4fdd03 Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Sat, 30 Sep 2006 23:38:50 -0700 Subject: [PATCH 0341/1619] [GFS2] Remove readv/writev methods and use aio_read/aio_write instead (gfs bits) 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: Steven Whitehouse --- fs/gfs2/ops_file.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index a9ac1358ce2..a05b75a7ed8 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -613,10 +613,8 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, .read = generic_file_read, - .readv = generic_file_readv, .aio_read = generic_file_aio_read, .write = generic_file_write, - .writev = generic_file_writev, .aio_write = generic_file_aio_write, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, -- GitLab From 930cc237d67dc62464fe71529631d16f51d7aee3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 30 Sep 2006 23:38:51 -0700 Subject: [PATCH 0342/1619] [GFS2] streamline-generic_file_-interfaces-and-filemap gfs fix Fix GFS for streamline-generic_file_-interfaces-and-filemap.patch Signed-off-by: Andrew Morton Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index a05b75a7ed8..f2d0bd80a1c 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -612,9 +612,9 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, - .read = generic_file_read, + .read = do_sync_read, .aio_read = generic_file_aio_read, - .write = generic_file_write, + .write = do_sync_write, .aio_write = generic_file_aio_write, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, -- GitLab From d00223f1693173c7b51f867dd52049955a92d0ed Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 10:28:05 -0400 Subject: [PATCH 0343/1619] [GFS2] Fix code style/indent in ops_file.c Fix a couple of minor issues. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index f2d0bd80a1c..fafa48b9105 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -606,15 +606,16 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) if (fl->fl_type == F_UNLCK) { do_unflock(file, fl); return 0; - } else + } else { return do_flock(file, cmd, fl); + } } const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, - .read = do_sync_read, + .read = do_sync_read, .aio_read = generic_file_aio_read, - .write = do_sync_write, + .write = do_sync_write, .aio_write = generic_file_aio_write, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, -- GitLab From 128e5ebaf8abbda375bba82690b09630003c9213 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 11:24:43 -0400 Subject: [PATCH 0344/1619] [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 diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index fafa48b9105..3064f133bf3 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 839a97ee1f7..15667cc947d 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 2e29a2edaee..bc0e645abb8 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 5b27102dfea..00000000000 --- 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 */ -- GitLab From 2e565bb69ce2184eabf4f43e64afc79c46f46204 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 11:38:25 -0400 Subject: [PATCH 0345/1619] [GFS2] Mark metadata reads for blktrace Mark the metadata reads so that blktrace knows what they are. Signed-off-by: Steven Whitehouse --- fs/gfs2/meta_io.c | 7 ++++--- fs/gfs2/quota.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 73179915318..d0d981dac4c 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -385,7 +386,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, { *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); if (!buffer_uptodate(*bhp)) - ll_rw_block(READ, 1, bhp); + ll_rw_block(READ_META, 1, bhp); if (flags & DIO_WAIT) { int error = gfs2_meta_wait(gl->gl_sbd, *bhp); if (error) { @@ -659,7 +660,7 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, } else { u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(READ_META, 1, &bh); if (gfs2_meta_wait(sdp, bh)) goto err; } @@ -712,7 +713,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) if (buffer_uptodate(first_bh)) goto out; if (!buffer_locked(first_bh)) - ll_rw_block(READ, 1, &first_bh); + ll_rw_block(READ_META, 1, &first_bh); dblock++; extlen--; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c0a3c9a2a59..c69b94a5558 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -609,7 +610,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, set_buffer_uptodate(bh); if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(READ_META, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) goto unlock; -- GitLab From 3cf1e7bed4681bdb1c14b6e146ae9c0afb6c1552 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 11:49:41 -0400 Subject: [PATCH 0346/1619] [GFS2] Remove duplicate sb reading code For some reason we had two different sets of code for reading in the superblock. This removes one of them in favour of the other. Also we don't need the temporary buffer for the sb since we already have one in the gfs2 sb itself. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 41 +++++++++++++---------------------------- fs/gfs2/super.c | 4 ++-- fs/gfs2/super.h | 1 + 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index a9aa2edd756..178b3391184 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -116,7 +116,7 @@ static void init_vfs(struct super_block *sb, unsigned noatime) static int init_names(struct gfs2_sbd *sdp, int silent) { - struct gfs2_sb *sb = NULL; + struct page *page; char *proto, *table; int error = 0; @@ -126,37 +126,23 @@ static int init_names(struct gfs2_sbd *sdp, int silent) /* 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); + struct gfs2_sb *sb; + page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift); + if (!page) + return -ENOBUFS; + sb = kmap(page); + gfs2_sb_in(&sdp->sd_sb, sb); + kunmap(page); + __free_page(page); + + error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); if (error) goto out; if (!proto[0]) - proto = sb->sb_lockproto; + proto = sdp->sd_sb.sb_lockproto; if (!table[0]) - table = sb->sb_locktable; + table = sdp->sd_sb.sb_locktable; } if (!table[0]) @@ -166,7 +152,6 @@ static int init_names(struct gfs2_sbd *sdp, int silent) snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table); out: - kfree(sb); return error; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f6ce5e4eaf7..6a78b1b32e2 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -180,7 +180,7 @@ static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) return 0; } -static struct page *gfs2_read_super(struct super_block *sb, sector_t sector) +struct page *gfs2_read_super(struct super_block *sb, sector_t sector) { struct page *page; struct bio *bio; @@ -205,7 +205,7 @@ static struct page *gfs2_read_super(struct super_block *sb, sector_t sector) bio->bi_end_io = end_bio_io_page; bio->bi_private = page; - submit_bio(READ_SYNC, bio); + submit_bio(READ_SYNC | (1 << BIO_RW_META), bio); wait_on_page_locked(page); bio_put(bio); if (!PageUptodate(page)) { diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 5fa5119cfba..5bb443ae0f5 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -16,6 +16,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_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent); +struct page *gfs2_read_super(struct super_block *sb, sector_t sector); static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) { -- GitLab From 48516ced21e83a755ebae3d1ed03f1731befc391 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 12:39:19 -0400 Subject: [PATCH 0347/1619] [GFS2] Remove uneeded endian conversion In many places GFS2 was calling the endian conversion routines for an inode even when only a single field, or a few fields might have changed. As a result we were copying lots of data needlessly. This patch replaces those calls with conversion of just the required fields in each case. This should be faster and easier to understand. There are still other places which suffer from this problem, but this is a start in the right direction. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 21 +++++++++++---------- fs/gfs2/inode.c | 4 +++- fs/gfs2/ops_address.c | 14 +++++++++++--- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 92eef825167..cc57f2ecd21 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -121,6 +121,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) { struct buffer_head *bh, *dibh; + struct gfs2_dinode *di; u64 block = 0; int isdir = gfs2_is_dir(ip); int error; @@ -141,8 +142,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) error = gfs2_dir_get_new_buffer(ip, block, &bh); if (error) goto out_brelse; - gfs2_buffer_copy_tail(bh, - sizeof(struct gfs2_meta_header), + gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_meta_header), dibh, sizeof(struct gfs2_dinode)); brelse(bh); } else { @@ -157,18 +157,17 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) /* Set up the pointer to the new block */ gfs2_trans_add_bh(ip->i_gl, dibh, 1); - + di = (struct gfs2_dinode *)dibh->b_data; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); if (ip->i_di.di_size) { - *(u64 *)(dibh->b_data + sizeof(struct gfs2_dinode)) = - cpu_to_be64(block); + *(__be64 *)(di + 1) = cpu_to_be64(block); ip->i_di.di_blocks++; + di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); } ip->i_di.di_height = 1; - - gfs2_dinode_out(&ip->i_di, dibh->b_data); + di->di_height = cpu_to_be16(1); out_brelse: brelse(dibh); @@ -229,6 +228,7 @@ static int build_height(struct inode *inode, unsigned height) unsigned new_height = height - ip->i_di.di_height; struct buffer_head *dibh; struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; + struct gfs2_dinode *di; int error; u64 *bp; u64 bn; @@ -267,12 +267,13 @@ static int build_height(struct inode *inode, unsigned height) dibh, sizeof(struct gfs2_dinode)); brelse(blocks[n]); gfs2_trans_add_bh(ip->i_gl, dibh, 1); + di = (struct gfs2_dinode *)dibh->b_data; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - bp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode)); - *bp = cpu_to_be64(bn); + *(__be64 *)(di + 1) = cpu_to_be64(bn); ip->i_di.di_height += new_height; ip->i_di.di_blocks += new_height; - gfs2_dinode_out(&ip->i_di, dibh->b_data); + di->di_height = cpu_to_be16(ip->i_di.di_height); + di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); brelse(dibh); return error; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 57a4c8b6858..660dc81849a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1166,6 +1166,7 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) curtime = get_seconds(); if (curtime - ip->i_di.di_atime >= quantum) { struct buffer_head *dibh; + struct gfs2_dinode *di; error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error == -EROFS) @@ -1180,7 +1181,8 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) ip->i_di.di_atime = curtime; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + di = (struct gfs2_dinode *)dibh->b_data; + di->di_atime = cpu_to_be64(ip->i_di.di_atime); brelse(dibh); gfs2_trans_end(sdp); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 811f4ada2a0..4fb743f4e4a 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -460,7 +460,8 @@ static int gfs2_commit_write(struct file *file, struct page *page, struct gfs2_sbd *sdp = GFS2_SB(inode); int error = -EOPNOTSUPP; struct buffer_head *dibh; - struct gfs2_alloc *al = &ip->i_alloc;; + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_dinode *di; if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) goto fail_nounlock; @@ -470,6 +471,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, goto fail_endtrans; gfs2_trans_add_bh(ip->i_gl, dibh, 1); + di = (struct gfs2_dinode *)dibh->b_data; if (gfs2_is_stuffed(ip)) { u64 file_size; @@ -495,10 +497,16 @@ static int gfs2_commit_write(struct file *file, struct page *page, goto fail; } - if (ip->i_di.di_size < inode->i_size) + if (ip->i_di.di_size < inode->i_size) { ip->i_di.di_size = inode->i_size; + 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); - gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); gfs2_trans_end(sdp); if (al->al_requested) { -- GitLab From 409e185d2370356ac2e4c7160e002ac5340b6709 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 14:20:43 -0400 Subject: [PATCH 0348/1619] [GFS2] Two redundant casts removed Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 57af0192b24..82432d8f713 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -411,10 +411,10 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) 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); + gfs2_inum_out(&dip->i_num, &dent->de_inum); dent->de_type = DT_DIR; - gfs2_dinode_out(&ip->i_di, (char *)di); + gfs2_dinode_out(&ip->i_di, di); brelse(dibh); } -- GitLab From f92a0b6ff43e8e07bbd5b1d2dd1cff130014f3c7 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 16:01:53 -0400 Subject: [PATCH 0349/1619] [GFS2] Mark nlink cleared so VFS sees it happen This does nothing atm, but will be required for later support of r/o bind mounts. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 660dc81849a..81a92116594 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -353,6 +353,7 @@ 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: -- GitLab From a542dbd3172922f178d25b463751da81d7b1e560 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 13:49:58 +1000 Subject: [PATCH 0350/1619] [POWERPC] Allow combined iSeries and MULTIPLATFORM build This will build with ISERIES, PSERIES and PMAC64 selected, but will only boot on iSeries so far. Signed-off-by: Stephen Rothwell --- arch/powerpc/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index de1ef2fa1a2..0969fe89df8 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -338,10 +338,6 @@ config PPC_MULTIPLATFORM RS/6000 machine, an Apple machine, or a PReP, CHRP, Maple or Cell-based machine. -config PPC_ISERIES - bool "IBM Legacy iSeries" - depends on PPC64 - config EMBEDDED6xx bool "Embedded 6xx/7xx/7xxx-based board" depends on PPC32 && (BROKEN||BROKEN_ON_SMP) @@ -365,6 +361,10 @@ config PPC_PSERIES select PPC_UDBG_16550 default y +config PPC_ISERIES + bool "IBM Legacy iSeries" + depends on PPC_MULTIPLATFORM && PPC64 + config PPC_CHRP bool "Common Hardware Reference Platform (CHRP) based machines" depends on PPC_MULTIPLATFORM && PPC32 -- GitLab From fc246c389db7b08b4a054e68c742c6598b02523c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 14:00:41 +1000 Subject: [PATCH 0351/1619] [POWERPC] iSeries does not need pcibios_fixup_resources Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/pci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index e904b3609c6..4aa165e010d 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -262,10 +262,6 @@ void __init iSeries_pci_final_fixup(void) mf_display_src(0xC9000200); } -void pcibios_fixup_resources(struct pci_dev *pdev) -{ -} - /* * Look down the chain to find the matching Device Device */ -- GitLab From 3f639ee8c52c187d8c95db430ac6f485bffbe5af Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 25 Sep 2006 18:19:00 +1000 Subject: [PATCH 0352/1619] [POWERPC] implement BEGIN/END_FW_FTR_SECTION and use it an all the obvious places in assembler code. Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/entry_64.S | 18 ++++++--- arch/powerpc/kernel/head_64.S | 28 +++++++++++-- arch/powerpc/kernel/misc_64.S | 46 +++++++++++++++++++++ arch/powerpc/kernel/vmlinux.lds.S | 8 ++++ arch/powerpc/mm/slb_low.S | 3 ++ include/asm-powerpc/firmware.h | 67 ++++++++++++++++++++----------- 6 files changed, 137 insertions(+), 33 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2cd872b5283..748e74fcf54 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -27,10 +27,7 @@ #include #include #include - -#ifdef CONFIG_PPC_ISERIES -#define DO_SOFT_DISABLE -#endif +#include /* * System calls. @@ -91,6 +88,7 @@ system_call_common: ld r11,exception_marker@toc(r2) std r11,-16(r9) /* "regshere" marker */ #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION /* Hack for handling interrupts when soft-enabling on iSeries */ cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ andi. r10,r12,MSR_PR /* from kernel */ @@ -98,6 +96,7 @@ system_call_common: beq hardware_interrupt_entry lbz r10,PACAPROCENABLED(r13) std r10,SOFTE(r1) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif mfmsr r11 ori r11,r11,MSR_EE @@ -462,6 +461,7 @@ _GLOBAL(ret_from_except_lite) restore: #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION ld r5,SOFTE(r1) cmpdi 0,r5,0 beq 4f @@ -480,6 +480,7 @@ restore: b .ret_from_except_lite /* loop back and handle more */ 4: stb r5,PACAPROCENABLED(r13) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif ld r3,_MSR(r1) @@ -538,18 +539,23 @@ do_work: lwz r8,TI_PREEMPT(r9) cmpwi cr1,r8,0 #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION ld r0,SOFTE(r1) cmpdi r0,0 -#else - andi. r0,r3,MSR_EE +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif +BEGIN_FW_FTR_SECTION + andi. r0,r3,MSR_EE +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) crandc eq,cr1*4+eq,eq bne restore /* here we are preempting the current task */ 1: #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION li r0,1 stb r0,PACAPROCENABLED(r13) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif ori r10,r10,MSR_EE mtmsrd r10,1 /* reenable interrupts */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 3065b472b95..645c7f10fb2 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_PPC_ISERIES #define DO_SOFT_DISABLE @@ -365,19 +366,28 @@ label##_iSeries: \ #ifdef DO_SOFT_DISABLE #define DISABLE_INTS \ +BEGIN_FW_FTR_SECTION; \ lbz r10,PACAPROCENABLED(r13); \ li r11,0; \ std r10,SOFTE(r1); \ mfmsr r10; \ stb r11,PACAPROCENABLED(r13); \ ori r10,r10,MSR_EE; \ - mtmsrd r10,1 + mtmsrd r10,1; \ +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #define ENABLE_INTS \ +BEGIN_FW_FTR_SECTION; \ lbz r10,PACAPROCENABLED(r13); \ mfmsr r11; \ std r10,SOFTE(r1); \ ori r11,r11,MSR_EE; \ +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ +BEGIN_FW_FTR_SECTION; \ + ld r12,_MSR(r1); \ + mfmsr r11; \ + rlwimi r11,r12,0,MSR_EE; \ +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ mtmsrd r11,1 #else /* hard enable/disable interrupts */ @@ -1071,8 +1081,10 @@ _GLOBAL(slb_miss_realmode) ld r3,PACA_EXSLB+EX_R3(r13) lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION ld r11,PACALPPACAPTR(r13) ld r11,LPPACASRR0(r11) /* get SRR0 value */ +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif /* CONFIG_PPC_ISERIES */ mtlr r10 @@ -1087,8 +1099,10 @@ _GLOBAL(slb_miss_realmode) .machine pop #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION mtspr SPRN_SRR0,r11 mtspr SPRN_SRR1,r12 +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) @@ -1301,6 +1315,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) cmpdi r3,0 /* see if hash_page succeeded */ #ifdef DO_SOFT_DISABLE +BEGIN_FW_FTR_SECTION /* * If we had interrupts soft-enabled at the point where the * DSI/ISI occurred, and an interrupt came in during hash_page, @@ -1321,12 +1336,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) ld r3,SOFTE(r1) bl .local_irq_restore b 11f -#else +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif +BEGIN_FW_FTR_SECTION beq fast_exception_return /* Return from exception on success */ ble- 12f /* Failure return from hash_page */ /* fall through */ -#endif +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) /* Here we have a page fault that hash_page can't handle. */ _GLOBAL(handle_page_fault) @@ -1861,7 +1878,9 @@ _GLOBAL(__secondary_start) LOAD_REG_ADDR(r3, .start_secondary_prolog) LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) #ifdef DO_SOFT_DISABLE +BEGIN_FW_FTR_SECTION ori r4,r4,MSR_EE +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif mtspr SPRN_SRR0,r3 mtspr SPRN_SRR1,r4 @@ -1986,6 +2005,7 @@ _STATIC(start_here_common) */ li r3,0 bl .do_cpu_ftr_fixups + bl .do_fw_ftr_fixups /* ptr to current */ LOAD_REG_IMMEDIATE(r4, init_task) @@ -2000,11 +2020,13 @@ _STATIC(start_here_common) /* Load up the kernel context */ 5: #ifdef DO_SOFT_DISABLE +BEGIN_FW_FTR_SECTION li r5,0 stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ mfmsr r5 ori r5,r5,MSR_EE /* Hard Enabled */ mtmsrd r5 +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif bl .start_kernel diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index e3ed21cd3d9..465a7641cd0 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -325,6 +325,52 @@ _GLOBAL(do_cpu_ftr_fixups) isync b 1b +/* + * do_fw_ftr_fixups - goes through the list of firmware feature fixups + * and writes nop's over sections of code that don't apply for this firmware. + * r3 = data offset (not changed) + */ +_GLOBAL(do_fw_ftr_fixups) + /* Get firmware features */ + LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features) + sub r6,r6,r3 + ld r4,0(r6) + /* Get the fixup table */ + LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup) + sub r6,r6,r3 + LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup) + sub r7,r7,r3 + /* Do the fixup */ +1: cmpld r6,r7 + bgelr + addi r6,r6,32 + ld r8,-32(r6) /* mask */ + and r8,r8,r4 + ld r9,-24(r6) /* value */ + cmpld r8,r9 + beq 1b + ld r8,-16(r6) /* section begin */ + ld r9,-8(r6) /* section end */ + subf. r9,r8,r9 + beq 1b + /* write nops over the section of code */ + /* todo: if large section, add a branch at the start of it */ + srwi r9,r9,2 + mtctr r9 + sub r8,r8,r3 + lis r0,0x60000000@h /* nop */ +3: stw r0,0(r8) +BEGIN_FTR_SECTION + dcbst 0,r8 /* suboptimal, but simpler */ + sync + icbi 0,r8 +END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE) + addi r8,r8,4 + bdnz 3b + sync /* additional sync needed on g4 */ + isync + b 1b + #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) /* * Do an IO access in real mode diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 02665a02130..cb0e8d46c3e 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -132,6 +132,14 @@ SECTIONS *(__ftr_fixup) __stop___ftr_fixup = .; } +#ifdef CONFIG_PPC64 + . = ALIGN(8); + __fw_ftr_fixup : { + __start___fw_ftr_fixup = .; + *(__fw_ftr_fixup) + __stop___fw_ftr_fixup = .; + } +#endif . = ALIGN(PAGE_SIZE); .init.ramfs : { diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index dbc1abbde03..b10e4707d7c 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -21,6 +21,7 @@ #include #include #include +#include /* void slb_allocate_realmode(unsigned long ea); * @@ -183,6 +184,7 @@ slb_finish_load: * dont have any LRU information to help us choose a slot. */ #ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION /* * On iSeries, the "bolted" stack segment can be cast out on * shared processor switch so we need to check for a miss on @@ -194,6 +196,7 @@ slb_finish_load: li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ cmpld r9,r3 beq 3f +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif /* CONFIG_PPC_ISERIES */ ld r10,PACASTABRR(r13) diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h index 77069df92bf..1022737f4f3 100644 --- a/include/asm-powerpc/firmware.h +++ b/include/asm-powerpc/firmware.h @@ -14,34 +14,36 @@ #ifdef __KERNEL__ -#ifndef __ASSEMBLY__ +#include /* firmware feature bitmask values */ #define FIRMWARE_MAX_FEATURES 63 -#define FW_FEATURE_PFT (1UL<<0) -#define FW_FEATURE_TCE (1UL<<1) -#define FW_FEATURE_SPRG0 (1UL<<2) -#define FW_FEATURE_DABR (1UL<<3) -#define FW_FEATURE_COPY (1UL<<4) -#define FW_FEATURE_ASR (1UL<<5) -#define FW_FEATURE_DEBUG (1UL<<6) -#define FW_FEATURE_TERM (1UL<<7) -#define FW_FEATURE_PERF (1UL<<8) -#define FW_FEATURE_DUMP (1UL<<9) -#define FW_FEATURE_INTERRUPT (1UL<<10) -#define FW_FEATURE_MIGRATE (1UL<<11) -#define FW_FEATURE_PERFMON (1UL<<12) -#define FW_FEATURE_CRQ (1UL<<13) -#define FW_FEATURE_VIO (1UL<<14) -#define FW_FEATURE_RDMA (1UL<<15) -#define FW_FEATURE_LLAN (1UL<<16) -#define FW_FEATURE_BULK (1UL<<17) -#define FW_FEATURE_XDABR (1UL<<18) -#define FW_FEATURE_MULTITCE (1UL<<19) -#define FW_FEATURE_SPLPAR (1UL<<20) -#define FW_FEATURE_ISERIES (1UL<<21) -#define FW_FEATURE_LPAR (1UL<<22) +#define FW_FEATURE_PFT ASM_CONST(0x0000000000000001) +#define FW_FEATURE_TCE ASM_CONST(0x0000000000000002) +#define FW_FEATURE_SPRG0 ASM_CONST(0x0000000000000004) +#define FW_FEATURE_DABR ASM_CONST(0x0000000000000008) +#define FW_FEATURE_COPY ASM_CONST(0x0000000000000010) +#define FW_FEATURE_ASR ASM_CONST(0x0000000000000020) +#define FW_FEATURE_DEBUG ASM_CONST(0x0000000000000040) +#define FW_FEATURE_TERM ASM_CONST(0x0000000000000080) +#define FW_FEATURE_PERF ASM_CONST(0x0000000000000100) +#define FW_FEATURE_DUMP ASM_CONST(0x0000000000000200) +#define FW_FEATURE_INTERRUPT ASM_CONST(0x0000000000000400) +#define FW_FEATURE_MIGRATE ASM_CONST(0x0000000000000800) +#define FW_FEATURE_PERFMON ASM_CONST(0x0000000000001000) +#define FW_FEATURE_CRQ ASM_CONST(0x0000000000002000) +#define FW_FEATURE_VIO ASM_CONST(0x0000000000004000) +#define FW_FEATURE_RDMA ASM_CONST(0x0000000000008000) +#define FW_FEATURE_LLAN ASM_CONST(0x0000000000010000) +#define FW_FEATURE_BULK ASM_CONST(0x0000000000020000) +#define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000) +#define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000) +#define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000) +#define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000) +#define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000) + +#ifndef __ASSEMBLY__ enum { #ifdef CONFIG_PPC64 @@ -94,6 +96,23 @@ extern void machine_check_fwnmi(void); /* This is true if we are using the firmware NMI handler (typically LPAR) */ extern int fwnmi_active; +#else /* __ASSEMBLY__ */ + +#define BEGIN_FW_FTR_SECTION 96: + +#define END_FW_FTR_SECTION(msk, val) \ +97: \ + .section __fw_ftr_fixup,"a"; \ + .align 3; \ + .llong msk; \ + .llong val; \ + .llong 96b; \ + .llong 97b; \ + .previous + +#define END_FW_FTR_SECTION_IFSET(msk) END_FW_FTR_SECTION((msk), (msk)) +#define END_FW_FTR_SECTION_IFCLR(msk) END_FW_FTR_SECTION((msk), 0) + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_FIRMWARE_H */ -- GitLab From 80a544cebca5f28397020332e21e04d639a18943 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 26 Sep 2006 13:55:58 +1000 Subject: [PATCH 0353/1619] [POWERPC] iSeries has no legacy I/O Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/setup.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 7cb6b5f7c59..a0ff7ba7d66 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -649,6 +649,15 @@ static void iseries_dedicated_idle(void) void __init iSeries_init_IRQ(void) { } #endif +/* + * iSeries has no legacy IO, anything calling this function has to + * fail or bad things will happen + */ +static int iseries_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + static int __init iseries_probe(void) { unsigned long root = of_get_flat_dt_root(); @@ -677,6 +686,7 @@ define_machine(iseries) { .calibrate_decr = generic_calibrate_decr, .progress = iSeries_progress, .probe = iseries_probe, + .check_legacy_ioport = iseries_check_legacy_ioport, /* XXX Implement enable_pmcs for iSeries */ }; -- GitLab From 8f6fd19f1f7ab1dab225845464c96cba36a18533 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 1 Oct 2006 12:00:47 +0200 Subject: [PATCH 0354/1619] [SCSI] enable clustering for tmscsim following an email from John Adams to me with a patch to enable tmscsim to use blocks up to 1MB and a discussion on linux-scsi, below is a patch to enable clustering for tmscsim. I made it switchable with a module parameter, with default "enable" - in case somebody gets problems with it. Unfortunately, I was not able to check if this alone lets you use any bigger blocks with a tape, as my tape seems to only support 1 block size - only "mt setblk 1" is successful, any other value fails. OTOH, testing on a P-133 showed that enabling clustering alone improves throughput by 10% and reduces CPU load by another 10%, so, seems a worthy thing to do. As for setting max_sectors, that might become a separate patch... Signed-off-by: James Bottomley --- drivers/scsi/tmscsim.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 9404ff3d4c7..028d5f641cc 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -279,6 +279,10 @@ static void dc390_ResetDevParam(struct dc390_acb* pACB); static u32 dc390_laststatus = 0; static u8 dc390_adapterCnt = 0; +static int disable_clustering; +module_param(disable_clustering, int, S_IRUGO); +MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1"); + /* Startup values, to be overriden on the commandline */ static int tmscsim[] = {-2, -2, -2, -2, -2, -2}; @@ -2299,7 +2303,7 @@ static struct scsi_host_template driver_template = { .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, }; /*********************************************************************** @@ -2525,6 +2529,8 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev, pci_set_master(pdev); error = -ENOMEM; + if (disable_clustering) + driver_template.use_clustering = DISABLE_CLUSTERING; shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb)); if (!shost) goto out_disable_device; @@ -2660,6 +2666,10 @@ static struct pci_driver dc390_driver = { static int __init dc390_module_init(void) { + if (!disable_clustering) + printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n" + "\twith \"disable_clustering=1\" and report to maintainers\n"); + if (tmscsim[0] == -1 || tmscsim[0] > 15) { tmscsim[0] = 7; tmscsim[1] = 4; -- GitLab From ddacfaf76dd620af9b73343a975749778321b51c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 3 Oct 2006 11:10:41 -0400 Subject: [PATCH 0355/1619] [GFS2] Move logging code into log.c (mostly) This moves the logging code from meta_io.c into log.c and glops.c. As a result the routines can now be static and all the logging code is together in log.c, leaving meta_io.c with just metadata i/o code in it. Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 51 ++++++++++++++ fs/gfs2/log.c | 109 ++++++++++++++++++++++++++++++ fs/gfs2/meta_io.c | 164 ---------------------------------------------- fs/gfs2/meta_io.h | 10 +-- 4 files changed, 165 insertions(+), 169 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index ef1492e2d44..41a6b6818a5 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -26,7 +26,58 @@ #include "recovery.h" #include "rgrp.h" #include "util.h" +#include "trans.h" +/** + * 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. + */ + +static 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; + u64 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, NULL); +} /** * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 6112d648b7e..554fe5bd1b7 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -58,6 +58,90 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, return blks; } +/** + * gfs2_ail1_start_one - Start I/O on a part of the AIL + * @sdp: the filesystem + * @tr: the part of the AIL + * + */ + +static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct gfs2_bufdata *bd, *s; + struct buffer_head *bh; + int retry; + + BUG_ON(!spin_is_locked(&sdp->sd_log_lock)); + + 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_log_unlock(sdp); + gfs2_io_error_bh(sdp, bh); + gfs2_log_lock(sdp); + } + 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 + * + */ + +static 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); +} + void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) { struct list_head *head = &sdp->sd_ail1_list; @@ -121,6 +205,31 @@ int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) return ret; } + +/** + * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced + * @sdp: the filesystem + * @ai: the AIL entry + * + */ + +static 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); + } +} + static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) { struct gfs2_ail *ai, *safe; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index d0d981dac4c..3912d6a4b1e 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -34,11 +34,6 @@ #include "util.h" #include "ops_address.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) { @@ -91,165 +86,6 @@ void gfs2_aspace_put(struct inode *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; - - BUG_ON(!spin_is_locked(&sdp->sd_log_lock)); - - 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_log_unlock(sdp); - gfs2_io_error_bh(sdp, bh); - gfs2_log_lock(sdp); - } - 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; - u64 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, NULL); -} - /** * gfs2_meta_inval - Invalidate all buffers associated with a glock * @gl: the glock diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 3323e6d0ed8..3ec939e20df 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -40,11 +40,6 @@ static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh, 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); @@ -74,5 +69,10 @@ static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); +#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))) + #endif /* __DIO_DOT_H__ */ -- GitLab From fcb47e0bd279cab5ba8299c0a1e3364d15413a6b Mon Sep 17 00:00:00 2001 From: Ryan O'Hara Date: Tue, 3 Oct 2006 11:57:35 -0400 Subject: [PATCH 0356/1619] [GFS2] Initialize SELinux extended attributes at inode creation time. This patch has gfs2_security_init declared as a static function, which is correct. As a result, the declaration of this function in inode.h is removed (and thus inode.h is unchanged). Also removed #include eaops.h, which is not needed. Signed-Off-By: Ryan O'Hara Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 81a92116594..57c43ac4792 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -806,6 +807,39 @@ fail: return error; } +static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) +{ + int err; + size_t len; + void *value; + char *name; + struct gfs2_ea_request er; + + err = security_inode_init_security(&ip->i_inode, &dip->i_inode, + &name, &value, &len); + + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + + er.er_type = GFS2_EATYPE_SECURITY; + er.er_name = name; + er.er_data = value; + er.er_name_len = strlen(name); + er.er_data_len = len; + + err = gfs2_ea_set_i(ip, &er); + + kfree(value); + kfree(name); + + return err; +} + /** * gfs2_createi - Create a new inode * @ghs: An array of two holders @@ -897,6 +931,10 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_iput; + error = gfs2_security_init(dip, GFS2_I(inode)); + if (error) + goto fail_iput; + error = link_dinode(dip, name, GFS2_I(inode)); if (error) goto fail_iput; -- GitLab From e02f73e9fd69f1c6d16c207f7a91ce721fe8beab Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 2 Oct 2006 22:22:36 +0400 Subject: [PATCH 0357/1619] POWERPC: Added devicetree for mpc8272ads board This adds current dts file used with MPC8272ADS, introducing new mdio bitbang defines, as well as fully-CPM2-SoC board design. Signed-off-by: Vitaly Bordug --- arch/powerpc/boot/dts/mpc8272ads.dts | 223 +++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc8272ads.dts diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts new file mode 100644 index 00000000000..34efdd028c4 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -0,0 +1,223 @@ +/* + * MPC8272 ADS Device Tree Source + * + * Copyright 2005 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/ { + model = "MPC8272ADS"; + compatible = "MPC8260ADS"; + #address-cells = <1>; + #size-cells = <1>; + linux,phandle = <100>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <200>; + + PowerPC,8272@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <4000>; // L1, 16K + i-cache-size = <4000>; // L1, 16K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + 32-bit; + linux,phandle = <201>; + linux,boot-cpu; + }; + }; + + interrupt-controller@f8200000 { + linux,phandle = ; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = ; + built-in; + device_type = "pci-pic"; + }; + memory { + device_type = "memory"; + linux,phandle = <300>; + reg = <00000000 4000000 f4500000 00000020>; + }; + + soc8272@f0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = < 0 0 2 00000000 f0000000 00053000>; + reg = ; + + mdio@0 { + device_type = "mdio"; + compatible = "fs_enet"; + reg = <0 0>; + linux,phandle = <24520>; + #address-cells = <1>; + #size-cells = <0>; + ethernet-phy@0 { + linux,phandle = <2452000>; + interrupt-parent = <10c00>; + interrupts = <19 1>; + reg = <0>; + bitbang = [ 12 12 13 02 02 01 ]; + device_type = "ethernet-phy"; + }; + ethernet-phy@1 { + linux,phandle = <2452001>; + interrupt-parent = <10c00>; + interrupts = <19 1>; + bitbang = [ 12 12 13 02 02 01 ]; + reg = <3>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@24000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + device-id = <2>; + compatible = "fs_enet"; + model = "FCC"; + reg = <11300 20 8400 100 11380 30>; + mac-address = [ 00 11 2F 99 43 54 ]; + interrupts = <20 2>; + interrupt-parent = <10c00>; + phy-handle = <2452000>; + rx-clock = <13>; + tx-clock = <12>; + }; + + ethernet@25000 { + device_type = "network"; + device-id = <3>; + compatible = "fs_enet"; + model = "FCC"; + reg = <11320 20 8500 100 113b0 30>; + mac-address = [ 00 11 2F 99 44 54 ]; + interrupts = <21 2>; + interrupt-parent = <10c00>; + phy-handle = <2452001>; + rx-clock = <17>; + tx-clock = <18>; + }; + + cpm@f0000000 { + linux,phandle = ; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "cpm"; + model = "CPM2"; + ranges = <00000000 00000000 3ffff>; + reg = <10d80 3280>; + command-proc = <119c0>; + brg-frequency = <17D7840>; + cpm_clk = ; + + scc@11a00 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SCC"; + device-id = <2>; + reg = <11a00 20 8000 100>; + current-speed = <1c200>; + interrupts = <28 2>; + interrupt-parent = <10c00>; + clock-setup = <0 00ffffff>; + rx-clock = <1>; + tx-clock = <1>; + }; + + scc@11a60 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SCC"; + device-id = <5>; + reg = <11a60 20 8300 100>; + current-speed = <1c200>; + interrupts = <2b 2>; + interrupt-parent = <10c00>; + clock-setup = <1b ffffff00>; + rx-clock = <4>; + tx-clock = <4>; + }; + + }; + interrupt-controller@10c00 { + linux,phandle = <10c00>; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = <10c00 80>; + built-in; + device_type = "cpm-pic"; + compatible = "CPM2"; + }; + pci@0500 { + linux,phandle = <0500>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "8272"; + device_type = "pci"; + reg = <10430 4dc>; + clock-frequency = <3f940aa>; + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x16 */ + b000 0 0 1 f8200000 40 0 + b000 0 0 2 f8200000 41 0 + b000 0 0 3 f8200000 42 0 + b000 0 0 4 f8200000 43 0 + + /* IDSEL 0x17 */ + b800 0 0 1 f8200000 43 0 + b800 0 0 2 f8200000 40 0 + b800 0 0 3 f8200000 41 0 + b800 0 0 4 f8200000 42 0 + + /* IDSEL 0x18 */ + c000 0 0 1 f8200000 42 0 + c000 0 0 2 f8200000 43 0 + c000 0 0 3 f8200000 40 0 + c000 0 0 4 f8200000 41 0>; + interrupt-parent = <10c00>; + interrupts = <14 3>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 40000000 + 01000000 0 00000000 f6000000 0 02000000>; + }; + +/* May need to remove if on a part without crypto engine */ + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 10000>; + interrupts = ; + interrupt-parent = <10c00>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <0000007e>; +/* desc mask is for rev1.x, we need runtime fixup for >=2.x */ + descriptor-types-mask = <01010ebf>; + }; + + }; +}; -- GitLab From ed943c1faba53d9a0bde56007ee27762b29dccbd Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 2 Oct 2006 22:41:50 +0400 Subject: [PATCH 0358/1619] POWERPC: 8272ads merge to powerpc: common stuff This has modules of common directories related to the mpc8272ADS board, mainly common cpm2 changes and fsl_soc.c portions related to the bitbang MDIO and other mechanisms specific for this family. Signed-off-by: Vitaly Bordug --- arch/powerpc/Kconfig | 1 + arch/powerpc/sysdev/cpm2_pic.c | 2 +- arch/powerpc/sysdev/cpm2_pic.h | 2 +- arch/powerpc/sysdev/fsl_soc.c | 62 ++++++++++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index de1ef2fa1a2..18102163e7d 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -594,6 +594,7 @@ endmenu source arch/powerpc/platforms/embedded6xx/Kconfig source arch/powerpc/platforms/4xx/Kconfig +source arch/powerpc/platforms/82xx/Kconfig source arch/powerpc/platforms/83xx/Kconfig source arch/powerpc/platforms/85xx/Kconfig source arch/powerpc/platforms/86xx/Kconfig diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 51752990f7b..28b01899474 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -147,7 +147,7 @@ static struct irq_chip cpm2_pic = { .end = cpm2_end_irq, }; -int cpm2_get_irq(struct pt_regs *regs) +unsigned int cpm2_get_irq(struct pt_regs *regs) { int irq; unsigned long bits; diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h index d63e45d4df5..3c513e5a688 100644 --- a/arch/powerpc/sysdev/cpm2_pic.h +++ b/arch/powerpc/sysdev/cpm2_pic.h @@ -3,7 +3,7 @@ extern intctl_cpm2_t *cpm2_intctl; -extern int cpm2_get_irq(struct pt_regs *regs); +extern unsigned int cpm2_get_irq(struct pt_regs *regs); extern void cpm2_pic_init(struct device_node*); diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 022ed275ea6..7d759f1c26b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -37,6 +37,7 @@ #include extern void init_fcc_ioports(struct fs_platform_info*); +extern void init_scc_ioports(struct fs_uart_platform_info*); static phys_addr_t immrbase = -1; phys_addr_t get_immrbase(void) @@ -566,7 +567,7 @@ static int __init fs_enet_of_init(void) struct resource r[4]; struct device_node *phy, *mdio; struct fs_platform_info fs_enet_data; - const unsigned int *id, *phy_addr; + const unsigned int *id, *phy_addr, phy_irq; const void *mac_addr; const phandle *ph; const char *model; @@ -588,6 +589,7 @@ static int __init fs_enet_of_init(void) if (ret) goto err; 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; @@ -620,6 +622,8 @@ static int __init fs_enet_of_init(void) phy_addr = get_property(phy, "reg", NULL); fs_enet_data.phy_addr = *phy_addr; + phy_irq = get_property(phy, "interrupts", NULL); + id = get_property(np, "device-id", NULL); fs_enet_data.fs_no = *id; strcpy(fs_enet_data.fs_type, model); @@ -637,6 +641,7 @@ static int __init fs_enet_of_init(void) if (strstr(model, "FCC")) { int fcc_index = *id - 1; + unsigned char* mdio_bb_prop; fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); fs_enet_data.rx_ring = 32; @@ -652,14 +657,57 @@ static int __init fs_enet_of_init(void) (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); - of_node_put(mdio); + mdio_bb_prop = get_property(phy, "bitbang", NULL); + if (mdio_bb_prop) { + struct platform_device *fs_enet_mdio_bb_dev; + struct fs_mii_bb_platform_info fs_enet_mdio_bb_data; + + fs_enet_mdio_bb_dev = + platform_device_register_simple("fsl-bb-mdio", + i, NULL, 0); + memset(&fs_enet_mdio_bb_data, 0, + sizeof(struct fs_mii_bb_platform_info)); + fs_enet_mdio_bb_data.mdio_dat.bit = + mdio_bb_prop[0]; + fs_enet_mdio_bb_data.mdio_dir.bit = + mdio_bb_prop[1]; + fs_enet_mdio_bb_data.mdc_dat.bit = + mdio_bb_prop[2]; + fs_enet_mdio_bb_data.mdio_port = + mdio_bb_prop[3]; + fs_enet_mdio_bb_data.mdc_port = + mdio_bb_prop[4]; + fs_enet_mdio_bb_data.delay = + mdio_bb_prop[5]; + + fs_enet_mdio_bb_data.irq[0] = phy_irq[0]; + fs_enet_mdio_bb_data.irq[1] = -1; + fs_enet_mdio_bb_data.irq[2] = -1; + fs_enet_mdio_bb_data.irq[3] = phy_irq[0]; + fs_enet_mdio_bb_data.irq[31] = -1; + + fs_enet_mdio_bb_data.mdio_dat.offset = + (u32)&cpm2_immr->im_ioport.iop_pdatc; + fs_enet_mdio_bb_data.mdio_dir.offset = + (u32)&cpm2_immr->im_ioport.iop_pdirc; + fs_enet_mdio_bb_data.mdc_dat.offset = + (u32)&cpm2_immr->im_ioport.iop_pdatc; + + ret = platform_device_add_data( + fs_enet_mdio_bb_dev, + &fs_enet_mdio_bb_data, + sizeof(struct fs_mii_bb_platform_info)); + if (ret) + goto unreg; + } + + of_node_put(phy); + of_node_put(mdio); - ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, - sizeof(struct - fs_platform_info)); + ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, + sizeof(struct + fs_platform_info)); if (ret) goto unreg; } -- GitLab From 91bd61099defb28a442db358dd9c1693c6589cee Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 2 Oct 2006 22:45:17 +0400 Subject: [PATCH 0359/1619] POWERPC: mpc82xx merge: board-specific/platform stuff(resend) This intruduces 82xx family in arch/powerpc/platforms, and has all the board-specific code to represent regression-less transaction from ppc. The functionality is apparently the same, including PCI controller. Signed-off-by: Vitaly Bordug --- arch/powerpc/platforms/82xx/Kconfig | 21 + arch/powerpc/platforms/82xx/Makefile | 5 + arch/powerpc/platforms/82xx/m82xx_pci.h | 19 + arch/powerpc/platforms/82xx/mpc82xx.c | 111 ++++ arch/powerpc/platforms/82xx/mpc82xx_ads.c | 661 ++++++++++++++++++++++ arch/powerpc/platforms/82xx/pq2ads.h | 67 +++ 6 files changed, 884 insertions(+) create mode 100644 arch/powerpc/platforms/82xx/Kconfig create mode 100644 arch/powerpc/platforms/82xx/Makefile create mode 100644 arch/powerpc/platforms/82xx/m82xx_pci.h create mode 100644 arch/powerpc/platforms/82xx/mpc82xx.c create mode 100644 arch/powerpc/platforms/82xx/mpc82xx_ads.c create mode 100644 arch/powerpc/platforms/82xx/pq2ads.h diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig new file mode 100644 index 00000000000..47d841ecf2e --- /dev/null +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -0,0 +1,21 @@ +menu "Platform support" + depends on PPC_82xx + +choice + prompt "Machine Type" + default MPC82xx_ADS + +config MPC82xx_ADS + bool "Freescale MPC82xx ADS" + select DEFAULT_UIMAGE + select PQ2ADS + select 8272 + select 8260 + select CPM2 + select FSL_SOC + help + This option enables support for the MPC8272 ADS board + +endchoice + +endmenu diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile new file mode 100644 index 00000000000..d9fd4c84d2e --- /dev/null +++ b/arch/powerpc/platforms/82xx/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the PowerPC 82xx linux kernel. +# +obj-$(CONFIG_PPC_82xx) += mpc82xx.o +obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h new file mode 100644 index 00000000000..9cd8893b5a3 --- /dev/null +++ b/arch/powerpc/platforms/82xx/m82xx_pci.h @@ -0,0 +1,19 @@ +#ifndef _PPC_KERNEL_M82XX_PCI_H +#define _PPC_KERNEL_M82XX_PCI_H + +/* + * 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 + +#define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET) + +#ifndef _IO_BASE +#define _IO_BASE isa_io_base +#endif + +#endif /* _PPC_KERNEL_M8260_PCI_H */ diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c new file mode 100644 index 00000000000..89d702de486 --- /dev/null +++ b/arch/powerpc/platforms/82xx/mpc82xx.c @@ -0,0 +1,111 @@ +/* + * MPC82xx setup and early boot code plus other random bits. + * + * Author: Vitaly Bordug + * + * Copyright (c) 2006 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. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "pq2ads_pd.h" + +static int __init get_freq(char *name, unsigned long *val) +{ + struct device_node *cpu; + unsigned int *fp; + int found = 0; + + /* The cpu node should have timebase and clock frequency properties */ + cpu = of_find_node_by_type(NULL, "cpu"); + + if (cpu) { + fp = (unsigned int *)get_property(cpu, name, NULL); + if (fp) { + found = 1; + *val = *fp++; + } + + of_node_put(cpu); + } + + return found; +} + +void __init m82xx_calibrate_decr(void) +{ + ppc_tb_freq = 125000000; + if (!get_freq("bus-frequency", &ppc_tb_freq)) { + printk(KERN_ERR "WARNING: Estimating decrementer frequency " + "(not found)\n"); + } + ppc_tb_freq /= 4; + ppc_proc_freq = 1000000000; + if (!get_freq("clock-frequency", &ppc_proc_freq)) + printk(KERN_ERR "WARNING: Estimating processor frequency" + "(not found)\n"); +} + +void mpc82xx_ads_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); + seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); +} diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c new file mode 100644 index 00000000000..4276f087f26 --- /dev/null +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -0,0 +1,661 @@ +/* + * MPC82xx_ads setup and early boot code plus other random bits. + * + * Author: Vitaly Bordug + * m82xx_restart fix by Wade Farnsworth + * + * Copyright (c) 2006 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. + */ + + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include <../sysdev/cpm2_pic.h> + +#include "pq2ads_pd.h" + +#ifdef CONFIG_PCI +static uint pci_clk_frq; +static struct { + unsigned long *pci_int_stat_reg; + unsigned long *pci_int_mask_reg; +} pci_regs; + +static unsigned long pci_int_base; +static struct irq_host *pci_pic_host; +static struct device_node *pci_pic_node; +#endif + +static void __init mpc82xx_ads_pic_init(void) +{ + struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2"); + struct resource r; + cpm2_map_t *cpm_reg; + + if (np == NULL) { + printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); + return; + } + if (of_address_to_resource(np, 0, &r)) { + printk(KERN_ERR "PIC init: invalid resource\n"); + of_node_put(np); + return; + } + cpm2_pic_init(np); + of_node_put(np); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t)); + cpm_reg->im_intctl.ic_siprr = 0x05309770; + iounmap(cpm_reg); +#ifdef CONFIG_PCI + /* Initialize stuff for the 82xx CPLD IC and install demux */ + m82xx_pci_init_irq(); +#endif +} + +static void init_fcc1_ioports(struct fs_platform_info *fpi) +{ + struct io_port *io; + u32 tempval; + cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); + struct device_node *np; + struct resource r; + u32 *bcsr; + + np = of_find_node_by_type(NULL, "memory"); + if (!np) { + printk(KERN_INFO "No memory node in device tree\n"); + return; + } + if (of_address_to_resource(np, 1, &r)) { + printk(KERN_INFO "No memory reg property [1] in devicetree\n"); + return; + } + of_node_put(np); + bcsr = ioremap(r.start + 4, sizeof(u32)); + io = &immap->im_ioport; + + /* Enable the PHY */ + clrbits32(bcsr, BCSR1_FETHIEN); + setbits32(bcsr, BCSR1_FETH_RST); + + /* FCC1 pins are on port A/C. */ + /* Configure port A and C pins for FCC1 Ethernet. */ + + tempval = in_be32(&io->iop_pdira); + tempval &= ~PA1_DIRA0; + tempval |= PA1_DIRA1; + out_be32(&io->iop_pdira, tempval); + + tempval = in_be32(&io->iop_psora); + tempval &= ~PA1_PSORA0; + tempval |= PA1_PSORA1; + out_be32(&io->iop_psora, tempval); + + setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1); + + /* Alter clocks */ + tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); + + clrbits32(&io->iop_psorc, tempval); + clrbits32(&io->iop_pdirc, tempval); + setbits32(&io->iop_pparc, tempval); + + cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX); + + iounmap(bcsr); + iounmap(immap); +} + +static void init_fcc2_ioports(struct fs_platform_info *fpi) +{ + cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); + struct device_node *np; + struct resource r; + u32 *bcsr; + + struct io_port *io; + u32 tempval; + + np = of_find_node_by_type(NULL, "memory"); + if (!np) { + printk(KERN_INFO "No memory node in device tree\n"); + return; + } + if (of_address_to_resource(np, 1, &r)) { + printk(KERN_INFO "No memory reg property [1] in devicetree\n"); + return; + } + of_node_put(np); + io = &immap->im_ioport; + bcsr = ioremap(r.start + 12, sizeof(u32)); + + /* Enable the PHY */ + clrbits32(bcsr, BCSR3_FETHIEN2); + setbits32(bcsr, BCSR3_FETH2_RST); + + /* FCC2 are port B/C. */ + /* Configure port A and C pins for FCC2 Ethernet. */ + + 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); + + setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1); + + tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); + + /* Alter clocks */ + clrbits32(&io->iop_psorc, tempval); + clrbits32(&io->iop_pdirc, tempval); + setbits32(&io->iop_pparc, tempval); + + cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX); + + iounmap(bcsr); + iounmap(immap); +} + +void init_fcc_ioports(struct fs_platform_info *fpi) +{ + int fcc_no = fs_get_fcc_index(fpi->fs_no); + + switch (fcc_no) { + case 0: + init_fcc1_ioports(fpi); + break; + case 1: + init_fcc2_ioports(fpi); + break; + default: + printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); + return; + } +} + +static void init_scc1_uart_ioports(struct fs_uart_platform_info *data) +{ + cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); + + /* SCC1 is only on port D */ + setbits32(&immap->im_ioport.iop_ppard, 0x00000003); + clrbits32(&immap->im_ioport.iop_psord, 0x00000001); + setbits32(&immap->im_ioport.iop_psord, 0x00000002); + clrbits32(&immap->im_ioport.iop_pdird, 0x00000001); + setbits32(&immap->im_ioport.iop_pdird, 0x00000002); + + clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); + clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); + setbits32(&immap->im_cpmux.cmx_scr, + ((data->clk_tx - 1) << (4 - data->clk_tx))); + setbits32(&immap->im_cpmux.cmx_scr, + ((data->clk_rx - 1) << (4 - data->clk_rx))); + + iounmap(immap); +} + +static void init_scc4_uart_ioports(struct fs_uart_platform_info *data) +{ + cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); + + setbits32(&immap->im_ioport.iop_ppard, 0x00000600); + clrbits32(&immap->im_ioport.iop_psord, 0x00000600); + clrbits32(&immap->im_ioport.iop_pdird, 0x00000200); + setbits32(&immap->im_ioport.iop_pdird, 0x00000400); + + clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); + clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); + setbits32(&immap->im_cpmux.cmx_scr, + ((data->clk_tx - 1) << (4 - data->clk_tx))); + setbits32(&immap->im_cpmux.cmx_scr, + ((data->clk_rx - 1) << (4 - data->clk_rx))); + + iounmap(immap); +} + +void init_scc_ioports(struct fs_uart_platform_info *data) +{ + int scc_no = fs_get_scc_index(data->fs_no); + + switch (scc_no) { + case 0: + init_scc1_uart_ioports(data); + data->brg = data->clk_rx; + break; + case 3: + init_scc4_uart_ioports(data); + data->brg = data->clk_rx; + break; + default: + printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); + return; + } +} + +void __init m82xx_board_setup(void) +{ + cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); + struct device_node *np; + struct resource r; + u32 *bcsr; + + np = of_find_node_by_type(NULL, "memory"); + if (!np) { + printk(KERN_INFO "No memory node in device tree\n"); + return; + } + if (of_address_to_resource(np, 1, &r)) { + printk(KERN_INFO "No memory reg property [1] in devicetree\n"); + return; + } + of_node_put(np); + bcsr = ioremap(r.start + 4, sizeof(u32)); + /* Enable the 2nd UART port */ + clrbits32(bcsr, BCSR1_RS232_EN2); + +#ifdef CONFIG_SERIAL_CPM_SCC1 + clrbits32((u32 *) & immap->im_scc[0].scc_sccm, + UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl, + SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC2 + clrbits32((u32 *) & immap->im_scc[1].scc_sccm, + UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl, + SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC3 + clrbits32((u32 *) & immap->im_scc[2].scc_sccm, + UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl, + SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + +#ifdef CONFIG_SERIAL_CPM_SCC4 + clrbits32((u32 *) & immap->im_scc[3].scc_sccm, + UART_SCCM_TX | UART_SCCM_RX); + clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl, + SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + + iounmap(bcsr); + iounmap(immap); +} + +#ifdef CONFIG_PCI +static void m82xx_pci_mask_irq(unsigned int irq) +{ + int bit = irq - pci_int_base; + + *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); + return; +} + +static void m82xx_pci_unmask_irq(unsigned int irq) +{ + int bit = irq - pci_int_base; + + *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); + return; +} + +static void m82xx_pci_mask_and_ack(unsigned int irq) +{ + int bit = irq - pci_int_base; + + *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); + return; +} + +static void m82xx_pci_end_irq(unsigned int irq) +{ + int bit = irq - pci_int_base; + + *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); + return; +} + +struct hw_interrupt_type m82xx_pci_ic = { + .typename = "MPC82xx ADS PCI", + .name = "MPC82xx ADS PCI", + .enable = m82xx_pci_unmask_irq, + .disable = m82xx_pci_mask_irq, + .ack = m82xx_pci_mask_and_ack, + .end = m82xx_pci_end_irq, + .mask = m82xx_pci_mask_irq, + .mask_ack = m82xx_pci_mask_and_ack, + .unmask = m82xx_pci_unmask_irq, + .eoi = m82xx_pci_end_irq, +}; + +static void +m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs) +{ + unsigned long stat, mask, pend; + int bit; + + for (;;) { + stat = *pci_regs.pci_int_stat_reg; + mask = *pci_regs.pci_int_mask_reg; + pend = stat & ~mask & 0xf0000000; + if (!pend) + break; + for (bit = 0; pend != 0; ++bit, pend <<= 1) { + if (pend & 0x80000000) + __do_IRQ(pci_int_base + bit, regs); + } + } +} + +static int pci_pic_host_match(struct irq_host *h, struct device_node *node) +{ + return node == pci_pic_node; +} + +static int pci_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip(virq, &m82xx_pci_ic); + return 0; +} + +static void pci_host_unmap(struct irq_host *h, unsigned int virq) +{ + /* remove chip and handler */ + set_irq_chip(virq, NULL); +} + +static struct irq_host_ops pci_pic_host_ops = { + .match = pci_pic_host_match, + .map = pci_pic_host_map, + .unmap = pci_host_unmap, +}; + +void m82xx_pci_init_irq(void) +{ + int irq; + cpm2_map_t *immap; + struct device_node *np; + struct resource r; + const u32 *regs; + unsigned int size; + const u32 *irq_map; + int i; + unsigned int irq_max, irq_min; + + if ((np = of_find_node_by_type(NULL, "soc")) == NULL) { + printk(KERN_INFO "No SOC node in device tree\n"); + return; + } + memset(&r, 0, sizeof(r)); + if (of_address_to_resource(np, 0, &r)) { + printk(KERN_INFO "No SOC reg property in device tree\n"); + return; + } + immap = ioremap(r.start, sizeof(*immap)); + of_node_put(np); + + /* install the demultiplexer for the PCI cascade interrupt */ + np = of_find_node_by_type(NULL, "pci"); + if (!np) { + printk(KERN_INFO "No pci node on device tree\n"); + iounmap(immap); + return; + } + irq_map = get_property(np, "interrupt-map", &size); + if ((!irq_map) || (size <= 7)) { + printk(KERN_INFO "No interrupt-map property of pci node\n"); + iounmap(immap); + return; + } + size /= sizeof(irq_map[0]); + for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) { + if (irq_map[5] < irq_min) + irq_min = irq_map[5]; + if (irq_map[5] > irq_max) + irq_max = irq_map[5]; + } + pci_int_base = irq_min; + irq = irq_of_parse_and_map(np, 0); + set_irq_chained_handler(irq, m82xx_pci_irq_demux); + of_node_put(np); + np = of_find_node_by_type(NULL, "pci-pic"); + if (!np) { + printk(KERN_INFO "No pci pic node on device tree\n"); + iounmap(immap); + return; + } + pci_pic_node = of_node_get(np); + /* PCI interrupt controller registers: status and mask */ + regs = get_property(np, "reg", &size); + if ((!regs) || (size <= 2)) { + printk(KERN_INFO "No reg property in pci pic node\n"); + iounmap(immap); + return; + } + pci_regs.pci_int_stat_reg = + ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg)); + pci_regs.pci_int_mask_reg = + ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg)); + of_node_put(np); + /* configure chip select for PCI interrupt controller */ + immap->im_memctl.memc_br3 = regs[0] | 0x00001801; + immap->im_memctl.memc_or3 = 0xffff8010; + /* make PCI IRQ level sensitive */ + immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1))); + + /* mask all PCI interrupts */ + *pci_regs.pci_int_mask_reg |= 0xfff00000; + iounmap(immap); + pci_pic_host = + irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1, + &pci_pic_host_ops, irq_max + 1); + return; +} + +static int m82xx_pci_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +static void +__init mpc82xx_pcibios_fixup(void) +{ + struct pci_dev *dev = NULL; + + for_each_pci_dev(dev) { + pci_read_irq_line(dev); + } +} + +void __init add_bridge(struct device_node *np) +{ + int len; + struct pci_controller *hose; + struct resource r; + const int *bus_range; + const void *ptr; + + memset(&r, 0, sizeof(r)); + if (of_address_to_resource(np, 0, &r)) { + printk(KERN_INFO "No PCI reg property in device tree\n"); + return; + } + if (!(ptr = get_property(np, "clock-frequency", NULL))) { + printk(KERN_INFO "No clock-frequency property in PCI node"); + return; + } + pci_clk_frq = *(uint *) ptr; + of_node_put(np); + bus_range = get_property(np, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume" + " bus 0\n", np->full_name); + } + + pci_assign_all_buses = 1; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->arch_data = np; + hose->set_cfg_type = 1; + + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->bus_offset = 0; + + hose->set_cfg_type = 1; + + setup_indirect_pci(hose, + r.start + offsetof(pci_cpm2_t, pci_cfg_addr), + r.start + offsetof(pci_cpm2_t, pci_cfg_data)); + + pci_process_bridge_OF_ranges(hose, np, 1); +} +#endif + +/* + * Setup the architecture + */ +static void __init mpc82xx_ads_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("mpc82xx_ads_setup_arch()", 0); + cpm2_reset(); + + /* Map I/O region to a 256MB BAT */ + + m82xx_board_setup(); + +#ifdef CONFIG_PCI + ppc_md.pci_exclude_device = m82xx_pci_exclude_device; + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + add_bridge(np); + + of_node_put(np); + ppc_md.pci_map_irq = NULL; + ppc_md.pcibios_fixup = mpc82xx_pcibios_fixup; + ppc_md.pcibios_fixup_bus = NULL; +#endif + +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + if (ppc_md.progress) + ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc82xx_ads_probe(void) +{ + /* We always match for now, eventually we should look at + * the flat dev tree to ensure this is the board we are + * supposed to run on + */ + return 1; +} + +#define RMR_CSRE 0x00000001 +static void m82xx_restart(char *cmd) +{ + __volatile__ unsigned char dummy; + + local_irq_disable(); + ((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE; + + /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */ + mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR)); + dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0]; + printk("Restart failed\n"); + while (1) ; +} + +static void m82xx_halt(void) +{ + local_irq_disable(); + while (1) ; +} + +define_machine(mpc82xx_ads) +{ + .name = "MPC82xx ADS", + .probe = mpc82xx_ads_probe, + .setup_arch = mpc82xx_ads_setup_arch, + .init_IRQ = mpc82xx_ads_pic_init, + .show_cpuinfo = mpc82xx_ads_show_cpuinfo, + .get_irq = cpm2_get_irq, + .calibrate_decr = m82xx_calibrate_decr, + .restart = m82xx_restart,.halt = m82xx_halt, +}; diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h new file mode 100644 index 00000000000..a7348213508 --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -0,0 +1,67 @@ +/* + * PQ2/mpc8260 board-specific stuff + * + * A collection of structures, addresses, and values associated with + * the Freescale MPC8260ADS/MPC8266ADS-PCI boards. + * Copied from the RPX-Classic and SBS8260 stuff. + * + * Author: Vitaly Bordug + * + * Originally written by Dan Malek for Motorola MPC8260 family + * + * Copyright (c) 2001 Dan Malek + * Copyright (c) 2006 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. + */ + +#ifdef __KERNEL__ +#ifndef __MACH_ADS8260_DEFS +#define __MACH_ADS8260_DEFS + +#include + +#include + +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Freescale Semiconductor" +#define CPUINFO_MACHINE "PQ2 ADS PowerPC" + +/* Backword-compatibility stuff for the drivers */ +#define CPM_MAP_ADDR ((uint)0xf0000000) +#define CPM_IRQ_OFFSET 0 + +/* The ADS8260 has 16, 32-bit wide control/status registers, accessed + * only on word boundaries. + * Not all are used (yet), or are interesting to us (yet). + */ + +/* Things of interest in the CSR. + */ +#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */ +#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */ +#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable*/ +#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */ +#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ +#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ +#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ +#define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */ + +/* cpm serial driver works with constants below */ + +#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) +#define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET) +#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) +#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) +#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) +#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) + +void m82xx_pci_init_irq(void); +void mpc82xx_ads_show_cpuinfo(struct seq_file*); +void m82xx_calibrate_decr(void); + +#endif /* __MACH_ADS8260_DEFS */ +#endif /* __KERNEL__ */ -- GitLab From 1516b55d903a5d370859d9013e48db5caea95204 Mon Sep 17 00:00:00 2001 From: Henne Date: Mon, 2 Oct 2006 14:56:23 +0200 Subject: [PATCH 0360/1619] [SCSI] scsi: Convertion to struct scsi_cmnd in ips-driver Converts the obsolete Scsi_Cmnd to struct scsi_cmnd in the ips-driver. Signed-off-by: Henrik Kretzschmar Signed-off-by: James Bottomley --- drivers/scsi/ips.c | 83 +++++++++++++++++++++------------------------- drivers/scsi/ips.h | 16 ++++----- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 58065ff6936..95b7536626f 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -250,9 +250,9 @@ module_param(ips, charp, 0); */ static int ips_detect(struct scsi_host_template *); static int ips_release(struct Scsi_Host *); -static int ips_eh_abort(Scsi_Cmnd *); -static int ips_eh_reset(Scsi_Cmnd *); -static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +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 int ips_hainit(ips_ha_t *); @@ -325,24 +325,26 @@ static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); static uint32_t ips_statupd_morpheus(ips_ha_t *); static ips_scb_t *ips_getscb(ips_ha_t *); static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); -static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); +static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *); static void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *); static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); -static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); -static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); +static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *); +static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *, + struct scsi_cmnd *); static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); -static int ips_is_passthru(Scsi_Cmnd *); -static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); +static int ips_is_passthru(struct scsi_cmnd *); +static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int); static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); -static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, +static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data, unsigned int count); -static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count); +static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data, + unsigned int count); static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); static int ips_host_info(ips_ha_t *, char *, off_t, int); @@ -812,8 +814,7 @@ ips_halt(struct notifier_block *nb, ulong event, void *buf) /* Abort a command (using the new error code stuff) */ /* Note: this routine is called under the io_request_lock */ /****************************************************************************/ -int -ips_eh_abort(Scsi_Cmnd * SC) +int ips_eh_abort(struct scsi_cmnd *SC) { ips_ha_t *ha; ips_copp_wait_item_t *item; @@ -871,8 +872,7 @@ ips_eh_abort(Scsi_Cmnd * SC) /* NOTE: this routine is called under the io_request_lock spinlock */ /* */ /****************************************************************************/ -static int -__ips_eh_reset(Scsi_Cmnd * SC) +static int __ips_eh_reset(struct scsi_cmnd *SC) { int ret; int i; @@ -968,7 +968,7 @@ __ips_eh_reset(Scsi_Cmnd * SC) ret = (*ha->func.reset) (ha); if (!ret) { - Scsi_Cmnd *scsi_cmd; + struct scsi_cmnd *scsi_cmd; IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Controller reset failed - controller now offline.\n"); @@ -997,7 +997,7 @@ __ips_eh_reset(Scsi_Cmnd * SC) } if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { - Scsi_Cmnd *scsi_cmd; + struct scsi_cmnd *scsi_cmd; IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Controller reset failed - controller now offline.\n"); @@ -1059,8 +1059,7 @@ __ips_eh_reset(Scsi_Cmnd * SC) } -static int -ips_eh_reset(Scsi_Cmnd * SC) +static int ips_eh_reset(struct scsi_cmnd *SC) { int rc; @@ -1083,8 +1082,7 @@ ips_eh_reset(Scsi_Cmnd * SC) /* Linux obtains io_request_lock before calling this function */ /* */ /****************************************************************************/ -static int -ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *)) +static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *)) { ips_ha_t *ha; ips_passthru_t *pt; @@ -1602,8 +1600,7 @@ ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, /* Determine if the specified SCSI command is really a passthru command */ /* */ /****************************************************************************/ -static int -ips_is_passthru(Scsi_Cmnd * SC) +static int ips_is_passthru(struct scsi_cmnd *SC) { unsigned long flags; @@ -1685,7 +1682,7 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length) /* */ /****************************************************************************/ static int -ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr) +ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr) { ips_passthru_t *pt; int length = 0; @@ -2734,9 +2731,9 @@ static void ips_next(ips_ha_t * ha, int intr) { ips_scb_t *scb; - Scsi_Cmnd *SC; - Scsi_Cmnd *p; - Scsi_Cmnd *q; + struct scsi_cmnd *SC; + struct scsi_cmnd *p; + struct scsi_cmnd *q; ips_copp_wait_item_t *item; int ret; unsigned long cpu_flags = 0; @@ -2847,7 +2844,7 @@ ips_next(ips_ha_t * ha, int intr) dcdb_active[scmd_channel(p) - 1] & (1 << scmd_id(p)))) { ips_freescb(ha, scb); - p = (Scsi_Cmnd *) p->host_scribble; + p = (struct scsi_cmnd *) p->host_scribble; continue; } @@ -2962,7 +2959,7 @@ ips_next(ips_ha_t * ha, int intr) break; } /* end case */ - p = (Scsi_Cmnd *) p->host_scribble; + p = (struct scsi_cmnd *) p->host_scribble; } /* end while */ @@ -3090,8 +3087,7 @@ ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static void -ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) +static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item) { METHOD_TRACE("ips_putq_wait_tail", 1); @@ -3122,10 +3118,9 @@ ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static Scsi_Cmnd * -ips_removeq_wait_head(ips_wait_queue_t * queue) +static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue) { - Scsi_Cmnd *item; + struct scsi_cmnd *item; METHOD_TRACE("ips_removeq_wait_head", 1); @@ -3135,7 +3130,7 @@ ips_removeq_wait_head(ips_wait_queue_t * queue) return (NULL); } - queue->head = (Scsi_Cmnd *) item->host_scribble; + queue->head = (struct scsi_cmnd *) item->host_scribble; item->host_scribble = NULL; if (queue->tail == item) @@ -3157,10 +3152,10 @@ ips_removeq_wait_head(ips_wait_queue_t * queue) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static Scsi_Cmnd * -ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) +static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue, + struct scsi_cmnd *item) { - Scsi_Cmnd *p; + struct scsi_cmnd *p; METHOD_TRACE("ips_removeq_wait", 1); @@ -3173,8 +3168,8 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) p = queue->head; - while ((p) && (item != (Scsi_Cmnd *) p->host_scribble)) - p = (Scsi_Cmnd *) p->host_scribble; + while ((p) && (item != (struct scsi_cmnd *) p->host_scribble)) + p = (struct scsi_cmnd *) p->host_scribble; if (p) { /* found a match */ @@ -3659,11 +3654,10 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) /* Routine Name: ips_scmd_buf_write */ /* */ /* Routine Description: */ -/* Write data to Scsi_Cmnd request_buffer at proper offsets */ +/* Write data to struct scsi_cmnd request_buffer at proper offsets */ /****************************************************************************/ static void -ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned - int count) +ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) { if (scmd->use_sg) { int i; @@ -3698,11 +3692,10 @@ ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned /* Routine Name: ips_scmd_buf_read */ /* */ /* Routine Description: */ -/* Copy data from a Scsi_Cmnd to a new, linear buffer */ +/* Copy data from a struct scsi_cmnd to a new, linear buffer */ /****************************************************************************/ static void -ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned - int count) +ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count) { if (scmd->use_sg) { int i; diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index f46c382e559..34680f3dd45 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -6,7 +6,7 @@ /* David Jeffery, Adaptec, Inc. */ /* */ /* Copyright (C) 1999 IBM Corporation */ -/* Copyright (C) 2003 Adaptec, Inc. */ +/* Copyright (C) 2003 Adaptec, 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 */ @@ -1033,14 +1033,14 @@ typedef struct ips_scb_queue { * Wait queue_format */ typedef struct ips_wait_queue { - Scsi_Cmnd *head; - Scsi_Cmnd *tail; - int count; + struct scsi_cmnd *head; + struct scsi_cmnd *tail; + int count; } ips_wait_queue_t; typedef struct ips_copp_wait_item { - Scsi_Cmnd *scsi_cmd; - struct ips_copp_wait_item *next; + struct scsi_cmnd *scsi_cmd; + struct ips_copp_wait_item *next; } ips_copp_wait_item_t; typedef struct ips_copp_queue { @@ -1149,7 +1149,7 @@ typedef struct ips_scb { uint32_t flags; uint32_t op_code; IPS_SG_LIST sg_list; - Scsi_Cmnd *scsi_cmd; + struct scsi_cmnd *scsi_cmd; struct ips_scb *q_next; ips_scb_callback callback; uint32_t sg_busaddr; @@ -1175,7 +1175,7 @@ typedef struct ips_scb_pt { uint32_t flags; uint32_t op_code; IPS_SG_LIST *sg_list; - Scsi_Cmnd *scsi_cmd; + struct scsi_cmnd *scsi_cmd; struct ips_scb *q_next; ips_scb_callback callback; } ips_scb_pt_t; -- GitLab From ee0ca6bab394fe41a2b4de58c4532b09a41c9165 Mon Sep 17 00:00:00 2001 From: Henne Date: Sun, 1 Oct 2006 13:18:37 +0200 Subject: [PATCH 0361/1619] [SCSI] scsi: Scsi_Cmnd convertion in arm subtree Changes the obsolete Scsi_Cmnd to struct scsi_cmnd in the arm subdir of the scsi-subsys. Signed-off-by: Henrik Kretzschmar Acked-by: Russell King Signed-off-by: James Bottomley --- drivers/scsi/arm/acornscsi.c | 48 +++++++++++++++++----------------- drivers/scsi/arm/acornscsi.h | 4 +-- drivers/scsi/arm/fas216.c | 50 +++++++++++++++++++----------------- drivers/scsi/arm/fas216.h | 36 ++++++++++++++------------ drivers/scsi/arm/queue.c | 37 +++++++++++++------------- drivers/scsi/arm/queue.h | 28 ++++++++++---------- drivers/scsi/arm/scsi.h | 2 +- 7 files changed, 108 insertions(+), 97 deletions(-) diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 7621e3fa37b..0525d672e1e 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -194,7 +194,8 @@ unsigned int sdtr_period = SDTR_PERIOD; unsigned int sdtr_size = SDTR_SIZE; -static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); +static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, + unsigned int result); static int acornscsi_reconnect_finish(AS_Host *host); static void acornscsi_dma_cleanup(AS_Host *host); static void acornscsi_abortcmd(AS_Host *host, unsigned char tag); @@ -712,7 +713,7 @@ static intr_ret_t acornscsi_kick(AS_Host *host) { int from_queue = 0; - Scsi_Cmnd *SCpnt; + struct scsi_cmnd *SCpnt; /* first check to see if a command is waiting to be executed */ SCpnt = host->origSCpnt; @@ -796,15 +797,15 @@ intr_ret_t acornscsi_kick(AS_Host *host) } /* - * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) + * Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result) * Purpose : complete processing for command * Params : host - interface that completed * result - driver byte of result */ -static -void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) +static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, + unsigned int result) { - Scsi_Cmnd *SCpnt = *SCpntp; + struct scsi_cmnd *SCpnt = *SCpntp; /* clean up */ sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP); @@ -1318,7 +1319,7 @@ acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int static void acornscsi_sendcommand(AS_Host *host) { - Scsi_Cmnd *SCpnt = host->SCpnt; + struct scsi_cmnd *SCpnt = host->SCpnt; sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0); sbic_arm_writenext(host->scsi.io_port, 0); @@ -1693,7 +1694,7 @@ void acornscsi_message(AS_Host *host) acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } else { - Scsi_Cmnd *SCpnt = host->SCpnt; + struct scsi_cmnd *SCpnt = host->SCpnt; acornscsi_dma_cleanup(host); @@ -2509,13 +2510,14 @@ acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) */ /* - * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + * Function : acornscsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) * Purpose : queues a SCSI command * Params : cmd - SCSI command * done - function called on completion, with pointer to command descriptor * Returns : 0, or < 0 on error. */ -int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +int acornscsi_queuecmd(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata; @@ -2565,17 +2567,18 @@ int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } /* - * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) + * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result) * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 * Params : SCpntp1 - pointer to command to return * SCpntp2 - pointer to command to check * result - result to pass back to mid-level done function * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. */ -static inline -void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) +static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, + struct scsi_cmnd **SCpntp2, + int result) { - Scsi_Cmnd *SCpnt = *SCpntp1; + struct scsi_cmnd *SCpnt = *SCpntp1; if (SCpnt) { *SCpntp1 = NULL; @@ -2591,13 +2594,12 @@ void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result enum res_abort { res_not_running, res_success, res_success_clear, res_snooze }; /* - * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt) + * Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt) * Purpose : abort a command on this host * Params : SCpnt - command to abort * Returns : our abort status */ -static enum res_abort -acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) +static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt) { enum res_abort res = res_not_running; @@ -2684,12 +2686,12 @@ acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) } /* - * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt) + * Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt) * Purpose : abort a command on this host * Params : SCpnt - command to abort * Returns : one of SCSI_ABORT_ macros */ -int acornscsi_abort(Scsi_Cmnd *SCpnt) +int acornscsi_abort(struct scsi_cmnd *SCpnt) { AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata; int result; @@ -2770,16 +2772,16 @@ int acornscsi_abort(Scsi_Cmnd *SCpnt) } /* - * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags) * Purpose : reset a command on this host/reset this host * Params : SCpnt - command causing reset * result - what type of reset to perform * Returns : one of SCSI_RESET_ macros */ -int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags) { - AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata; - Scsi_Cmnd *SCptr; + AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata; + struct scsi_cmnd *SCptr; host->stats.resets += 1; diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h index 2142290f840..d11424b89f4 100644 --- a/drivers/scsi/arm/acornscsi.h +++ b/drivers/scsi/arm/acornscsi.h @@ -277,8 +277,8 @@ struct status_entry { typedef struct acornscsi_hostdata { /* miscellaneous */ struct Scsi_Host *host; /* host */ - Scsi_Cmnd *SCpnt; /* currently processing command */ - Scsi_Cmnd *origSCpnt; /* original connecting command */ + struct scsi_cmnd *SCpnt; /* currently processing command */ + struct scsi_cmnd *origSCpnt; /* original connecting command */ /* driver information */ struct { diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 4cf7afc31cc..e05f0c2fc91 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -297,8 +297,8 @@ fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap) printk("scsi%d.%c: %s", info->host->host_no, target, buf); } -static void -fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...) +static void fas216_log_command(FAS216_Info *info, int level, + struct scsi_cmnd *SCpnt, char *fmt, ...) { va_list args; @@ -1662,7 +1662,7 @@ irqreturn_t fas216_intr(FAS216_Info *info) return handled; } -static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) +static void __fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt) { int tot_msglen; @@ -1754,7 +1754,7 @@ static int parity_test(FAS216_Info *info, int target) return info->device[target].parity_check; } -static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) +static void fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt) { int disconnect_ok; @@ -1808,7 +1808,7 @@ static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) __fas216_start_command(info, SCpnt); } -static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt) +static void fas216_allocate_tag(FAS216_Info *info, struct scsi_cmnd *SCpnt) { #ifdef SCSI2_TAG /* @@ -1842,7 +1842,8 @@ static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt) } } -static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt) +static void fas216_do_bus_device_reset(FAS216_Info *info, + struct scsi_cmnd *SCpnt) { struct message *msg; @@ -1890,7 +1891,7 @@ static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt) */ static void fas216_kick(FAS216_Info *info) { - Scsi_Cmnd *SCpnt = NULL; + struct scsi_cmnd *SCpnt = NULL; #define TYPE_OTHER 0 #define TYPE_RESET 1 #define TYPE_QUEUE 2 @@ -1978,8 +1979,8 @@ static void fas216_kick(FAS216_Info *info) /* * Clean up from issuing a BUS DEVICE RESET message to a device. */ -static void -fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) +static void fas216_devicereset_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, + unsigned int result) { fas216_log(info, LOG_ERROR, "fas216 device reset complete"); @@ -1996,8 +1997,8 @@ fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result * * Finish processing automatic request sense command */ -static void -fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) +static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, + unsigned int result) { fas216_log_target(info, LOG_CONNECT, SCpnt->device->id, "request sense complete, result=0x%04x%02x%02x", @@ -2030,7 +2031,7 @@ fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) * Finish processing of standard command */ static void -fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) +fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result) { info->stats.fins += 1; @@ -2142,8 +2143,8 @@ request_sense: */ static void fas216_done(FAS216_Info *info, unsigned int result) { - void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int); - Scsi_Cmnd *SCpnt; + void (*fn)(FAS216_Info *, struct scsi_cmnd *, unsigned int); + struct scsi_cmnd *SCpnt; unsigned long flags; fas216_checkmagic(info); @@ -2182,7 +2183,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result) info->device[SCpnt->device->id].parity_check = 0; clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns); - fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble; + fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble; fn(info, SCpnt, result); if (info->scsi.irq != NO_IRQ) { @@ -2207,7 +2208,8 @@ no_command: * Returns: 0 on success, else error. * Notes: io_request_lock is held, interrupts are disabled. */ -int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +int fas216_queue_command(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; int result; @@ -2254,7 +2256,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) * * Trigger restart of a waiting thread in fas216_command */ -static void fas216_internal_done(Scsi_Cmnd *SCpnt) +static void fas216_internal_done(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; @@ -2271,7 +2273,8 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt) * Returns: scsi result code. * Notes: io_request_lock is held, interrupts are disabled. */ -int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +int fas216_noqueue_command(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; @@ -2350,7 +2353,8 @@ enum res_find { * Decide how to abort a command. * Returns: abort status */ -static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) +static enum res_find fas216_find_command(FAS216_Info *info, + struct scsi_cmnd *SCpnt) { enum res_find res = res_failed; @@ -2417,7 +2421,7 @@ static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) * Returns: FAILED if unable to abort * Notes: io_request_lock is taken, and irqs are disabled */ -int fas216_eh_abort(Scsi_Cmnd *SCpnt) +int fas216_eh_abort(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; int result = FAILED; @@ -2474,7 +2478,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt) * Notes: We won't be re-entered, so we'll only have one device * reset on the go at one time. */ -int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) +int fas216_eh_device_reset(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; unsigned long flags; @@ -2555,7 +2559,7 @@ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) * Returns: FAILED if unable to reset. * Notes: Further commands are blocked. */ -int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) +int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; unsigned long flags; @@ -2655,7 +2659,7 @@ static void fas216_init_chip(FAS216_Info *info) * Returns: FAILED if unable to reset. * Notes: io_request_lock is taken, and irqs are disabled */ -int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) +int fas216_eh_host_reset(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 540914d6fd3..00e5f055afd 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -218,11 +218,11 @@ typedef struct { unsigned long magic_start; spinlock_t host_lock; struct Scsi_Host *host; /* host */ - Scsi_Cmnd *SCpnt; /* currently processing command */ - Scsi_Cmnd *origSCpnt; /* original connecting command */ - Scsi_Cmnd *reqSCpnt; /* request sense command */ - Scsi_Cmnd *rstSCpnt; /* reset command */ - Scsi_Cmnd *pending_SCpnt[8]; /* per-device pending commands */ + struct scsi_cmnd *SCpnt; /* currently processing command */ + struct scsi_cmnd *origSCpnt; /* original connecting command */ + struct scsi_cmnd *reqSCpnt; /* request sense command */ + struct scsi_cmnd *rstSCpnt; /* reset command */ + struct scsi_cmnd *pending_SCpnt[8]; /* per-device pending commands */ int next_pending; /* next pending device */ /* @@ -328,21 +328,23 @@ extern int fas216_init (struct Scsi_Host *instance); */ extern int fas216_add (struct Scsi_Host *instance, struct device *dev); -/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) * Purpose : queue a command for adapter to process. * Params : SCpnt - Command to queue * done - done function to call once command is complete * Returns : 0 - success, else error */ -extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int fas216_queue_command(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); -/* Function: int fas216_noqueue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) * Purpose : queue a command for adapter to process, and process it to completion. * Params : SCpnt - Command to queue * done - done function to call once command is complete * Returns : 0 - success, else error */ -extern int fas216_noqueue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int fas216_noqueue_command(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command @@ -363,32 +365,32 @@ extern int fas216_print_host(FAS216_Info *info, char *buffer); extern int fas216_print_stats(FAS216_Info *info, char *buffer); extern int fas216_print_devices(FAS216_Info *info, char *buffer); -/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt) +/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt) * Purpose : abort this command * Params : SCpnt - command to abort * Returns : FAILED if unable to abort */ -extern int fas216_eh_abort(Scsi_Cmnd *SCpnt); +extern int fas216_eh_abort(struct scsi_cmnd *SCpnt); -/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) +/* Function: int fas216_eh_device_reset(struct scsi_cmnd *SCpnt) * Purpose : Reset the device associated with this command * Params : SCpnt - command specifing device to reset * Returns : FAILED if unable to reset */ -extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt); +extern int fas216_eh_device_reset(struct scsi_cmnd *SCpnt); -/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) +/* Function: int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt) * Purpose : Reset the complete bus associated with this command * Params : SCpnt - command specifing bus to reset * Returns : FAILED if unable to reset */ -extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt); +extern int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt); -/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) +/* Function: int fas216_eh_host_reset(struct scsi_cmnd *SCpnt) * Purpose : Reset the host associated with this command * Params : SCpnt - command specifing host to reset * Returns : FAILED if unable to reset */ -extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt); +extern int fas216_eh_host_reset(struct scsi_cmnd *SCpnt); #endif /* FAS216_H */ diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c index 8caa5903ce3..cb11ccef54e 100644 --- a/drivers/scsi/arm/queue.c +++ b/drivers/scsi/arm/queue.c @@ -29,7 +29,7 @@ typedef struct queue_entry { struct list_head list; - Scsi_Cmnd *SCpnt; + struct scsi_cmnd *SCpnt; #ifdef DEBUG unsigned long magic; #endif @@ -96,14 +96,14 @@ void queue_free (Queue_t *queue) /* - * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head) + * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head) * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head. * Params : queue - destination queue * SCpnt - command to add * head - add command to head of queue * Returns : 0 on error, !0 on success */ -int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head) +int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head) { unsigned long flags; struct list_head *l; @@ -134,7 +134,7 @@ empty: return ret; } -static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent) +static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent) { QE_t *q; @@ -152,17 +152,17 @@ static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent) } /* - * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude) + * Function: struct scsi_cmnd *queue_remove_exclude (queue, exclude) * Purpose : remove a SCSI command from a queue * Params : queue - queue to remove command from * exclude - bit array of target&lun which is busy - * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available */ -Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude) +struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude) { unsigned long flags; struct list_head *l; - Scsi_Cmnd *SCpnt = NULL; + struct scsi_cmnd *SCpnt = NULL; spin_lock_irqsave(&queue->queue_lock, flags); list_for_each(l, &queue->head) { @@ -178,15 +178,15 @@ Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude) } /* - * Function: Scsi_Cmnd *queue_remove (queue) + * Function: struct scsi_cmnd *queue_remove (queue) * Purpose : removes first SCSI command from a queue * Params : queue - queue to remove command from - * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available */ -Scsi_Cmnd *queue_remove(Queue_t *queue) +struct scsi_cmnd *queue_remove(Queue_t *queue) { unsigned long flags; - Scsi_Cmnd *SCpnt = NULL; + struct scsi_cmnd *SCpnt = NULL; spin_lock_irqsave(&queue->queue_lock, flags); if (!list_empty(&queue->head)) @@ -197,19 +197,20 @@ Scsi_Cmnd *queue_remove(Queue_t *queue) } /* - * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) + * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag) * Purpose : remove a SCSI command from the queue for a specified target/lun/tag * Params : queue - queue to remove command from * target - target that we want * lun - lun on device * tag - tag on device - * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements + * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements */ -Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag) +struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun, + int tag) { unsigned long flags; struct list_head *l; - Scsi_Cmnd *SCpnt = NULL; + struct scsi_cmnd *SCpnt = NULL; spin_lock_irqsave(&queue->queue_lock, flags); list_for_each(l, &queue->head) { @@ -275,13 +276,13 @@ int queue_probetgtlun (Queue_t *queue, int target, int lun) } /* - * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt) + * Function: int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt) * Purpose : remove a specific command from the queues * Params : queue - queue to look in * SCpnt - command to find * Returns : 0 if not found */ -int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt) +int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt) { unsigned long flags; struct list_head *l; diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h index 0c9dec4c171..3c519c9237b 100644 --- a/drivers/scsi/arm/queue.h +++ b/drivers/scsi/arm/queue.h @@ -32,46 +32,48 @@ extern int queue_initialise (Queue_t *queue); extern void queue_free (Queue_t *queue); /* - * Function: Scsi_Cmnd *queue_remove (queue) + * Function: struct scsi_cmnd *queue_remove (queue) * Purpose : removes first SCSI command from a queue * Params : queue - queue to remove command from - * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available */ -extern Scsi_Cmnd *queue_remove (Queue_t *queue); +extern struct scsi_cmnd *queue_remove (Queue_t *queue); /* - * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude) + * Function: struct scsi_cmnd *queue_remove_exclude_ref (queue, exclude) * Purpose : remove a SCSI command from a queue * Params : queue - queue to remove command from * exclude - array of busy LUNs - * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available */ -extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude); +extern struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, + unsigned long *exclude); #define queue_add_cmd_ordered(queue,SCpnt) \ __queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE) #define queue_add_cmd_tail(queue,SCpnt) \ __queue_add(queue,SCpnt,0) /* - * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head) + * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head) * Purpose : Add a new command onto a queue * Params : queue - destination queue * SCpnt - command to add * head - add command to head of queue * Returns : 0 on error, !0 on success */ -extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head); +extern int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head); /* - * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) + * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag) * Purpose : remove a SCSI command from the queue for a specified target/lun/tag * Params : queue - queue to remove command from * target - target that we want * lun - lun on device * tag - tag on device - * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements + * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements */ -extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag); +extern struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, + int lun, int tag); /* * Function: queue_remove_all_target(queue, target) @@ -94,12 +96,12 @@ extern void queue_remove_all_target(Queue_t *queue, int target); extern int queue_probetgtlun (Queue_t *queue, int target, int lun); /* - * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Function: int queue_remove_cmd (Queue_t *queue, struct scsi_cmnd *SCpnt) * Purpose : remove a specific command from the queues * Params : queue - queue to look in * SCpnt - command to find * Returns : 0 if not found */ -int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt); +int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt); #endif /* QUEUE_H */ diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 8c2600ffc6a..3a39579bd08 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -66,7 +66,7 @@ static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c) SCp->this_residual -= 1; } -static inline void init_SCp(Scsi_Cmnd *SCpnt) +static inline void init_SCp(struct scsi_cmnd *SCpnt) { memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer)); -- GitLab From d8b4521349274ab610d0b29384c704444e55cbca Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:43 -0700 Subject: [PATCH 0362/1619] [SCSI] qla2xxx: Add iIDMA support. iIDMA (Intelligent Interleaved Direct Memory Access) allows for the HBA hardware to send FC frames at the rate at which they can be received by a target device. By taking advantage of the higher link rate, the HBA can maximize bandwidth utilization in a heterogeneous multi-speed SAN. Within a fabric topology, port speed detection is done via a Name Server command (GFPN_ID) followed by a Fabric Management command (GPSC). In an FCAL/N2N topology, port speed is based on the HBA link-rate. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 6 +- drivers/scsi/qla2xxx/qla_def.h | 39 ++++++- drivers/scsi/qla2xxx/qla_gbl.h | 8 ++ drivers/scsi/qla2xxx/qla_gs.c | 187 +++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_init.c | 81 ++++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 4 +- drivers/scsi/qla2xxx/qla_mbx.c | 86 +++++++++++++++ drivers/scsi/qla2xxx/qla_os.c | 2 +- 8 files changed, 401 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 87f90c4f08e..144b0f8459c 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -691,13 +691,13 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) uint32_t speed = 0; switch (ha->link_data_rate) { - case LDR_1GB: + case PORT_SPEED_1GB: speed = 1; break; - case LDR_2GB: + case PORT_SPEED_2GB: speed = 2; break; - case LDR_4GB: + case PORT_SPEED_4GB: speed = 4; break; } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 0930260aec2..6d677b0fb55 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -608,6 +608,7 @@ typedef struct { */ #define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */ #define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */ +#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */ #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ #define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ @@ -1497,6 +1498,9 @@ typedef struct { port_id_t d_id; uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; + uint8_t fabric_port_name[WWN_SIZE]; + uint16_t fp_speeds; + uint16_t fp_speed; } sw_info_t; /* @@ -1524,6 +1528,9 @@ typedef struct fc_port { uint16_t loop_id; uint16_t old_loop_id; + uint8_t fabric_port_name[WWN_SIZE]; + uint16_t fp_speed; + fc_port_type_t port_type; atomic_t state; @@ -1635,6 +1642,15 @@ typedef struct fc_port { #define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255) #define RSNN_NN_RSP_SIZE 16 +#define GFPN_ID_CMD 0x11C +#define GFPN_ID_REQ_SIZE (16 + 4) +#define GFPN_ID_RSP_SIZE (16 + 8) + +#define GPSC_CMD 0x127 +#define GPSC_REQ_SIZE (16 + 8) +#define GPSC_RSP_SIZE (16 + 2 + 2) + + /* * HBA attribute types. */ @@ -1748,7 +1764,7 @@ struct ct_sns_req { uint8_t reserved[3]; union { - /* GA_NXT, GPN_ID, GNN_ID, GFT_ID */ + /* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */ struct { uint8_t reserved; uint8_t port_id[3]; @@ -1823,6 +1839,10 @@ struct ct_sns_req { struct { uint8_t port_name[8]; } dpa; + + struct { + uint8_t port_name[8]; + } gpsc; } req; }; @@ -1886,6 +1906,15 @@ struct ct_sns_rsp { uint8_t port_name[8]; struct ct_fdmi_hba_attributes attrs; } ghat; + + struct { + uint8_t port_name[8]; + } gfpn_id; + + struct { + uint16_t speeds; + uint16_t speed; + } gpsc; } rsp; }; @@ -2182,11 +2211,11 @@ typedef struct scsi_qla_host { uint16_t max_public_loop_ids; uint16_t min_external_loopid; /* First external loop Id */ +#define PORT_SPEED_UNKNOWN 0xFFFF +#define PORT_SPEED_1GB 0x00 +#define PORT_SPEED_2GB 0x01 +#define PORT_SPEED_4GB 0x03 uint16_t link_data_rate; /* F/W operating speed */ -#define LDR_1GB 0 -#define LDR_2GB 1 -#define LDR_4GB 3 -#define LDR_UNKNOWN 0xFFFF uint8_t current_topology; uint8_t prev_topology; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 8311ac2b93a..c48e1d8bb10 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -208,6 +208,12 @@ qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t); extern int qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); +extern int +qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *); + +extern int +qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -279,6 +285,8 @@ extern int qla2x00_rsnn_nn(scsi_qla_host_t *); extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); +extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); +extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); /* * Global Function Prototypes in qla_attr.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 2ebf259fccb..029953c1a9c 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -687,7 +687,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha) return (rval); } - /** * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. * @ha: HA context @@ -1647,3 +1646,189 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha) return rval; } + +/** + * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query. + * @ha: HA context + * @list: switch info entries to populate + * + * Returns 0 on success. + */ +int +qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + /* Issue GFPN_ID */ + memset(list[i].fabric_port_name, 0, WWN_SIZE); + + /* Prepare common MS IOCB */ + ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE, + GFPN_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD, + GFPN_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id */ + ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; + ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; + ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB " + "failed (%d).\n", ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, + "GFPN_ID") != QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + /* Save fabric portname */ + memcpy(list[i].fabric_port_name, + ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE); + } + + /* Last device exit. */ + if (list[i].d_id.b.rsvd_1 != 0) + break; + } + + return (rval); +} + +static inline void * +qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + struct ct_entry_24xx *ct_pkt; + + ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); + + ct_pkt->entry_type = CT_IOCB_TYPE; + ct_pkt->entry_count = 1; + ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); + ct_pkt->timeout = __constant_cpu_to_le16(59); + ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + + ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + + ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + + return ct_pkt; +} + + +static inline struct ct_sns_req * +qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd, + uint16_t rsp_size) +{ + memset(ct_req, 0, sizeof(struct ct_sns_pkt)); + + ct_req->header.revision = 0x01; + ct_req->header.gs_type = 0xFA; + ct_req->header.gs_subtype = 0x01; + ct_req->command = cpu_to_be16(cmd); + ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); + + return ct_req; +} + +/** + * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. + * @ha: HA context + * @list: switch info entries to populate + * + * Returns 0 on success. + */ +int +qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + rval = qla2x00_mgmt_svr_login(ha); + if (rval) + return rval; + + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + /* Issue GFPN_ID */ + list[i].fp_speeds = list[i].fp_speed = 0; + + /* Prepare common MS IOCB */ + ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE, + GPSC_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req, + GPSC_CMD, GPSC_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_name */ + memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name, + WWN_SIZE); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB " + "failed (%d).\n", ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, + "GPSC") != QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + /* Save portname */ + list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds; + list[i].fp_speed = ct_rsp->rsp.gpsc.speed; + + DEBUG2_3(printk("scsi(%ld): GPSC ext entry - " + "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x " + "speed=%04x.\n", ha->host_no, + list[i].fabric_port_name[0], + list[i].fabric_port_name[1], + list[i].fabric_port_name[2], + list[i].fabric_port_name[3], + list[i].fabric_port_name[4], + list[i].fabric_port_name[5], + list[i].fabric_port_name[6], + list[i].fabric_port_name[7], + be16_to_cpu(list[i].fp_speeds), + be16_to_cpu(list[i].fp_speed))); + } + + /* Last device exit. */ + if (list[i].d_id.b.rsvd_1 != 0) + break; + } + + return (rval); +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 859649160ca..270096441f3 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2074,6 +2074,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) new_fcport->flags &= ~FCF_FABRIC_DEVICE; } + /* Base iIDMA settings on HBA port speed. */ + switch (ha->link_data_rate) { + case PORT_SPEED_1GB: + fcport->fp_speed = cpu_to_be16(BIT_15); + break; + case PORT_SPEED_2GB: + fcport->fp_speed = cpu_to_be16(BIT_14); + break; + case PORT_SPEED_4GB: + fcport->fp_speed = cpu_to_be16(BIT_13); + break; + } + qla2x00_update_fcport(ha, fcport); found_devs++; @@ -2109,6 +2122,62 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha) } } +static void +qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) +{ +#define LS_UNKNOWN 2 + static char *link_speeds[5] = { "1", "2", "?", "4" }; + int rval; + uint16_t port_speed, mb[6]; + + if (!IS_QLA24XX(ha)) + return; + + switch (be16_to_cpu(fcport->fp_speed)) { + case BIT_15: + port_speed = PORT_SPEED_1GB; + break; + case BIT_14: + port_speed = PORT_SPEED_2GB; + break; + case BIT_13: + port_speed = PORT_SPEED_4GB; + break; + default: + DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- " + "unsupported FM port operating speed (%04x).\n", + ha->host_no, fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7], + be16_to_cpu(fcport->fp_speed))); + port_speed = PORT_SPEED_UNKNOWN; + break; + } + if (port_speed == PORT_SPEED_UNKNOWN) + return; + + rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb); + if (rval != QLA_SUCCESS) { + DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA " + "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n", + ha->host_no, fcport->port_name[0], fcport->port_name[1], + fcport->port_name[2], fcport->port_name[3], + fcport->port_name[4], fcport->port_name[5], + fcport->port_name[6], fcport->port_name[7], rval, + port_speed, mb[0], mb[1])); + } else { + DEBUG2(qla_printk(KERN_INFO, ha, + "iIDMA adjusted to %s GB/s on " + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", + link_speeds[port_speed], fcport->port_name[0], + fcport->port_name[1], fcport->port_name[2], + fcport->port_name[3], fcport->port_name[4], + fcport->port_name[5], fcport->port_name[6], + fcport->port_name[7])); + } +} + /* * qla2x00_update_fcport * Updates device on list. @@ -2135,6 +2204,8 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) PORT_RETRY_TIME); fcport->flags &= ~FCF_LOGIN_NEEDED; + qla2x00_iidma_fcport(ha, fcport); + atomic_set(&fcport->state, FCS_ONLINE); if (ha->flags.init_done) @@ -2416,6 +2487,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) { kfree(swl); swl = NULL; + } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) { + qla2x00_gpsc(ha, swl); } } swl_idx = 0; @@ -2450,6 +2523,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) swl[swl_idx].node_name, WWN_SIZE); memcpy(new_fcport->port_name, swl[swl_idx].port_name, WWN_SIZE); + memcpy(new_fcport->fabric_port_name, + swl[swl_idx].fabric_port_name, WWN_SIZE); + new_fcport->fp_speed = swl[swl_idx].fp_speed; if (swl[swl_idx].d_id.b.rsvd_1 != 0) { last_dev = 1; @@ -2507,6 +2583,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) found++; + /* Update port state. */ + memcpy(fcport->fabric_port_name, + new_fcport->fabric_port_name, WWN_SIZE); + fcport->fp_speed = new_fcport->fp_speed; + /* * If address the same and state FCS_ONLINE, nothing * changed. diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index de0613135f7..5fa933cda99 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -400,7 +400,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) case MBA_LOOP_UP: /* Loop Up Event */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) { link_speed = link_speeds[0]; - ha->link_data_rate = LDR_1GB; + ha->link_data_rate = PORT_SPEED_1GB; } else { link_speed = link_speeds[LS_UNKNOWN]; if (mb[1] < 5) @@ -429,7 +429,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) } ha->flags.management_server_logged_in = 0; - ha->link_data_rate = LDR_UNKNOWN; + ha->link_data_rate = PORT_SPEED_UNKNOWN; if (ql2xfdmienable) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); break; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 879f281e2ea..4cde76c85cb 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2540,3 +2540,89 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, return rval; } + +int +qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, + uint16_t *port_speed, uint16_t *mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_PORT_PARAMS; + mcp->mb[1] = loop_id; + mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0; + mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox statuses. */ + if (mb != NULL) { + mb[0] = mcp->mb[0]; + mb[1] = mcp->mb[1]; + mb[3] = mcp->mb[3]; + mb[4] = mcp->mb[4]; + mb[5] = mcp->mb[5]; + } + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + if (port_speed) + *port_speed = mcp->mb[3]; + } + + return rval; +} + +int +qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, + uint16_t port_speed, uint16_t *mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_PORT_PARAMS; + mcp->mb[1] = loop_id; + mcp->mb[2] = BIT_0; + mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); + mcp->mb[4] = mcp->mb[5] = 0; + mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox statuses. */ + if (mb != NULL) { + mb[0] = mcp->mb[0]; + mb[1] = mcp->mb[1]; + mb[3] = mcp->mb[3]; + mb[4] = mcp->mb[4]; + mb[5] = mcp->mb[5]; + } + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 65cbe2f5eea..9e665e1281c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1385,7 +1385,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->prev_topology = 0; ha->init_cb_size = sizeof(init_cb_t); ha->mgmt_svr_loop_id = MANAGEMENT_SERVER; - ha->link_data_rate = LDR_UNKNOWN; + ha->link_data_rate = PORT_SPEED_UNKNOWN; ha->optrom_size = OPTROM_SIZE_2300; /* Assign ISP specific operations. */ -- GitLab From 1620f7c2d8e3fdd7dba04bfe5f9c42201eef1188 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:44 -0700 Subject: [PATCH 0363/1619] [SCSI] qla2xxx: Add support for symbolic nodename FC transport attribute. Refactored original code from qla_gs.c:qla2x00_rsnn_nn(). Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 10 ++++++++++ drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_gs.c | 26 +++++++++++--------------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 144b0f8459c..463846942e1 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -849,6 +849,14 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) return pfc_host_stat; } +static void +qla2x00_get_host_symbolic_name(struct Scsi_Host *shost) +{ + scsi_qla_host_t *ha = to_qla_host(shost); + + qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost)); +} + struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, @@ -861,6 +869,8 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_speed = 1, .get_host_port_type = qla2x00_get_host_port_type, .show_host_port_type = 1, + .get_host_symbolic_name = qla2x00_get_host_symbolic_name, + .show_host_symbolic_name = 1, .dd_fcrport_size = sizeof(struct fc_port *), .show_rport_supported_classes = 1, diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index c48e1d8bb10..bef7011378c 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -287,6 +287,7 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); +extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *); /* * Global Function Prototypes in qla_attr.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 029953c1a9c..225cf724dcf 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -612,6 +612,14 @@ qla2x00_rnn_id(scsi_qla_host_t *ha) return (rval); } +void +qla2x00_get_sym_node_name(scsi_qla_host_t *ha, uint8_t *snn) +{ + sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number, + ha->fw_major_version, ha->fw_minor_version, + ha->fw_subminor_version, qla2x00_version_str); +} + /** * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA. * @ha: HA context @@ -622,9 +630,6 @@ int qla2x00_rsnn_nn(scsi_qla_host_t *ha) { int rval; - uint8_t *snn; - uint8_t version[20]; - ms_iocb_entry_t *ms_pkt; struct ct_sns_req *ct_req; struct ct_sns_rsp *ct_rsp; @@ -649,20 +654,11 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha) memcpy(ct_req->req.rsnn_nn.node_name, ha->node_name, WWN_SIZE); /* Prepare the Symbolic Node Name */ - /* Board type */ - snn = ct_req->req.rsnn_nn.sym_node_name; - strcpy(snn, ha->model_number); - /* Firmware version */ - strcat(snn, " FW:v"); - sprintf(version, "%d.%02d.%02d", ha->fw_major_version, - ha->fw_minor_version, ha->fw_subminor_version); - strcat(snn, version); - /* Driver version */ - strcat(snn, " DVR:v"); - strcat(snn, qla2x00_version_str); + qla2x00_get_sym_node_name(ha, ct_req->req.rsnn_nn.sym_node_name); /* Calculate SNN length */ - ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn); + ct_req->req.rsnn_nn.name_len = + (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name); /* Update MS IOCB request */ ms_pkt->req_bytecount = -- GitLab From a740a3f0407ed3344b28b05926b0ce61768e9893 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:45 -0700 Subject: [PATCH 0364/1619] [SCSI] qla2xxx: Add support for system hostname FC transport attribute. The system hostname will be used during a subsequent FDMI registration with the fabric. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 10 ++++++++++ drivers/scsi/qla2xxx/qla_gs.c | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 463846942e1..4e1e175cb9d 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -857,6 +857,14 @@ qla2x00_get_host_symbolic_name(struct Scsi_Host *shost) qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost)); } +static void +qla2x00_set_host_system_hostname(struct Scsi_Host *shost) +{ + scsi_qla_host_t *ha = to_qla_host(shost); + + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); +} + struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, @@ -871,6 +879,8 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_port_type = 1, .get_host_symbolic_name = qla2x00_get_host_symbolic_name, .show_host_symbolic_name = 1, + .set_host_system_hostname = qla2x00_set_host_system_hostname, + .show_host_system_hostname = 1, .dd_fcrport_size = sizeof(struct fc_port *), .show_rport_supported_classes = 1, diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 225cf724dcf..97fbc62ec66 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1580,6 +1580,21 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha) DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no, eiter->a.os_dev_name)); + /* Hostname. */ + if (strlen(fc_host_system_hostname(ha->host))) { + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME); + snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), + "%s", fc_host_system_hostname(ha->host)); + alen = strlen(eiter->a.host_name); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__, + ha->host_no, eiter->a.host_name)); + } + /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(ha, size + 16); -- GitLab From 90991c85d398fd46b2b07440b5639eb50dfacb2b Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:46 -0700 Subject: [PATCH 0365/1619] [SCSI] qla2xxx: Add support for fabric name FC transport attribute. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 16 ++++++++++++++++ drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 4e1e175cb9d..d4cf51a8796 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -865,6 +865,20 @@ qla2x00_set_host_system_hostname(struct Scsi_Host *shost) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); } +static void +qla2x00_get_host_fabric_name(struct Scsi_Host *shost) +{ + scsi_qla_host_t *ha = to_qla_host(shost); + u64 node_name; + + if (ha->device_flags & SWITCH_FOUND) + node_name = wwn_to_u64(ha->fabric_node_name); + else + node_name = wwn_to_u64(ha->node_name); + + fc_host_fabric_name(shost) = node_name; +} + struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, @@ -881,6 +895,8 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_symbolic_name = 1, .set_host_system_hostname = qla2x00_set_host_system_hostname, .show_host_system_hostname = 1, + .get_host_fabric_name = qla2x00_get_host_fabric_name, + .show_host_fabric_name = 1, .dd_fcrport_size = sizeof(struct fc_port *), .show_rport_supported_classes = 1, diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6d677b0fb55..c37a30aa214 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2362,6 +2362,7 @@ typedef struct scsi_qla_host { uint8_t *node_name; uint8_t *port_name; + uint8_t fabric_node_name[WWN_SIZE]; uint32_t isp_abort_cnt; /* Option ROM information. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 270096441f3..d5d26273c04 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2280,7 +2280,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) loop_id = NPH_F_PORT; else loop_id = SNS_FL_PORT; - rval = qla2x00_get_port_name(ha, loop_id, NULL, 0); + rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1); if (rval != QLA_SUCCESS) { DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL " "Port\n", ha->host_no)); @@ -2288,6 +2288,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) ha->device_flags &= ~SWITCH_FOUND; return (QLA_SUCCESS); } + ha->device_flags |= SWITCH_FOUND; /* Mark devices that need re-synchronization. */ rval2 = qla2x00_device_resync(ha); -- GitLab From 7047fcddb1bc96a80fc54ac3a88ea18ca3ae77f6 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:47 -0700 Subject: [PATCH 0366/1619] [SCSI] qla2xxx: Add support for host port state FC transport attribute. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d4cf51a8796..ee75a71f3c6 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -879,6 +879,19 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost) fc_host_fabric_name(shost) = node_name; } +static void +qla2x00_get_host_port_state(struct Scsi_Host *shost) +{ + scsi_qla_host_t *ha = to_qla_host(shost); + + if (!ha->flags.online) + fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; + else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT) + fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; + else + fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; +} + struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, @@ -897,6 +910,8 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_system_hostname = 1, .get_host_fabric_name = qla2x00_get_host_fabric_name, .show_host_fabric_name = 1, + .get_host_port_state = qla2x00_get_host_port_state, + .show_host_port_state = 1, .dd_fcrport_size = sizeof(struct fc_port *), .show_rport_supported_classes = 1, -- GitLab From bb8ee4998498e15b5c8ed94cd7dd8d07e586c0ab Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:48 -0700 Subject: [PATCH 0367/1619] [SCSI] qla2xxx: Add MODULE_FIRMWARE tags. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9e665e1281c..cdc7fca421b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2564,14 +2564,20 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout) #define FW_ISP2322 3 #define FW_ISP24XX 4 +#define FW_FILE_ISP21XX "ql2100_fw.bin" +#define FW_FILE_ISP22XX "ql2200_fw.bin" +#define FW_FILE_ISP2300 "ql2300_fw.bin" +#define FW_FILE_ISP2322 "ql2322_fw.bin" +#define FW_FILE_ISP24XX "ql2400_fw.bin" + static DECLARE_MUTEX(qla_fw_lock); static struct fw_blob qla_fw_blobs[FW_BLOBS] = { - { .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, }, - { .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, }, - { .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, }, - { .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, }, - { .name = "ql2400_fw.bin", }, + { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, }, + { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, }, + { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, }, + { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, }, + { .name = FW_FILE_ISP24XX, }, }; struct fw_blob * @@ -2702,3 +2708,8 @@ MODULE_AUTHOR("QLogic Corporation"); MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(QLA2XXX_VERSION); +MODULE_FIRMWARE(FW_FILE_ISP21XX); +MODULE_FIRMWARE(FW_FILE_ISP22XX); +MODULE_FIRMWARE(FW_FILE_ISP2300); +MODULE_FIRMWARE(FW_FILE_ISP2322); +MODULE_FIRMWARE(FW_FILE_ISP24XX); -- GitLab From 07db51831371f2875ef234b1535a15afdb381b6c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:49 -0700 Subject: [PATCH 0368/1619] [SCSI] qla2xxx: Stall mid-layer error handlers while rport is blocked. Stall error handler if attempting recovery while an rport is blocked. This avoids device offline scenarios due to errors in the error handler. Reference implementation from lpfc/mptfc. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index cdc7fca421b..3ba8c239f17 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -589,6 +589,23 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) return (return_status); } +static void +qla2x00_block_error_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + while (rport->port_state == FC_PORTSTATE_BLOCKED) { + spin_unlock_irqrestore(shost->host_lock, flags); + msleep(1000); + spin_lock_irqsave(shost->host_lock, flags); + } + spin_unlock_irqrestore(shost->host_lock, flags); + return; +} + /************************************************************************** * qla2xxx_eh_abort * @@ -615,6 +632,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned long flags; int wait = 0; + qla2x00_block_error_handler(cmd); + if (!CMD_SP(cmd)) return SUCCESS; @@ -748,6 +767,8 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) unsigned int id, lun; unsigned long serial; + qla2x00_block_error_handler(cmd); + ret = FAILED; id = cmd->device->id; @@ -877,6 +898,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) unsigned int id, lun; unsigned long serial; + qla2x00_block_error_handler(cmd); + ret = FAILED; id = cmd->device->id; @@ -936,6 +959,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) unsigned int id, lun; unsigned long serial; + qla2x00_block_error_handler(cmd); + ret = FAILED; id = cmd->device->id; -- GitLab From 65935ff95cfda67c7b2bf228d6f7083a46f832a1 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 2 Oct 2006 12:00:50 -0700 Subject: [PATCH 0369/1619] [SCSI] qla2xxx: Update version number to 8.01.07-k2. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 971259032ef..e57bf45a339 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.07-k1" +#define QLA2XXX_VERSION "8.01.07-k2" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 -- GitLab From 7ecdb70a0ea436c06540140242bfac6ac3babfc0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 3 Oct 2006 21:03:35 -0400 Subject: [PATCH 0370/1619] [GFS2] Fix endian bug for de_type Missing endian conversion for the de_type field. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 82432d8f713..ef6e5ed70e9 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -404,7 +404,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) 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_type = DT_DIR; + dent->de_type = cpu_to_be16(DT_DIR); di->di_entries = cpu_to_be32(1); gfs2_str2qstr(&str, ".."); @@ -412,7 +412,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); gfs2_inum_out(&dip->i_num, &dent->de_inum); - dent->de_type = DT_DIR; + dent->de_type = cpu_to_be16(DT_DIR); gfs2_dinode_out(&ip->i_di, di); -- GitLab From 2e194583125bfea94d1ceaa6a32e891643befa7d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 29 Sep 2006 15:00:29 +1000 Subject: [PATCH 0371/1619] [POWERPC] Cell interrupt rework This patch reworks the cell iic interrupt handling so that: - Node ID is back in the interrupt number (only one IRQ host is created for all nodes). This allows interrupts from sources on another node to be routed non-locally. This will allow possibly one day to fix maxcpus=1 or 2 and still get interrupts from devices on BE 1. (A bit more fixing is needed for that) and it will allow us to implement actual affinity control of external interrupts. - Added handling of the IO exceptions interrupts (badly named, but I re-used the name initially used by STI). Those are the interrupts exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception, performance monitor, etc... Those get their special numbers in the IRQ number space and are internally implemented as a cascade on unit 0xe, class 1 of each node. Signed-off-by: Benjamin Herrenschmidt Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/interrupt.c | 235 ++++++++++++++++------- arch/powerpc/platforms/cell/interrupt.h | 97 ++++++---- arch/powerpc/platforms/cell/spider-pic.c | 9 +- arch/powerpc/platforms/cell/spu_base.c | 19 +- 4 files changed, 238 insertions(+), 122 deletions(-) diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 6b57a47c5d3..6cc59e0b458 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -21,6 +21,12 @@ * 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: + * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers + * vs node numbers in the setup code + * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from + * a non-active node to the active node) */ #include @@ -44,24 +50,25 @@ struct iic { u8 target_id; u8 eoi_stack[16]; int eoi_ptr; - struct irq_host *host; + struct device_node *node; }; static DEFINE_PER_CPU(struct iic, iic); #define IIC_NODE_COUNT 2 -static struct irq_host *iic_hosts[IIC_NODE_COUNT]; +static struct irq_host *iic_host; /* Convert between "pending" bits and hw irq number */ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) { unsigned char unit = bits.source & 0xf; + unsigned char node = bits.source >> 4; + unsigned char class = bits.class & 3; + /* Decode IPIs */ if (bits.flags & CBE_IIC_IRQ_IPI) - return IIC_IRQ_IPI0 | (bits.prio >> 4); - else if (bits.class <= 3) - return (bits.class << 4) | unit; + return IIC_IRQ_TYPE_IPI | (bits.prio >> 4); else - return IIC_IRQ_INVALID; + return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit; } static void iic_mask(unsigned int irq) @@ -86,21 +93,70 @@ static struct irq_chip iic_chip = { .eoi = iic_eoi, }; + +static void iic_ioexc_eoi(unsigned int irq) +{ +} + +static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs) +{ + struct cbe_iic_regs *node_iic = desc->handler_data; + unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC; + unsigned long bits, ack; + int cascade; + + for (;;) { + bits = in_be64(&node_iic->iic_is); + if (bits == 0) + break; + /* pre-ack edge interrupts */ + ack = bits & IIC_ISR_EDGE_MASK; + if (ack) + out_be64(&node_iic->iic_is, ack); + /* handle them */ + for (cascade = 63; cascade >= 0; cascade--) + if (bits & (0x8000000000000000UL >> cascade)) { + unsigned int cirq = + irq_linear_revmap(iic_host, + base | cascade); + if (cirq != NO_IRQ) + generic_handle_irq(cirq, regs); + } + /* post-ack level interrupts */ + ack = bits & ~IIC_ISR_EDGE_MASK; + if (ack) + out_be64(&node_iic->iic_is, ack); + } + desc->chip->eoi(irq); +} + + +static struct irq_chip iic_ioexc_chip = { + .typename = " CELL-IOEX", + .mask = iic_mask, + .unmask = iic_unmask, + .eoi = iic_ioexc_eoi, +}; + /* Get an IRQ number from the pending state register of the IIC */ static unsigned int iic_get_irq(struct pt_regs *regs) { struct cbe_iic_pending_bits pending; struct iic *iic; + unsigned int virq; iic = &__get_cpu_var(iic); *(unsigned long *) &pending = in_be64((unsigned long __iomem *) &iic->regs->pending_destr); + if (!(pending.flags & CBE_IIC_IRQ_VALID)) + return NO_IRQ; + virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending)); + if (virq == NO_IRQ) + return NO_IRQ; iic->eoi_stack[++iic->eoi_ptr] = pending.prio; BUG_ON(iic->eoi_ptr > 15); - if (pending.flags & CBE_IIC_IRQ_VALID) - return irq_linear_revmap(iic->host, - iic_pending_to_hwnum(pending)); - return NO_IRQ; + return virq; } #ifdef CONFIG_SMP @@ -108,12 +164,7 @@ static unsigned int iic_get_irq(struct pt_regs *regs) /* Use the highest interrupt priorities for IPI */ static inline int iic_ipi_to_irq(int ipi) { - return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi; -} - -static inline int iic_irq_to_ipi(int irq) -{ - return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0); + return IIC_IRQ_TYPE_IPI + 0xf - ipi; } void iic_setup_cpu(void) @@ -123,7 +174,7 @@ void iic_setup_cpu(void) void iic_cause_IPI(int cpu, int mesg) { - out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4); + out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4); } u8 iic_get_target_id(int cpu) @@ -134,9 +185,7 @@ EXPORT_SYMBOL_GPL(iic_get_target_id); struct irq_host *iic_get_irq_host(int node) { - if (node < 0 || node >= IIC_NODE_COUNT) - return NULL; - return iic_hosts[node]; + return iic_host; } EXPORT_SYMBOL_GPL(iic_get_irq_host); @@ -149,34 +198,20 @@ static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } - static void iic_request_ipi(int ipi, const char *name) { - int node, virq; + int virq; - for (node = 0; node < IIC_NODE_COUNT; node++) { - char *rname; - if (iic_hosts[node] == NULL) - continue; - virq = irq_create_mapping(iic_hosts[node], - iic_ipi_to_irq(ipi)); - if (virq == NO_IRQ) { - printk(KERN_ERR - "iic: failed to map IPI %s on node %d\n", - name, node); - continue; - } - rname = kzalloc(strlen(name) + 16, GFP_KERNEL); - if (rname) - sprintf(rname, "%s node %d", name, node); - else - rname = (char *)name; - if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, - rname, (void *)(long)ipi)) - printk(KERN_ERR - "iic: failed to request IPI %s on node %d\n", - name, node); + virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi)); + if (virq == NO_IRQ) { + printk(KERN_ERR + "iic: failed to map IPI %s\n", name); + return; } + if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name, + (void *)(long)ipi)) + printk(KERN_ERR + "iic: failed to request IPI %s\n", name); } void iic_request_IPIs(void) @@ -193,16 +228,24 @@ void iic_request_IPIs(void) static int iic_host_match(struct irq_host *h, struct device_node *node) { - return h->host_data != NULL && node == h->host_data; + return device_is_compatible(node, + "IBM,CBEA-Internal-Interrupt-Controller"); } static int iic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { - if (hw < IIC_IRQ_IPI0) - set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); - else + switch (hw & IIC_IRQ_TYPE_MASK) { + case IIC_IRQ_TYPE_IPI: set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq); + break; + case IIC_IRQ_TYPE_IOEXC: + set_irq_chip_and_handler(virq, &iic_ioexc_chip, + handle_fasteoi_irq); + break; + default: + set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); + } return 0; } @@ -211,11 +254,39 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { - /* Currently, we don't translate anything. That needs to be fixed as - * we get better defined device-trees. iic interrupts have to be - * explicitely mapped by whoever needs them - */ - return -ENODEV; + unsigned int node, ext, unit, class; + const u32 *val; + + if (!device_is_compatible(ct, + "IBM,CBEA-Internal-Interrupt-Controller")) + return -ENODEV; + if (intsize != 1) + return -ENODEV; + val = get_property(ct, "#interrupt-cells", NULL); + if (val == NULL || *val != 1) + return -ENODEV; + + node = intspec[0] >> 24; + ext = (intspec[0] >> 16) & 0xff; + class = (intspec[0] >> 8) & 0xff; + unit = intspec[0] & 0xff; + + /* Check if node is in supported range */ + if (node > 1) + return -EINVAL; + + /* Build up interrupt number, special case for IO exceptions */ + *out_hwirq = (node << IIC_IRQ_NODE_SHIFT); + if (unit == IIC_UNIT_IIC && class == 1) + *out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext; + else + *out_hwirq |= IIC_IRQ_TYPE_NORMAL | + (class << IIC_IRQ_CLASS_SHIFT) | unit; + + /* Dummy flags, ignored by iic code */ + *out_flags = IRQ_TYPE_EDGE_RISING; + + return 0; } static struct irq_host_ops iic_host_ops = { @@ -225,7 +296,7 @@ static struct irq_host_ops iic_host_ops = { }; static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, - struct irq_host *host) + struct device_node *node) { /* XXX FIXME: should locate the linux CPU number from the HW cpu * number properly. We are lucky for now @@ -237,19 +308,19 @@ static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe); iic->eoi_stack[0] = 0xff; - iic->host = host; + iic->node = of_node_get(node); out_be64(&iic->regs->prio, 0); - printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n", - hw_cpu, addr, iic->regs, iic->target_id); + printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n", + hw_cpu, iic->target_id, node->full_name); } static int __init setup_iic(void) { struct device_node *dn; struct resource r0, r1; - struct irq_host *host; - int found = 0; + unsigned int node, cascade, found = 0; + struct cbe_iic_regs *node_iic; const u32 *np; for (dn = NULL; @@ -269,19 +340,33 @@ static int __init setup_iic(void) of_node_put(dn); return -ENODEV; } - host = NULL; - if (found < IIC_NODE_COUNT) { - host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, - IIC_SOURCE_COUNT, - &iic_host_ops, - IIC_IRQ_INVALID); - iic_hosts[found] = host; - BUG_ON(iic_hosts[found] == NULL); - iic_hosts[found]->host_data = of_node_get(dn); - found++; - } - init_one_iic(np[0], r0.start, host); - init_one_iic(np[1], r1.start, host); + found++; + init_one_iic(np[0], r0.start, dn); + init_one_iic(np[1], r1.start, dn); + + /* Setup cascade for IO exceptions. XXX cleanup tricks to get + * node vs CPU etc... + * Note that we configure the IIC_IRR here with a hard coded + * priority of 1. We might want to improve that later. + */ + node = np[0] >> 1; + node_iic = cbe_get_cpu_iic_regs(np[0]); + cascade = node << IIC_IRQ_NODE_SHIFT; + cascade |= 1 << IIC_IRQ_CLASS_SHIFT; + cascade |= IIC_UNIT_IIC; + cascade = irq_create_mapping(iic_host, cascade); + if (cascade == NO_IRQ) + continue; + set_irq_data(cascade, node_iic); + set_irq_chained_handler(cascade , iic_ioexc_cascade); + out_be64(&node_iic->iic_ir, + (1 << 12) /* priority */ | + (node << 4) /* dest node */ | + IIC_UNIT_THREAD_0 /* route them to thread 0 */); + /* Flush pending (make sure it triggers if there is + * anything pending + */ + out_be64(&node_iic->iic_is, 0xfffffffffffffffful); } if (found) @@ -292,6 +377,12 @@ static int __init setup_iic(void) void __init iic_init_IRQ(void) { + /* Setup an irq host data structure */ + iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, + &iic_host_ops, IIC_IRQ_INVALID); + BUG_ON(iic_host == NULL); + irq_set_default_host(iic_host); + /* Discover and initialize iics */ if (setup_iic() < 0) panic("IIC: Failed to initialize !\n"); diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index 5560a92ec3a..9ba1d3c17b4 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h @@ -2,48 +2,76 @@ #define ASM_CELL_PIC_H #ifdef __KERNEL__ /* - * Mapping of IIC pending bits into per-node - * interrupt numbers. + * Mapping of IIC pending bits into per-node interrupt numbers. * - * IRQ FF CC SS PP FF CC SS PP Description + * Interrupt numbers are in the range 0...0x1ff where the top bit + * (0x100) represent the source node. Only 2 nodes are supported with + * the current code though it's trivial to extend that if necessary using + * higher level bits * - * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge - * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge - * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0 - * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1 - * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2 - * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI + * The bottom 8 bits are split into 2 type bits and 6 data bits that + * depend on the type: * - * F flags - * C class - * S source - * P Priority - * + node number - * * don't care + * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source + * 01 (0x40 | data) : IO exception. data is the exception number as + * defined by bit numbers in IIC_SR + * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority) + * and node is always 0 (IPIs are per-cpu, their source is + * not relevant) + * 11 (0xc0 | data) : reserved * - * A node consists of a Cell Broadband Engine and an optional - * south bridge device providing a maximum of 64 IRQs. - * The south bridge may be connected to either IOIF0 - * or IOIF1. - * Each SPE is represented as three IRQ lines, one per - * interrupt class. - * 16 IRQ numbers are reserved for inter processor - * interruptions, although these are only used in the - * range of the first node. + * In addition, interrupt number 0x80000000 is defined as always invalid + * (that is the node field is expected to never extend to move than 23 bits) * - * This scheme needs 128 IRQ numbers per BIF node ID, - * which means that with the total of 512 lines - * available, we can have a maximum of four nodes. */ enum { - IIC_IRQ_INVALID = 0xff, - IIC_IRQ_MAX = 0x3f, - IIC_IRQ_EXT_IOIF0 = 0x20, - IIC_IRQ_EXT_IOIF1 = 0x2b, - IIC_IRQ_IPI0 = 0x40, - IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */ - IIC_SOURCE_COUNT = 0x50, + IIC_IRQ_INVALID = 0x80000000u, + IIC_IRQ_NODE_MASK = 0x100, + IIC_IRQ_NODE_SHIFT = 8, + IIC_IRQ_MAX = 0x1ff, + IIC_IRQ_TYPE_MASK = 0xc0, + IIC_IRQ_TYPE_NORMAL = 0x00, + IIC_IRQ_TYPE_IOEXC = 0x40, + IIC_IRQ_TYPE_IPI = 0x80, + IIC_IRQ_CLASS_SHIFT = 4, + IIC_IRQ_CLASS_0 = 0x00, + IIC_IRQ_CLASS_1 = 0x10, + IIC_IRQ_CLASS_2 = 0x20, + IIC_SOURCE_COUNT = 0x200, + + /* Here are defined the various source/dest units. Avoid using those + * definitions if you can, they are mostly here for reference + */ + IIC_UNIT_SPU_0 = 0x4, + IIC_UNIT_SPU_1 = 0x7, + IIC_UNIT_SPU_2 = 0x3, + IIC_UNIT_SPU_3 = 0x8, + IIC_UNIT_SPU_4 = 0x2, + IIC_UNIT_SPU_5 = 0x9, + IIC_UNIT_SPU_6 = 0x1, + IIC_UNIT_SPU_7 = 0xa, + IIC_UNIT_IOC_0 = 0x0, + IIC_UNIT_IOC_1 = 0xb, + IIC_UNIT_THREAD_0 = 0xe, /* target only */ + IIC_UNIT_THREAD_1 = 0xf, /* target only */ + IIC_UNIT_IIC = 0xe, /* source only (IO exceptions) */ + + /* Base numbers for the external interrupts */ + IIC_IRQ_EXT_IOIF0 = + IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0, + IIC_IRQ_EXT_IOIF1 = + IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1, + + /* Base numbers for the IIC_ISR interrupts */ + IIC_IRQ_IOEX_TMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63, + IIC_IRQ_IOEX_PMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62, + IIC_IRQ_IOEX_ATI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61, + IIC_IRQ_IOEX_MATBFI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60, + IIC_IRQ_IOEX_ELDI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59, + + /* Which bits in IIC_ISR are edge sensitive */ + IIC_ISR_EDGE_MASK = 0x4ul, }; extern void iic_init_IRQ(void); @@ -52,7 +80,6 @@ extern void iic_request_IPIs(void); extern void iic_setup_cpu(void); extern u8 iic_get_target_id(int cpu); -extern struct irq_host *iic_get_irq_host(int node); extern void spider_init_IRQ(void); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 742a03282b4..608b1ebc56b 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -243,7 +243,6 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) const u32 *imap, *tmp; int imaplen, intsize, unit; struct device_node *iic; - struct irq_host *iic_host; #if 0 /* Enable that when we have a way to retreive the node as well */ /* First, we check wether we have a real "interrupts" in the device @@ -289,11 +288,11 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) * the iic host from the iic OF node, but that way I'm still compatible * with really really old old firmwares for which we don't have a node */ - iic_host = iic_get_irq_host(pic->node_id); - if (iic_host == NULL) - return NO_IRQ; /* Manufacture an IIC interrupt number of class 2 */ - virq = irq_create_mapping(iic_host, 0x20 | unit); + virq = irq_create_mapping(NULL, + (pic->node_id << IIC_IRQ_NODE_SHIFT) | + (2 << IIC_IRQ_CLASS_SHIFT) | + unit); if (virq == NO_IRQ) printk(KERN_ERR "spider_pic: failed to map cascade !"); return virq; diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 0f5c8ebc7fc..f78680346e5 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -568,24 +568,23 @@ static void spu_unmap(struct spu *spu) /* This function shall be abstracted for HV platforms */ static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) { - struct irq_host *host; unsigned int isrc; const u32 *tmp; - host = iic_get_irq_host(spu->node); - if (host == NULL) - return -ENODEV; - - /* Get the interrupt source from the device-tree */ + /* Get the interrupt source unit from the device-tree */ tmp = get_property(np, "isrc", NULL); if (!tmp) return -ENODEV; - spu->isrc = isrc = tmp[0]; + isrc = tmp[0]; + + /* Add the node number */ + isrc |= spu->node << IIC_IRQ_NODE_SHIFT; + spu->isrc = isrc; /* Now map interrupts of all 3 classes */ - spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc); - spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc); - spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc); + spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); + spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); + spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); /* Right now, we only fail if class 2 failed */ return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; -- GitLab From 14b1ffb577a8678e228683bd015302cfe964040c Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 2 Oct 2006 22:57:23 +0200 Subject: [PATCH 0372/1619] [POWERPC] Update swim3 printk after blkdev.h change drivers/block/swim3.c: In function 'swim3_interrupt': drivers/block/swim3.c:640: warning: format '%lx' expects type 'long unsigned int', but argument 3 has type 'unsigned int' drivers/block/swim3.c:746: warning: format '%lx' expects type 'long unsigned int', but argument 3 has type 'unsigned int' Update printk format string after blkdev.h change: Split struct request ->flags into two parts Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- drivers/block/swim3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index f2305ee792a..fdc8f892eb8 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -636,7 +636,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) intr = in_8(&sw->intr); err = (intr & ERROR_INTR)? in_8(&sw->error): 0; if ((intr & ERROR_INTR) && fs->state != do_transfer) - printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n", + printk(KERN_ERR "swim3_interrupt, state=%d, dir=%x, intr=%x, err=%x\n", fs->state, rq_data_dir(fd_req), intr, err); switch (fs->state) { case locating: @@ -742,7 +742,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((stat & ACTIVE) == 0 || resid != 0) { /* musta been an error */ printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid); - printk(KERN_ERR " state=%d, dir=%lx, intr=%x, err=%x\n", + printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n", fs->state, rq_data_dir(fd_req), intr, err); end_request(fd_req, 0); fs->state = idle; -- GitLab From 23b8acb1cf49fea74a9d431de258787384951eac Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 3 Oct 2006 14:12:07 +1000 Subject: [PATCH 0373/1619] [POWERPC] Cleanup include/asm-powerpc/xmon.h For some reason we have two prototypes for xmon_init(), remove the one in system.h. No one calls xmon() anymore, debugger() is preferable, so we don't need the prototype. And similarly no one calls xmon_printf(). Also update the include guards on xmon.h to match the standard format, add copyright and license, and add comments to #endifs. Built for pseries_defconfig and pmac32_defconfig. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- include/asm-powerpc/system.h | 4 ---- include/asm-powerpc/xmon.h | 22 ++++++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 4b41deaa8d8..43627596003 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -91,10 +91,6 @@ DEBUGGER_BOILERPLATE(debugger_iabr_match) DEBUGGER_BOILERPLATE(debugger_dabr_match) DEBUGGER_BOILERPLATE(debugger_fault_handler) -#ifdef CONFIG_XMON -extern void xmon_init(int enable); -#endif - #else static inline int debugger(struct pt_regs *regs) { return 0; } static inline int debugger_ipi(struct pt_regs *regs) { return 0; } diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index 43f7129984c..c02dd0ce13a 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h @@ -1,12 +1,18 @@ -#ifndef __PPC_XMON_H -#define __PPC_XMON_H -#ifdef __KERNEL__ +#ifndef __ASM_POWERPC_XMON_H +#define __ASM_POWERPC_XMON_H + +/* + * Copyrignt (C) 2006 IBM Corp + * + * 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. + */ -struct pt_regs; +#ifdef __KERNEL__ -extern int xmon(struct pt_regs *excp); -extern void xmon_printf(const char *fmt, ...); extern void xmon_init(int); -#endif -#endif +#endif /* __KERNEL __ */ +#endif /* __ASM_POWERPC_XMON_H */ -- GitLab From 476792839467c08ddeedd8b44a7423d415b68259 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 3 Oct 2006 14:12:08 +1000 Subject: [PATCH 0374/1619] [POWERPC] Fix xmon=off and cleanup xmon initialisation My patch to make the early xmon logic work with earlier early param parsing (480f6f35a149802a94ad5c1a2673ed6ec8d2c158) breaks xmon=off. No one does this obviously as xmon rocks, but it should really work as documented. While fixing that it struck me that we could move the xmon param handling into xmon.c, and also consolidate the xmon_init()/do_early_xmon logic into xmon_setup(). This means xmon=early drops into xmon a little earlier on 32-bit, but it seems to work just fine. Tested on PSERIES and CLASSIC32. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup-common.c | 25 ---------------------- arch/powerpc/kernel/setup_32.c | 8 ++------ arch/powerpc/kernel/setup_64.c | 12 ++++------- arch/powerpc/xmon/xmon.c | 33 ++++++++++++++++++++++++++++++ include/asm-powerpc/xmon.h | 6 +++++- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 0af3fc1bdcc..89cfaf49d3d 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -442,31 +442,6 @@ void __init smp_setup_cpu_maps(void) } #endif /* CONFIG_SMP */ -int __initdata do_early_xmon; -#ifdef CONFIG_XMON -extern int xmon_no_auto_backtrace; - -static int __init early_xmon(char *p) -{ - /* ensure xmon is enabled */ - if (p) { - if (strncmp(p, "on", 2) == 0) - xmon_init(1); - if (strncmp(p, "off", 3) == 0) - xmon_init(0); - if (strncmp(p, "nobt", 4) == 0) - xmon_no_auto_backtrace = 1; - if (strncmp(p, "early", 5) != 0) - return 0; - } - xmon_init(1); - do_early_xmon = 1; - - return 0; -} -early_param("xmon", early_xmon); -#endif - static __init int add_pcspkr(void) { struct device_node *np; diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 79a17795d17..191d0ab0922 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -238,12 +238,11 @@ void __init setup_arch(char **cmdline_p) smp_setup_cpu_maps(); -#ifdef CONFIG_XMON_DEFAULT - xmon_init(1); -#endif /* Register early console */ register_early_udbg_console(); + xmon_setup(); + #if defined(CONFIG_KGDB) if (ppc_md.kgdb_map_scc) ppc_md.kgdb_map_scc(); @@ -280,9 +279,6 @@ void __init setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) _edata; init_mm.brk = klimit; - if (do_early_xmon) - debugger(NULL); - /* set up the bootmem stuff with available memory */ do_init_bootmem(); if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index cda2dbe70a7..4b2e32eab9d 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -390,19 +390,15 @@ void __init setup_system(void) */ find_legacy_serial_ports(); - /* - * Initialize xmon - */ -#ifdef CONFIG_XMON_DEFAULT - xmon_init(1); -#endif /* * Register early console */ register_early_udbg_console(); - if (do_early_xmon) - debugger(NULL); + /* + * Initialize xmon + */ + xmon_setup(); check_smt_enabled(); smp_setup_cpu_maps(); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 8adad1444a5..b54ff980ecd 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2,6 +2,8 @@ * Routines providing a simple monitor for use on the PowerMac. * * Copyright (C) 1996-2005 Paul Mackerras. + * Copyright (C) 2001 PPC64 Team, IBM Corp + * Copyrignt (C) 2006 Michael Ellerman, IBM Corp * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -2597,3 +2599,34 @@ static int __init setup_xmon_sysrq(void) } __initcall(setup_xmon_sysrq); #endif /* CONFIG_MAGIC_SYSRQ */ + +int __initdata xmon_early, xmon_off; + +static int __init early_parse_xmon(char *p) +{ + if (!p || strncmp(p, "early", 5) == 0) { + /* just "xmon" is equivalent to "xmon=early" */ + xmon_init(1); + xmon_early = 1; + } else if (strncmp(p, "on", 2) == 0) + xmon_init(1); + else if (strncmp(p, "off", 3) == 0) + xmon_off = 1; + else if (strncmp(p, "nobt", 4) == 0) + xmon_no_auto_backtrace = 1; + else + return 1; + + return 0; +} +early_param("xmon", early_parse_xmon); + +void __init xmon_setup(void) +{ +#ifdef CONFIG_XMON_DEFAULT + if (!xmon_off) + xmon_init(1); +#endif + if (xmon_early) + debugger(NULL); +} diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index c02dd0ce13a..f1d337ed68d 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h @@ -12,7 +12,11 @@ #ifdef __KERNEL__ -extern void xmon_init(int); +#ifdef CONFIG_XMON +extern void xmon_setup(void); +#else +static inline void xmon_setup(void) { }; +#endif #endif /* __KERNEL __ */ #endif /* __ASM_POWERPC_XMON_H */ -- GitLab From 54c9941288e86fad983e307e540808e155b16b34 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 3 Oct 2006 14:27:16 +1000 Subject: [PATCH 0375/1619] [POWERPC] Fix zImage.coff on oldworld PowerMac Recent changes to the PowerPC zImage wrapper broke zImage.coff due to the addition of new ELF sections that aren't very well converted to xcoff and not supported by old OpenFirmware. This fixes it by putting those sections in the xcoff .data. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/boot/zImage.coff.lds.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S index 6016251a1a2..05f32388b95 100644 --- a/arch/powerpc/boot/zImage.coff.lds.S +++ b/arch/powerpc/boot/zImage.coff.lds.S @@ -15,6 +15,7 @@ SECTIONS { *(.rodata*) *(.data*) + *(__builtin_*) *(.sdata*) __got2_start = .; *(.got2) -- GitLab From 2ec6ef1034632c67896955d52bf8efb99195b742 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 3 Oct 2006 14:47:58 +1000 Subject: [PATCH 0376/1619] [POWERPC] Get default baud rate in udbg_scc On powermac, when open firmware is set to use the SCC for console, this causes the low level udbg early console to read back the speed and re-use it instead of hard coding 57600 bps. This doesn't (yet) pass the detected speed all the way to pmac_zilog though. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/udbg_scc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c index ce1a235855f..379db05b008 100644 --- a/arch/powerpc/platforms/powermac/udbg_scc.c +++ b/arch/powerpc/platforms/powermac/udbg_scc.c @@ -111,8 +111,6 @@ void udbg_scc_init(int force_scc) pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch, PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); - - /* Setup for 57600 8N1 */ if (ch == ch_a) addr += 0x20; sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ; @@ -125,9 +123,21 @@ void udbg_scc_init(int force_scc) x = in_8(sccc); out_8(sccc, 0x09); /* reset A or B side */ out_8(sccc, 0xc0); + + /* If SCC was the OF output port, read the BRG value, else + * Setup for 57600 8N1 + */ + if (ch_def != NULL) { + out_8(sccc, 13); + scc_inittab[1] = in_8(sccc); + out_8(sccc, 12); + scc_inittab[3] = in_8(sccc); + } + for (i = 0; i < sizeof(scc_inittab); ++i) out_8(sccc, scc_inittab[i]); + udbg_putc = udbg_scc_putc; udbg_getc = udbg_scc_getc; udbg_getc_poll = udbg_scc_getc_poll; -- GitLab From 586da2cc78131d194ecacaf4de26b49691de5fd3 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 3 Oct 2006 14:48:43 +1000 Subject: [PATCH 0377/1619] [POWERPC] Fix a printk in pseries_mpic_init_IRQ This should probably say "mpic" to save confusion. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 43dbf737698..f82b13e531a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -180,7 +180,7 @@ static void __init pseries_mpic_init_IRQ(void) cascade_irq = irq_of_parse_and_map(cascade, 0); if (cascade == NO_IRQ) { - printk(KERN_ERR "xics: failed to map cascade interrupt"); + printk(KERN_ERR "mpic: failed to map cascade interrupt"); return; } -- GitLab From 0a730ae59960165ae50de3284fb50316d1755d98 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 3 Oct 2006 21:32:49 +1000 Subject: [PATCH 0378/1619] [POWERPC] Don't try to just continue if xmon has no input device Currently, if xmon has no input device (as is generally the case on G5 powermacs), and we drop into xmon as a result of a fatal exception, it will return 1, which die() interprets as "continue without causing an oops". This fixes it by making xmon() return 0 in the case where it has no input device. Signed-off-by: Paul Mackerras --- arch/powerpc/xmon/xmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index b54ff980ecd..708236f3474 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -505,7 +505,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) mtmsr(msr); /* restore interrupt enable */ - return cmd != 'X'; + return cmd != 'X' && cmd != EOF; } int xmon(struct pt_regs *excp) -- GitLab From 9a1ab883c04e43f9f9819c40eb435bcdc4136193 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Mon, 2 Oct 2006 20:08:59 -0500 Subject: [PATCH 0379/1619] [POWERPC] Add QE device tree node definition OF device tree node spec used in QE/8360 support patches. Signed-off-by: Li Yang Signed-off-by: Jiang Bo Signed-off-by: Kim Phillips Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras --- Documentation/powerpc/booting-without-of.txt | 252 +++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 5c0ba235f5a..b57e7da7897 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1441,6 +1441,258 @@ platforms are moved over to use the flattened-device-tree model. descriptor-types-mask = <012b0ebf>; }; + h) Board Control and Status (BCSR) + + Required properties: + + - device_type : Should be "board-control" + - reg : Offset and length of the register set for the device + + Example: + + bcsr@f8000000 { + device_type = "board-control"; + reg = ; + }; + + i) Freescale QUICC Engine module (QE) + This represents qe module that is installed on PowerQUICC II Pro. + Hopefully it will merge backward compatibility with CPM/CPM2. + Basically, it is a bus of devices, that could act more or less + as a complete entity (UCC, USB etc ). All of them should be siblings on + the "root" qe node, using the common properties from there. + The description below applies to the the qe of MPC8360 and + more nodes and properties would be extended in the future. + + i) Root QE device + + Required properties: + - device_type : should be "qe"; + - model : precise model of the QE, Can be "QE", "CPM", or "CPM2" + - reg : offset and length of the device registers. + - bus-frequency : the clock frequency for QUICC Engine. + + Recommended properties + - brg-frequency : the internal clock source frequency for baud-rate + generators in Hz. + + Example: + qe@e0100000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "qe"; + model = "QE"; + ranges = <0 e0100000 00100000>; + reg = ; + brg-frequency = <0>; + bus-frequency = <179A7B00>; + } + + + ii) SPI (Serial Peripheral Interface) + + Required properties: + - device_type : should be "spi". + - compatible : should be "fsl_spi". + - mode : the spi operation mode, it can be "cpu" or "qe". + - reg : Offset and length of the register set for the device + - interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. + - interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + + Example: + spi@4c0 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <4c0 40>; + interrupts = <82 0>; + interrupt-parent = <700>; + mode = "cpu"; + }; + + + iii) USB (Universal Serial Bus Controller) + + Required properties: + - device_type : should be "usb". + - compatible : could be "qe_udc" or "fhci-hcd". + - mode : the could be "host" or "slave". + - reg : Offset and length of the register set for the device + - interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. + - interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + + Example(slave): + usb@6c0 { + device_type = "usb"; + compatible = "qe_udc"; + reg = <6c0 40>; + interrupts = <8b 0>; + interrupt-parent = <700>; + mode = "slave"; + }; + + + iv) UCC (Unified Communications Controllers) + + Required properties: + - device_type : should be "network", "hldc", "uart", "transparent" + "bisync" or "atm". + - compatible : could be "ucc_geth" or "fsl_atm" and so on. + - model : should be "UCC". + - device-id : the ucc number(1-8), corresponding to UCCx in UM. + - reg : Offset and length of the register set for the device + - interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. + - interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + - pio-handle : The phandle for the Parallel I/O port configuration. + - rx-clock : represents the UCC receive clock source. + 0x00 : clock source is disabled; + 0x1~0x10 : clock source is BRG1~BRG16 respectively; + 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively. + - tx-clock: represents the UCC transmit clock source; + 0x00 : clock source is disabled; + 0x1~0x10 : clock source is BRG1~BRG16 respectively; + 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively. + + Required properties for network device_type: + - mac-address : list of bytes representing the ethernet address. + - phy-handle : The phandle for the PHY connected to this controller. + + Example: + ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <1>; + reg = <2000 200>; + interrupts = ; + interrupt-parent = <700>; + mac-address = [ 00 04 9f 00 23 23 ]; + rx-clock = "none"; + tx-clock = "clk9"; + phy-handle = <212000>; + pio-handle = <140001>; + }; + + + v) Parallel I/O Ports + + This node configures Parallel I/O ports for CPUs with QE support. + The node should reside in the "soc" node of the tree. For each + device that using parallel I/O ports, a child node should be created. + See the definition of the Pin configuration nodes below for more + information. + + Required properties: + - device_type : should be "par_io". + - reg : offset to the register set and its length. + - num-ports : number of Parallel I/O ports + + Example: + par_io@1400 { + reg = <1400 100>; + #address-cells = <1>; + #size-cells = <0>; + device_type = "par_io"; + num-ports = <7>; + ucc_pin@01 { + ...... + }; + + + vi) Pin configuration nodes + + Required properties: + - linux,phandle : phandle of this node; likely referenced by a QE + device. + - pio-map : array of pin configurations. Each pin is defined by 6 + integers. The six numbers are respectively: port, pin, dir, + open_drain, assignment, has_irq. + - port : port number of the pin; 0-6 represent port A-G in UM. + - pin : pin number in the port. + - dir : direction of the pin, should encode as follows: + + 0 = The pin is disabled + 1 = The pin is an output + 2 = The pin is an input + 3 = The pin is I/O + + - open_drain : indicates the pin is normal or wired-OR: + + 0 = The pin is actively driven as an output + 1 = The pin is an open-drain driver. As an output, the pin is + driven active-low, otherwise it is three-stated. + + - assignment : function number of the pin according to the Pin Assignment + tables in User Manual. Each pin can have up to 4 possible functions in + QE and two options for CPM. + - has_irq : indicates if the pin is used as source of exteral + interrupts. + + Example: + ucc_pin@01 { + linux,phandle = <140001>; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0 3 1 0 1 0 /* TxD0 */ + 0 4 1 0 1 0 /* TxD1 */ + 0 5 1 0 1 0 /* TxD2 */ + 0 6 1 0 1 0 /* TxD3 */ + 1 6 1 0 3 0 /* TxD4 */ + 1 7 1 0 1 0 /* TxD5 */ + 1 9 1 0 2 0 /* TxD6 */ + 1 a 1 0 2 0 /* TxD7 */ + 0 9 2 0 1 0 /* RxD0 */ + 0 a 2 0 1 0 /* RxD1 */ + 0 b 2 0 1 0 /* RxD2 */ + 0 c 2 0 1 0 /* RxD3 */ + 0 d 2 0 1 0 /* RxD4 */ + 1 1 2 0 2 0 /* RxD5 */ + 1 0 2 0 2 0 /* RxD6 */ + 1 4 2 0 2 0 /* RxD7 */ + 0 7 1 0 1 0 /* TX_EN */ + 0 8 1 0 1 0 /* TX_ER */ + 0 f 2 0 1 0 /* RX_DV */ + 0 10 2 0 1 0 /* RX_ER */ + 0 0 2 0 1 0 /* RX_CLK */ + 2 9 1 0 3 0 /* GTX_CLK - CLK10 */ + 2 8 2 0 1 0>; /* GTX125 - CLK9 */ + }; + + vii) Multi-User RAM (MURAM) + + Required properties: + - device_type : should be "muram". + - mode : the could be "host" or "slave". + - ranges : Should be defined as specified in 1) to describe the + translation of MURAM addresses. + - data-only : sub-node which defines the address area under MURAM + bus that can be allocated as data/parameter + + Example: + + muram@10000 { + device_type = "muram"; + ranges = <0 00010000 0000c000>; + + data-only@0{ + reg = <0 c000>; + }; + }; More devices will be defined as this spec matures. -- GitLab From 9865853851313e0d94a4acde42d6f9d8070bb376 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Tue, 3 Oct 2006 23:10:46 -0500 Subject: [PATCH 0380/1619] [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 diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b29adaa9734..2587468eec4 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 f15f4d78aee..91f052d8cce 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 00000000000..a725e80befa --- /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 00000000000..874fe1a5b1c --- /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 00000000000..2bae632d3ad --- /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 00000000000..c229d07d495 --- /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 00000000000..9a631adb189 --- /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 00000000000..aea43597038 --- /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 00000000000..916c9e5df57 --- /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 00000000000..c2be7348fcb --- /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 00000000000..1fb88ef7cf0 --- /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 00000000000..ce12f85fff9 --- /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 00000000000..a62168ec535 --- /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 00000000000..e386fb7e44b --- /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 00000000000..afe3076bdc0 --- /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 00000000000..39d1c90fd2c --- /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 00000000000..ca93bc99237 --- /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 16fbe59edeb..3da29e2d524 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__ */ -- GitLab From bc141deafb81f2efa453081e9d52d602a8cec766 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Tue, 3 Oct 2006 23:17:51 -0500 Subject: [PATCH 0381/1619] [POWERPC] Add MPC8360EMDS board support The patch adds MPC8360EMDS board support. Signed-off-by: Li Yang Signed-off-by: Yin Olivia Signed-off-by: Kim Phillips Signed-off-by: Paul Mackerras --- arch/powerpc/configs/mpc8360emds_defconfig | 1018 ++++++++++++++++++++ arch/powerpc/platforms/83xx/mpc8360e_pb.c | 219 +++++ 2 files changed, 1237 insertions(+) create mode 100644 arch/powerpc/configs/mpc8360emds_defconfig create mode 100644 arch/powerpc/platforms/83xx/mpc8360e_pb.c diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig new file mode 100644 index 00000000000..c0703415d60 --- /dev/null +++ b/arch/powerpc/configs/mpc8360emds_defconfig @@ -0,0 +1,1018 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.18 +# Thu Sep 21 18:14:27 2006 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_DEFAULT_UIMAGE=y + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_52xx is not set +# CONFIG_PPC_82xx is not set +CONFIG_PPC_83xx=y +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_86xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_6xx=y +CONFIG_83xx=y +CONFIG_PPC_FPU=y +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP 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_TASKSTATS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_EMBEDDED=y +CONFIG_SYSCTL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=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 is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# 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" +CONFIG_QUICC_ENGINE=y +CONFIG_PPC_GEN550=y +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Platform support +# +# CONFIG_MPC834x_SYS is not set +# CONFIG_MPC834x_ITX is not set +CONFIG_MPC8360E_PB=y +CONFIG_PPC_MPC836x=y +# CONFIG_MPIC is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=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_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +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_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# 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=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +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 is not set +# 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_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 is not set + +# +# 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 is not set + +# +# 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_FD is not set +# 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=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM 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 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM 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 +# CONFIG_GIANFAR is not set +CONFIG_UCC_GETH=y +# CONFIG_UGETH_NAPI is not set +# CONFIG_UGETH_MAGIC_PACKET is not set +# CONFIG_UGETH_FILTERING is not set +# CONFIG_UGETH_TX_ON_DEMOND 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_NET_FC 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 is not set +# 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 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# 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=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_83xx_WDT=y + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# 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=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP 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=y +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# 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=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# 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 is not set + +# +# 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=y +# 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=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS 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=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# QE Options +# +# CONFIG_UCC_SLOW is not set +CONFIG_UCC_FAST=y +CONFIG_UCC=y + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y + +# +# Instrumentation 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_BOOTX_TEXT is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c new file mode 100644 index 00000000000..c0191900fc2 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Li Yang + * Yin Olivia + * + * Description: + * MPC8360E MDS PB board specific routines. + * + * Changelog: + * Jun 21, 2006 Initial version + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpc83xx.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +static u8 *bcsr_regs = NULL; + +u8 *get_bcsr(void) +{ + return bcsr_regs; +} + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init mpc8360_sys_setup_arch(void) +{ + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("mpc8360_sys_setup_arch()", 0); + + np = of_find_node_by_type(NULL, "cpu"); + if (np != 0) { + const unsigned int *fp = + get_property(np, "clock-frequency", NULL); + if (fp != 0) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(np); + } + + /* Map BCSR area */ + np = of_find_node_by_name(NULL, "bcsr"); + if (np != 0) { + struct resource res; + + of_address_to_resource(np, 0, &res); + bcsr_regs = ioremap(res.start, res.end - res.start +1); + of_node_put(np); + } + +#ifdef CONFIG_PCI + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + add_bridge(np); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_exclude_device = mpc83xx_exclude_device; +#endif + +#ifdef CONFIG_QUICC_ENGINE + qe_reset(); + + if ((np = of_find_node_by_name(np, "par_io")) != NULL) { + par_io_init(np); + of_node_put(np); + + for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;) + par_io_of_config(np); + } + + if ((np = of_find_compatible_node(NULL, "network", "ucc_geth")) + != NULL){ + /* Reset the Ethernet PHY */ + bcsr_regs[9] &= ~0x20; + udelay(1000); + bcsr_regs[9] |= 0x20; + iounmap(bcsr_regs); + of_node_put(np); + } + +#endif /* CONFIG_QUICC_ENGINE */ + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +void __init mpc8360_sys_init_IRQ(void) +{ + + struct device_node *np; + + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); + of_node_put(np); + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_node_by_type(NULL, "qeic"); + if (!np) + return; + + qe_ic_init(np, 0); + of_node_put(np); +#endif /* CONFIG_QUICC_ENGINE */ +} + +#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) +extern ulong ds1374_get_rtc_time(void); +extern int ds1374_set_rtc_time(ulong); + +static int __init mpc8360_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.get_rtc_time = ds1374_get_rtc_time; + ppc_md.set_rtc_time = ds1374_set_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time) (); + do_settimeofday(&tv); + + return 0; +} + +late_initcall(mpc8360_rtc_hookup); +#endif + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc8360_sys_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + if (model == NULL) + return 0; + if (strcmp(model, "MPC8360EPB")) + return 0; + + DBG("MPC8360EMDS-PB found\n"); + + return 1; +} + +define_machine(mpc8360_sys) { + .name = "MPC8360E PB", + .probe = mpc8360_sys_probe, + .setup_arch = mpc8360_sys_setup_arch, + .init_IRQ = mpc8360_sys_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; -- GitLab From 7a234d03774a2949d0ce73e3aef56cfdb6856404 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Mon, 2 Oct 2006 20:10:10 -0500 Subject: [PATCH 0382/1619] [POWERPC] Add MPC8360EMDS default dts file Add MPC8360EMDS default device-tree source file Signed-off-by: Li Yang Signed-off-by: Jiang Bo Signed-off-by: Kim Phillips Signed-off-by: Paul Mackerras --- arch/powerpc/boot/dts/mpc8360emds.dts | 375 ++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc8360emds.dts diff --git a/arch/powerpc/boot/dts/mpc8360emds.dts b/arch/powerpc/boot/dts/mpc8360emds.dts new file mode 100644 index 00000000000..9022192155b --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8360emds.dts @@ -0,0 +1,375 @@ +/* + * MPC8360E EMDS Device Tree Source + * + * Copyright 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +/* +/memreserve/ 00000000 1000000; +*/ + +/ { + model = "MPC8360EPB"; + compatible = "MPC83xx"; + #address-cells = <1>; + #size-cells = <1>; + linux,phandle = <100>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <200>; + + PowerPC,8360@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <8000>; // L1, 32K + i-cache-size = <8000>; // L1, 32K + timebase-frequency = <3EF1480>; + bus-frequency = ; + clock-frequency = <1F78A400>; + 32-bit; + linux,phandle = <201>; + linux,boot-cpu; + }; + }; + + memory { + device_type = "memory"; + linux,phandle = <300>; + reg = <00000000 10000000>; + }; + + bcsr@f8000000 { + device_type = "board-control"; + reg = ; + }; + + soc8360@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = ; + + wdt@200 { + device_type = "watchdog"; + compatible = "mpc83xx_wdt"; + reg = <200 100>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = ; + interrupts = <9 8>; + interrupt-parent = <700>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = ; + interrupts = ; + interrupt-parent = <700>; + }; + + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 10000>; + interrupts = ; + interrupt-parent = <700>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <0000007e>; + /* desc mask is for rev1.x, we need runtime fixup for >=2.x */ + descriptor-types-mask = <01010ebf>; + }; + + pci@8500 { + linux,phandle = <8500>; + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 AD17 */ + 8800 0 0 1 700 14 8 + 8800 0 0 2 700 15 8 + 8800 0 0 3 700 16 8 + 8800 0 0 4 700 17 8 + + /* IDSEL 0x12 AD18 */ + 9000 0 0 1 700 16 8 + 9000 0 0 2 700 17 8 + 9000 0 0 3 700 14 8 + 9000 0 0 4 700 15 8 + + /* IDSEL 0x13 AD19 */ + 9800 0 0 1 700 17 8 + 9800 0 0 2 700 14 8 + 9800 0 0 3 700 15 8 + 9800 0 0 4 700 16 8 + + /* IDSEL 0x15 AD21*/ + a800 0 0 1 700 14 8 + a800 0 0 2 700 15 8 + a800 0 0 3 700 16 8 + a800 0 0 4 700 17 8 + + /* IDSEL 0x16 AD22*/ + b000 0 0 1 700 17 8 + b000 0 0 2 700 14 8 + b000 0 0 3 700 15 8 + b000 0 0 4 700 16 8 + + /* IDSEL 0x17 AD23*/ + b800 0 0 1 700 16 8 + b800 0 0 2 700 17 8 + b800 0 0 3 700 14 8 + b800 0 0 4 700 15 8 + + /* IDSEL 0x18 AD24*/ + c000 0 0 1 700 15 8 + c000 0 0 2 700 16 8 + c000 0 0 3 700 17 8 + c000 0 0 4 700 14 8>; + interrupt-parent = <700>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8500 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + pic@700 { + linux,phandle = <700>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <700 100>; + built-in; + device_type = "ipic"; + }; + + par_io@1400 { + reg = <1400 100>; + device_type = "par_io"; + num-ports = <7>; + + ucc_pin@01 { + linux,phandle = <140001>; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0 3 1 0 1 0 /* TxD0 */ + 0 4 1 0 1 0 /* TxD1 */ + 0 5 1 0 1 0 /* TxD2 */ + 0 6 1 0 1 0 /* TxD3 */ + 1 6 1 0 3 0 /* TxD4 */ + 1 7 1 0 1 0 /* TxD5 */ + 1 9 1 0 2 0 /* TxD6 */ + 1 a 1 0 2 0 /* TxD7 */ + 0 9 2 0 1 0 /* RxD0 */ + 0 a 2 0 1 0 /* RxD1 */ + 0 b 2 0 1 0 /* RxD2 */ + 0 c 2 0 1 0 /* RxD3 */ + 0 d 2 0 1 0 /* RxD4 */ + 1 1 2 0 2 0 /* RxD5 */ + 1 0 2 0 2 0 /* RxD6 */ + 1 4 2 0 2 0 /* RxD7 */ + 0 7 1 0 1 0 /* TX_EN */ + 0 8 1 0 1 0 /* TX_ER */ + 0 f 2 0 1 0 /* RX_DV */ + 0 10 2 0 1 0 /* RX_ER */ + 0 0 2 0 1 0 /* RX_CLK */ + 2 9 1 0 3 0 /* GTX_CLK - CLK10 */ + 2 8 2 0 1 0>; /* GTX125 - CLK9 */ + }; + ucc_pin@02 { + linux,phandle = <140002>; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0 11 1 0 1 0 /* TxD0 */ + 0 12 1 0 1 0 /* TxD1 */ + 0 13 1 0 1 0 /* TxD2 */ + 0 14 1 0 1 0 /* TxD3 */ + 1 2 1 0 1 0 /* TxD4 */ + 1 3 1 0 2 0 /* TxD5 */ + 1 5 1 0 3 0 /* TxD6 */ + 1 8 1 0 3 0 /* TxD7 */ + 0 17 2 0 1 0 /* RxD0 */ + 0 18 2 0 1 0 /* RxD1 */ + 0 19 2 0 1 0 /* RxD2 */ + 0 1a 2 0 1 0 /* RxD3 */ + 0 1b 2 0 1 0 /* RxD4 */ + 1 c 2 0 2 0 /* RxD5 */ + 1 d 2 0 3 0 /* RxD6 */ + 1 b 2 0 2 0 /* RxD7 */ + 0 15 1 0 1 0 /* TX_EN */ + 0 16 1 0 1 0 /* TX_ER */ + 0 1d 2 0 1 0 /* RX_DV */ + 0 1e 2 0 1 0 /* RX_ER */ + 0 1f 2 0 1 0 /* RX_CLK */ + 2 2 1 0 2 0 /* GTX_CLK - CLK10 */ + 2 3 2 0 1 0 /* GTX125 - CLK4 */ + 0 1 3 0 2 0 /* MDIO */ + 0 2 1 0 1 0>; /* MDC */ + }; + + }; + }; + + qe@e0100000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "qe"; + model = "QE"; + ranges = <0 e0100000 00100000>; + reg = ; + brg-frequency = <0>; + bus-frequency = <179A7B00>; + + muram@10000 { + device_type = "muram"; + ranges = <0 00010000 0000c000>; + + data-only@0{ + reg = <0 c000>; + }; + }; + + spi@4c0 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <4c0 40>; + interrupts = <2>; + interrupt-parent = <80>; + mode = "cpu"; + }; + + spi@500 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <500 40>; + interrupts = <1>; + interrupt-parent = <80>; + mode = "cpu"; + }; + + usb@6c0 { + device_type = "usb"; + compatible = "qe_udc"; + reg = <6c0 40 8B00 100>; + interrupts = ; + interrupt-parent = <80>; + mode = "slave"; + }; + + ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <1>; + reg = <2000 200>; + interrupts = <20>; + interrupt-parent = <80>; + mac-address = [ 00 04 9f 00 23 23 ]; + rx-clock = <0>; + tx-clock = <19>; + phy-handle = <212000>; + pio-handle = <140001>; + }; + + ucc@3000 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <2>; + reg = <3000 200>; + interrupts = <21>; + interrupt-parent = <80>; + mac-address = [ 00 11 22 33 44 55 ]; + rx-clock = <0>; + tx-clock = <14>; + phy-handle = <212001>; + pio-handle = <140002>; + }; + + mdio@2120 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2120 18>; + device_type = "mdio"; + compatible = "ucc_geth_phy"; + + ethernet-phy@00 { + linux,phandle = <212000>; + interrupt-parent = <700>; + interrupts = <11 2>; + reg = <0>; + device_type = "ethernet-phy"; + interface = <6>; //ENET_1000_GMII + }; + ethernet-phy@01 { + linux,phandle = <212001>; + interrupt-parent = <700>; + interrupts = <12 2>; + reg = <1>; + device_type = "ethernet-phy"; + interface = <6>; + }; + }; + + qeic@80 { + linux,phandle = <80>; + interrupt-controller; + device_type = "qeic"; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <80 80>; + built-in; + big-endian; + interrupts = <20 8 21 8>; //high:32 low:33 + interrupt-parent = <700>; + }; + + }; +}; -- GitLab From 6c4a2501d0b9fe90882efea5541275a46cda2a1a Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 2 Oct 2006 20:10:24 -0500 Subject: [PATCH 0383/1619] [POWERPC] Add initial support for the e300c2 core Add support for the Freescale e300c2 core found in the MPC832x processor line. As far as initial kernel support is concerned, the e300c2 core is identical to the e300c1 found in the mpc834x, except that it's had its floating point unit chopped off. Signed-off-by: Kim Phillips Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 190a57e2076..47a613cdd77 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -763,10 +763,10 @@ struct cpu_spec cpu_specs[] = { .cpu_setup = __setup_cpu_603, .platform = "ppc603", }, - { /* e300 (a 603e core, plus some) on 83xx */ + { /* e300c1 (a 603e core, plus some) on 83xx */ .pvr_mask = 0x7fff0000, .pvr_value = 0x00830000, - .cpu_name = "e300", + .cpu_name = "e300c1", .cpu_features = CPU_FTRS_E300, .cpu_user_features = COMMON_USER, .icache_bsize = 32, @@ -774,6 +774,17 @@ struct cpu_spec cpu_specs[] = { .cpu_setup = __setup_cpu_603, .platform = "ppc603", }, + { /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */ + .pvr_mask = 0x7fff0000, + .pvr_value = 0x00840000, + .cpu_name = "e300c2", + .cpu_features = CPU_FTRS_E300, + .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .icache_bsize = 32, + .dcache_bsize = 32, + .cpu_setup = __setup_cpu_603, + .platform = "ppc603", + }, { /* default match, we assume split I/D cache & TB (non-601)... */ .pvr_mask = 0x00000000, .pvr_value = 0x00000000, -- GitLab From 9020fc960b8f5fbca0de6e4d11881ddc827aa61d Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 2 Oct 2006 20:10:30 -0500 Subject: [PATCH 0384/1619] [POWERPC] Add support for the mpc832x mds board Add support for MPC832x MDS evaluation board. This patch depends on the 8360+QE lib patches by Leo. The MPC832x processors (MPC8323E, MPC8323, MPC8321E, MPC8321) sport the e300c2 core plus a QUICC Engine (QE). This patch adds support for the 832x MDS evaluation board. The 832x MDS dts and defconfig files are pending more tests. Signed-off-by: Kim Phillips Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/83xx/Kconfig | 13 ++ arch/powerpc/platforms/83xx/mpc832x_mds.c | 215 ++++++++++++++++++++++ arch/powerpc/platforms/83xx/mpc832x_mds.h | 19 ++ 3 files changed, 247 insertions(+) create mode 100644 arch/powerpc/platforms/83xx/mpc832x_mds.c create mode 100644 arch/powerpc/platforms/83xx/mpc832x_mds.h diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 5fe7b7faf45..0975e94ac7c 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -5,6 +5,13 @@ choice prompt "Machine Type" default MPC834x_SYS +config MPC832x_MDS + bool "Freescale MPC832x MDS" + select DEFAULT_UIMAGE + select QUICC_ENGINE + help + This option enables support for the MPC832x MDS evaluation board. + config MPC834x_SYS bool "Freescale MPC834x SYS" select DEFAULT_UIMAGE @@ -27,6 +34,12 @@ config MPC834x_ITX endchoice +config PPC_MPC832x + bool + select PPC_UDBG_16550 + select PPC_INDIRECT_PCI + default y if MPC832x_MDS + config MPC834x bool select PPC_UDBG_16550 diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c new file mode 100644 index 00000000000..54dea9d42dc --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Description: + * MPC832xE MDS board specific 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. + */ + +#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 "mpc83xx.h" +#include "mpc832x_mds.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +static u8 *bcsr_regs = NULL; + +u8 *get_bcsr(void) +{ + return bcsr_regs; +} + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init mpc832x_sys_setup_arch(void) +{ + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("mpc832x_sys_setup_arch()", 0); + + np = of_find_node_by_type(NULL, "cpu"); + if (np != 0) { + unsigned int *fp = + (int *)get_property(np, "clock-frequency", NULL); + if (fp != 0) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(np); + } + + /* Map BCSR area */ + np = of_find_node_by_name(NULL, "bcsr"); + if (np != 0) { + struct resource res; + + of_address_to_resource(np, 0, &res); + bcsr_regs = ioremap(res.start, res.end - res.start +1); + of_node_put(np); + } + +#ifdef CONFIG_PCI + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + add_bridge(np); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_exclude_device = mpc83xx_exclude_device; +#endif + +#ifdef CONFIG_QUICC_ENGINE + qe_reset(); + + if ((np = of_find_node_by_name(np, "par_io")) != NULL) { + par_io_init(np); + of_node_put(np); + + for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;) + par_io_of_config(np); + } + + if ((np = of_find_compatible_node(NULL, "network", "ucc_geth")) + != NULL){ + /* Reset the Ethernet PHY */ + bcsr_regs[9] &= ~0x20; + udelay(1000); + bcsr_regs[9] |= 0x20; + iounmap(bcsr_regs); + of_node_put(np); + } + +#endif /* CONFIG_QUICC_ENGINE */ + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +void __init mpc832x_sys_init_IRQ(void) +{ + + struct device_node *np; + + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); + of_node_put(np); + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_node_by_type(NULL, "qeic"); + if (!np) + return; + + qe_ic_init(np, 0); + of_node_put(np); +#endif /* CONFIG_QUICC_ENGINE */ +} + +#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) +extern ulong ds1374_get_rtc_time(void); +extern int ds1374_set_rtc_time(ulong); + +static int __init mpc832x_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.get_rtc_time = ds1374_get_rtc_time; + ppc_md.set_rtc_time = ds1374_set_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time) (); + do_settimeofday(&tv); + + return 0; +} + +late_initcall(mpc832x_rtc_hookup); +#endif + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc832x_sys_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + + if (model == NULL) + return 0; + if (strcmp(model, "MPC8323EMDS")) + return 0; + + DBG("%s found\n", model); + + return 1; +} + +define_machine(mpc832x_mds) { + .name = "MPC832x MDS", + .probe = mpc832x_sys_probe, + .setup_arch = mpc832x_sys_setup_arch, + .init_IRQ = mpc832x_sys_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h new file mode 100644 index 00000000000..a49588904f8 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Description: + * MPC832x MDS board specific header. + * + * 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 __MACH_MPC832x_MDS_H__ +#define __MACH_MPC832x_MDS_H__ + +extern u8 *get_bcsr(void); + +#endif /* __MACH_MPC832x_MDS_H__ */ -- GitLab From f1da70632fa0875f80fc60991a010c31f40983ff Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 2 Oct 2006 16:10:47 -0700 Subject: [PATCH 0385/1619] [NETFILTER]: Kconfig: fix xt_physdev dependencies xt_physdev depends on bridge netfilter, which is a boolean, but can still be built modular because of special handling in the bridge makefile. Add a dependency on BRIDGE to prevent XT_MATCH_PHYSDEV=y, BRIDGE=m. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 0a28d2c5c44..ce94732b8e2 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -365,7 +365,7 @@ config NETFILTER_XT_MATCH_MULTIPORT config NETFILTER_XT_MATCH_PHYSDEV tristate '"physdev" match support' - depends on NETFILTER_XTABLES && BRIDGE_NETFILTER + depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER help Physdev packet matching matches against the physical bridge ports the IP packet arrived on or will leave by. -- GitLab From b4c4ed175ff0ee816df48571cfa9b73f521964b6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 2 Oct 2006 16:11:13 -0700 Subject: [PATCH 0386/1619] [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(-) diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index ce02c984f3b..5b63a231a76 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 5ac15379a0c..e2005c6810a 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 021395b6746..d85d2de5044 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 e62ea2bb9c0..b91f3582359 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; } -- GitLab From 901eaf6c8f997f18ebc8fcbb85411c79161ab3b2 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 2 Oct 2006 16:11:51 -0700 Subject: [PATCH 0387/1619] [NETFILTER]: Honour source routing for LVS-NAT For policy routing, packets originating from this machine itself may be routed differently to packets passing through. We want this packet to be routed as if it came from this machine itself. So re-compute the routing information using ip_route_me_harder(). This patch is derived from work by Ken Brownfield Cc: Ken Brownfield Signed-off-by: Simon Horman Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/ipvs/ip_vs_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 6dee03935f7..1445bb47fea 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -813,6 +813,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, skb->nh.iph->saddr = cp->vaddr; ip_send_check(skb->nh.iph); + /* For policy routing, packets originating from this + * machine itself may be routed differently to packets + * passing through. We want this packet to be routed as + * if it came from this machine itself. So re-compute + * the routing information. + */ + if (ip_route_me_harder(pskb, RTN_LOCAL) != 0) + goto drop; + skb = *pskb; + IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); ip_vs_out_stats(cp, skb); -- GitLab From 9d02002d2dc2c7423e5891b97727fde4d667adf1 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 2 Oct 2006 16:12:20 -0700 Subject: [PATCH 0388/1619] [NETFILTER]: ipt_REJECT: remove largely duplicate route_reverse function Use ip_route_me_harder instead, which now allows to specify how we wish the packet to be routed. Based on patch by Simon Horman . Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_REJECT.c | 97 +++++++-------------------------- 1 file changed, 19 insertions(+), 78 deletions(-) diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index fd0c05efed8..ad0312d0e4f 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -38,76 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT target module"); #define DEBUGP(format, args...) #endif -static inline struct rtable *route_reverse(struct sk_buff *skb, - struct tcphdr *tcph, int hook) -{ - struct iphdr *iph = skb->nh.iph; - struct dst_entry *odst; - struct flowi fl = {}; - struct rtable *rt; - - /* We don't require ip forwarding to be enabled to be able to - * send a RST reply for bridged traffic. */ - if (hook != NF_IP_FORWARD -#ifdef CONFIG_BRIDGE_NETFILTER - || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED) -#endif - ) { - fl.nl_u.ip4_u.daddr = iph->saddr; - if (hook == NF_IP_LOCAL_IN) - fl.nl_u.ip4_u.saddr = iph->daddr; - fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); - - if (ip_route_output_key(&rt, &fl) != 0) - return NULL; - } else { - /* non-local src, find valid iif to satisfy - * rp-filter when calling ip_route_input. */ - fl.nl_u.ip4_u.daddr = iph->daddr; - if (ip_route_output_key(&rt, &fl) != 0) - return NULL; - - odst = skb->dst; - if (ip_route_input(skb, iph->saddr, iph->daddr, - RT_TOS(iph->tos), rt->u.dst.dev) != 0) { - dst_release(&rt->u.dst); - return NULL; - } - dst_release(&rt->u.dst); - rt = (struct rtable *)skb->dst; - skb->dst = odst; - - fl.nl_u.ip4_u.daddr = iph->saddr; - fl.nl_u.ip4_u.saddr = iph->daddr; - fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); - } - - if (rt->u.dst.error) { - dst_release(&rt->u.dst); - return NULL; - } - - fl.proto = IPPROTO_TCP; - fl.fl_ip_sport = tcph->dest; - fl.fl_ip_dport = tcph->source; - security_skb_classify_flow(skb, &fl); - - xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); - - return rt; -} - /* Send RST reply */ static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; struct iphdr *iph = oldskb->nh.iph; struct tcphdr _otcph, *oth, *tcph; - struct rtable *rt; __be16 tmp_port; __be32 tmp_addr; int needs_ack; - int hh_len; + unsigned int addr_type; /* IP header checks: fragment. */ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) @@ -126,23 +66,13 @@ static void send_reset(struct sk_buff *oldskb, int hook) if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) return; - if ((rt = route_reverse(oldskb, oth, hook)) == NULL) - return; - - hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); - /* We need a linear, writeable skb. We also need to expand headroom in case hh_len of incoming interface < hh_len of outgoing interface */ - nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), + nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb), GFP_ATOMIC); - if (!nskb) { - dst_release(&rt->u.dst); + if (!nskb) return; - } - - dst_release(nskb->dst); - nskb->dst = &rt->u.dst; /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); @@ -184,6 +114,21 @@ static void send_reset(struct sk_buff *oldskb, int hook) tcph->window = 0; tcph->urg_ptr = 0; + /* Set DF, id = 0 */ + nskb->nh.iph->frag_off = htons(IP_DF); + nskb->nh.iph->id = 0; + + addr_type = RTN_UNSPEC; + if (hook != NF_IP_FORWARD +#ifdef CONFIG_BRIDGE_NETFILTER + || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED) +#endif + ) + addr_type = RTN_LOCAL; + + if (ip_route_me_harder(&nskb, addr_type)) + goto free_nskb; + /* Adjust TCP checksum */ nskb->ip_summed = CHECKSUM_NONE; tcph->check = 0; @@ -192,12 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) nskb->nh.iph->daddr, csum_partial((char *)tcph, sizeof(struct tcphdr), 0)); - - /* Adjust IP TTL, DF */ + /* Adjust IP TTL */ nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); - /* Set DF, id = 0 */ - nskb->nh.iph->frag_off = htons(IP_DF); - nskb->nh.iph->id = 0; /* Adjust IP checksum */ nskb->nh.iph->check = 0; -- GitLab From b18dfa90c008850e0f3bfd63638dd8fbe8e08701 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Mon, 2 Oct 2006 16:12:52 -0700 Subject: [PATCH 0389/1619] [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(-) diff --git a/include/linux/netfilter_bridge/ebt_mark_t.h b/include/linux/netfilter_bridge/ebt_mark_t.h index 110fec6a40a..6270f6f3369 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 770c0df972a..b54306a934e 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; } -- GitLab From 81771b3b20fb4e98c6f2b2aac2bc10ed41a8f006 Mon Sep 17 00:00:00 2001 From: Ismail Donmez Date: Tue, 3 Oct 2006 13:49:10 -0700 Subject: [PATCH 0390/1619] [NET_SCHED]: Revert "HTB: fix incorrect use of RB_EMPTY_NODE" With commit 10fd48f2376db52f08bf0420d2c4f580e39269e1 [1] , RB_EMPTY_NODE changed behaviour so it returns true when the node is empty as expected. Hence Patrick McHardy's fix for sched_htb.c should be reverted. Signed-off-by: Ismail Donmez ACKed-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 6c058e3660c..bb3ddd4784b 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -391,7 +391,7 @@ static inline void htb_add_class_to_row(struct htb_sched *q, /* If this triggers, it is a bug in this code, but it need not be fatal */ static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root) { - if (!RB_EMPTY_NODE(rb)) { + if (RB_EMPTY_NODE(rb)) { WARN_ON(1); } else { rb_erase(rb, root); -- GitLab From 132a55f3c5c0b1a364d32f65595ad8838c30a60e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 3 Oct 2006 14:34:00 -0700 Subject: [PATCH 0391/1619] [UDP6]: Fix flowi clobbering The udp6_sendmsg function uses a shared buffer to store the flow without taking any locks. This leads to races with SMP. This patch moves the flowi object onto the stack. Signed-off-by: Herbert Xu Acked-by: James Morris Signed-off-by: David S. Miller --- net/ipv6/udp.c | 62 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9662561701d..552ec0f449a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -546,7 +546,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct in6_addr *daddr, *final_p = NULL, final; struct ipv6_txoptions *opt = NULL; struct ip6_flowlabel *flowlabel = NULL; - struct flowi *fl = &inet->cork.fl; + struct flowi fl; struct dst_entry *dst; int addr_len = msg->msg_namelen; int ulen = len; @@ -626,19 +626,19 @@ do_udp_sendmsg: } ulen += sizeof(struct udphdr); - memset(fl, 0, sizeof(*fl)); + memset(&fl, 0, sizeof(fl)); if (sin6) { if (sin6->sin6_port == 0) return -EINVAL; - fl->fl_ip_dport = sin6->sin6_port; + fl.fl_ip_dport = sin6->sin6_port; daddr = &sin6->sin6_addr; if (np->sndflow) { - fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; - if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) { - flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); + fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; + if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); if (flowlabel == NULL) return -EINVAL; daddr = &flowlabel->dst; @@ -656,32 +656,32 @@ do_udp_sendmsg: if (addr_len >= sizeof(struct sockaddr_in6) && sin6->sin6_scope_id && ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) - fl->oif = sin6->sin6_scope_id; + fl.oif = sin6->sin6_scope_id; } else { if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; - fl->fl_ip_dport = inet->dport; + fl.fl_ip_dport = inet->dport; daddr = &np->daddr; - fl->fl6_flowlabel = np->flow_label; + fl.fl6_flowlabel = np->flow_label; connected = 1; } - if (!fl->oif) - fl->oif = sk->sk_bound_dev_if; + if (!fl.oif) + fl.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { opt = &opt_space; memset(opt, 0, sizeof(struct ipv6_txoptions)); opt->tot_len = sizeof(*opt); - err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass); + err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); if (err < 0) { fl6_sock_release(flowlabel); return err; } - if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { - flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); + if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); if (flowlabel == NULL) return -EINVAL; } @@ -695,39 +695,39 @@ do_udp_sendmsg: opt = fl6_merge_options(&opt_space, flowlabel, opt); opt = ipv6_fixup_options(&opt_space, opt); - fl->proto = IPPROTO_UDP; - 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); - fl->fl_ip_sport = inet->sport; + fl.proto = IPPROTO_UDP; + 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); + fl.fl_ip_sport = inet->sport; /* merge ip6_build_xmit from ip6_output */ if (opt && opt->srcrt) { struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; - ipv6_addr_copy(&final, &fl->fl6_dst); - ipv6_addr_copy(&fl->fl6_dst, rt0->addr); + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); final_p = &final; connected = 0; } - if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) { - fl->oif = np->mcast_oif; + if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { + fl.oif = np->mcast_oif; connected = 0; } - security_sk_classify_flow(sk, fl); + security_sk_classify_flow(sk, &fl); - err = ip6_sk_dst_lookup(sk, &dst, fl); + err = ip6_sk_dst_lookup(sk, &dst, &fl); if (err) goto out; if (final_p) - ipv6_addr_copy(&fl->fl6_dst, final_p); + ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) goto out; if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl->fl6_dst)) + if (ipv6_addr_is_multicast(&fl.fl6_dst)) hlimit = np->mcast_hops; else hlimit = np->hop_limit; @@ -763,7 +763,7 @@ back_from_confirm: do_append_data: up->len += ulen; err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), hlimit, tclass, opt, fl, + sizeof(struct udphdr), hlimit, tclass, opt, &fl, (struct rt6_info*)dst, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) @@ -774,10 +774,10 @@ do_append_data: if (dst) { if (connected) { ip6_dst_store(sk, dst, - ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? + ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? &np->daddr : NULL, #ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_equal(&fl->fl6_src, &np->saddr) ? + ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? &np->saddr : #endif NULL); -- GitLab From 1e0c14f49d6b393179f423abbac47f85618d3d46 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 3 Oct 2006 14:35:49 -0700 Subject: [PATCH 0392/1619] [UDP]: Fix MSG_PROBE crash UDP tracks corking status through the pending variable. The IP layer also tracks it through the socket write queue. It is possible for the two to get out of sync when MSG_PROBE is used. This patch changes UDP to check the write queue to ensure that the two stay in sync. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/udp.c | 2 ++ net/ipv6/udp.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6d6142f9c47..865d75214a9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -675,6 +675,8 @@ do_append_data: udp_flush_pending_frames(sk); else if (!corkreq) err = udp_push_pending_frames(sk, up); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; release_sock(sk); out: diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 552ec0f449a..e0c3934a7e4 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -770,6 +770,8 @@ do_append_data: udp_v6_flush_pending_frames(sk); else if (!corkreq) err = udp_v6_push_pending_frames(sk, up); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; if (dst) { if (connected) { -- GitLab From c5e29460f5f9eb189cab5d9fdaa137e64f7734b6 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Tue, 3 Oct 2006 15:49:46 -0700 Subject: [PATCH 0393/1619] [NEIGH]: always use hash_mask under tbl lock Make sure hash_mask is protected with tbl->lock in all cases just like the hash_buckets. Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller --- net/core/neighbour.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 8ce8c471d86..b4b478353b2 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -344,12 +344,12 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, { struct neighbour *n; int key_len = tbl->key_len; - u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; + u32 hash_val = tbl->hash(pkey, dev); NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); - for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { + for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); NEIGH_CACHE_STAT_INC(tbl, hits); @@ -364,12 +364,12 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey) { struct neighbour *n; int key_len = tbl->key_len; - u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask; + u32 hash_val = tbl->hash(pkey, NULL); NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); - for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { + for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); NEIGH_CACHE_STAT_INC(tbl, hits); @@ -1998,12 +1998,12 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, int rc, h, s_h = cb->args[1]; int idx, s_idx = idx = cb->args[2]; + read_lock_bh(&tbl->lock); for (h = 0; h <= tbl->hash_mask; h++) { if (h < s_h) continue; if (h > s_h) s_idx = 0; - read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) { if (idx < s_idx) continue; @@ -2016,8 +2016,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, goto out; } } - read_unlock_bh(&tbl->lock); } + read_unlock_bh(&tbl->lock); rc = skb->len; out: cb->args[1] = h; -- GitLab From 667bbcb6c099d1b74f95c6963ddf37a32e7afc29 Mon Sep 17 00:00:00 2001 From: Masahide NAKAMURA Date: Tue, 3 Oct 2006 15:56:09 -0700 Subject: [PATCH 0394/1619] [XFRM] STATE: Use destination address for src hash. Src hash is introduced for Mobile IPv6 route optimization usage. On current kenrel code it is calculated with source address only. It results we uses the same hash value for outbound state (when the node has only one address for Mobile IPv6). This patch use also destination address as peer information for src hash to be dispersed. Signed-off-by: Masahide NAKAMURA Signed-off-by: David S. Miller --- net/xfrm/xfrm_hash.h | 7 ++++--- net/xfrm/xfrm_state.c | 16 +++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h index 6ac4e4f033a..d401dc8f05e 100644 --- a/net/xfrm/xfrm_hash.h +++ b/net/xfrm/xfrm_hash.h @@ -41,17 +41,18 @@ static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t return (h ^ (h >> 16)) & hmask; } -static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr, +static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr, + xfrm_address_t *saddr, unsigned short family, unsigned int hmask) { unsigned int h = family; switch (family) { case AF_INET: - h ^= __xfrm4_addr_hash(saddr); + h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); break; case AF_INET6: - h ^= __xfrm6_addr_hash(saddr); + h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); break; }; return (h ^ (h >> 16)) & hmask; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f927b7330f0..39b8bf3a9de 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -63,10 +63,11 @@ static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); } -static inline unsigned int xfrm_src_hash(xfrm_address_t *addr, +static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr, + xfrm_address_t *saddr, unsigned short family) { - return __xfrm_src_hash(addr, family, xfrm_state_hmask); + return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask); } static inline unsigned int @@ -92,7 +93,8 @@ static void xfrm_hash_transfer(struct hlist_head *list, nhashmask); hlist_add_head(&x->bydst, ndsttable+h); - h = __xfrm_src_hash(&x->props.saddr, x->props.family, + h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, + x->props.family, nhashmask); hlist_add_head(&x->bysrc, nsrctable+h); @@ -458,7 +460,7 @@ static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) { - unsigned int h = xfrm_src_hash(saddr, family); + unsigned int h = xfrm_src_hash(daddr, saddr, family); struct xfrm_state *x; struct hlist_node *entry; @@ -587,7 +589,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, if (km_query(x, tmpl, pol) == 0) { x->km.state = XFRM_STATE_ACQ; hlist_add_head(&x->bydst, xfrm_state_bydst+h); - h = xfrm_src_hash(saddr, family); + h = xfrm_src_hash(daddr, saddr, family); hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); if (x->id.spi) { h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); @@ -622,7 +624,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) x->props.reqid, x->props.family); hlist_add_head(&x->bydst, xfrm_state_bydst+h); - h = xfrm_src_hash(&x->props.saddr, x->props.family); + h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family); hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); if (x->id.spi) { @@ -748,7 +750,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; add_timer(&x->timer); hlist_add_head(&x->bydst, xfrm_state_bydst+h); - h = xfrm_src_hash(saddr, family); + h = xfrm_src_hash(daddr, saddr, family); hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); wake_up(&km_waitq); } -- GitLab From ae8c05779ac2f286b872db9ebea0c3c0a031ad1e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 Oct 2006 16:00:26 -0700 Subject: [PATCH 0395/1619] [XFRM]: Clearing xfrm_policy_count[] to zero during flush is incorrect. When we flush policies, we do a type match so we might not actually delete all policies matching a certain direction. So keep track of how many policies we actually kill and subtract that number from xfrm_policy_count[dir] at the end. Based upon a patch by Masahide NAKAMURA. Signed-off-by: David S. Miller --- net/xfrm/xfrm_policy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b6e2e79d726..2a7861661f1 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -778,8 +778,9 @@ void xfrm_policy_flush(u8 type) for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { struct xfrm_policy *pol; struct hlist_node *entry; - int i; + int i, killed; + killed = 0; again1: hlist_for_each_entry(pol, entry, &xfrm_policy_inexact[dir], bydst) { @@ -790,6 +791,7 @@ void xfrm_policy_flush(u8 type) write_unlock_bh(&xfrm_policy_lock); xfrm_policy_kill(pol); + killed++; write_lock_bh(&xfrm_policy_lock); goto again1; @@ -807,13 +809,14 @@ void xfrm_policy_flush(u8 type) write_unlock_bh(&xfrm_policy_lock); xfrm_policy_kill(pol); + killed++; write_lock_bh(&xfrm_policy_lock); goto again2; } } - xfrm_policy_count[dir] = 0; + xfrm_policy_count[dir] -= killed; } atomic_inc(&flow_cache_genid); write_unlock_bh(&xfrm_policy_lock); -- GitLab From 617dbeaa3f2987acc83c1149409685005e9dd740 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 3 Oct 2006 16:25:34 -0700 Subject: [PATCH 0396/1619] [TIPC]: fix printk warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc spits out this warning: net/tipc/link.c: In function ‘link_retransmit_failure’: net/tipc/link.c:1669: warning: cast from pointer to integer of different size More than a little bit ugly, storing integers in void*, but at least the code is correct, unlike some of the more crufty Linux kernel code found elsewhere. Rather than having two casts to massage the value into u32, it's easier just to have a single cast and use "%lu", since it's just a printk. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- net/tipc/link.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 693f02eca6d..53bc8cb5adb 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1666,8 +1666,9 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf) char addr_string[16]; tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg)); - tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle); - + tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n", + (unsigned long) TIPC_SKB_CB(buf)->handle); + n_ptr = l_ptr->owner->next; tipc_node_lock(n_ptr); -- GitLab From 0c1cca1d8e0d58775dad43374f925e6cddf1bebc Mon Sep 17 00:00:00 2001 From: Om Narasimhan Date: Tue, 3 Oct 2006 16:27:18 -0700 Subject: [PATCH 0397/1619] [ATM]: kmalloc to kzalloc patches for drivers/atm Signed-off-by: Om Narasimhan Signed-off-by: Chas Williams Signed-off-by: David S. Miller --- drivers/atm/adummy.c | 6 ++---- drivers/atm/firestream.c | 12 +++--------- drivers/atm/he.c | 4 +--- drivers/atm/horizon.c | 4 +--- drivers/atm/idt77252.c | 23 ++++++----------------- drivers/atm/lanai.c | 8 +------- drivers/atm/zatm.c | 6 ++---- 7 files changed, 16 insertions(+), 47 deletions(-) diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c index 6cc93de0b71..ac2c10822be 100644 --- a/drivers/atm/adummy.c +++ b/drivers/atm/adummy.c @@ -113,15 +113,13 @@ static int __init adummy_init(void) printk(KERN_ERR "adummy: version %s\n", DRV_VERSION); - adummy_dev = (struct adummy_dev *) kmalloc(sizeof(struct adummy_dev), + adummy_dev = kzalloc(sizeof(struct adummy_dev), GFP_KERNEL); if (!adummy_dev) { - printk(KERN_ERR DEV_LABEL ": kmalloc() failed\n"); + printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n"); err = -ENOMEM; goto out; } - memset(adummy_dev, 0, sizeof(struct adummy_dev)); - atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL); if (!atm_dev) { printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n"); diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 38fc054bd67..5f25e5efefc 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1784,7 +1784,7 @@ static int __devinit fs_init (struct fs_dev *dev) write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1); dev->nchannels = FS155_NR_CHANNELS; } - dev->atm_vccs = kmalloc (dev->nchannels * sizeof (struct atm_vcc *), + dev->atm_vccs = kcalloc (dev->nchannels, sizeof (struct atm_vcc *), GFP_KERNEL); fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%Zd)\n", dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *)); @@ -1794,9 +1794,8 @@ static int __devinit fs_init (struct fs_dev *dev) /* XXX Clean up..... */ return 1; } - memset (dev->atm_vccs, 0, dev->nchannels * sizeof (struct atm_vcc *)); - dev->tx_inuse = kmalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL); + dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL); fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n", dev->atm_vccs, dev->nchannels / 8); @@ -1805,8 +1804,6 @@ static int __devinit fs_init (struct fs_dev *dev) /* XXX Clean up..... */ return 1; } - memset (dev->tx_inuse, 0, dev->nchannels / 8); - /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */ /* -- RAS2 : FS50 only: Default is OK. */ @@ -1893,14 +1890,11 @@ static int __devinit firestream_init_one (struct pci_dev *pci_dev, if (pci_enable_device(pci_dev)) goto err_out; - fs_dev = kmalloc (sizeof (struct fs_dev), GFP_KERNEL); + fs_dev = kzalloc (sizeof (struct fs_dev), GFP_KERNEL); fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%Zd)\n", fs_dev, sizeof (struct fs_dev)); if (!fs_dev) goto err_out; - - memset (fs_dev, 0, sizeof (struct fs_dev)); - atm_dev = atm_dev_register("fs", &ops, -1, NULL); if (!atm_dev) goto err_out_free_fs_dev; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index f2511b42dba..b22a9142b24 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -383,14 +383,12 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) } pci_set_drvdata(pci_dev, atm_dev); - he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev), + he_dev = kzalloc(sizeof(struct he_dev), GFP_KERNEL); if (!he_dev) { err = -ENOMEM; goto init_one_failure; } - memset(he_dev, 0, sizeof(struct he_dev)); - he_dev->pci_dev = pci_dev; he_dev->atm_dev = atm_dev; he_dev->atm_dev->dev_data = he_dev; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index d1113e845f9..209dba1c70d 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2719,7 +2719,7 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_ goto out_disable; } - dev = kmalloc(sizeof(hrz_dev), GFP_KERNEL); + dev = kzalloc(sizeof(hrz_dev), GFP_KERNEL); if (!dev) { // perhaps we should be nice: deregister all adapters and abort? PRINTD(DBG_ERR, "out of memory"); @@ -2727,8 +2727,6 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_ goto out_release; } - memset(dev, 0, sizeof(hrz_dev)); - pci_set_drvdata(pci_dev, dev); // grab IRQ and install handler - move this someplace more sensible diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index b0369bb20f0..7487f0ad68e 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -642,11 +642,9 @@ alloc_scq(struct idt77252_dev *card, int class) { struct scq_info *scq; - scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL); + scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL); if (!scq) return NULL; - memset(scq, 0, sizeof(struct scq_info)); - scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE, &scq->paddr); if (scq->base == NULL) { @@ -2142,11 +2140,9 @@ idt77252_init_est(struct vc_map *vc, int pcr) { struct rate_estimator *est; - est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL); + est = kzalloc(sizeof(struct rate_estimator), GFP_KERNEL); if (!est) return NULL; - memset(est, 0, sizeof(*est)); - est->maxcps = pcr < 0 ? -pcr : pcr; est->cps = est->maxcps; est->avcps = est->cps << 5; @@ -2451,14 +2447,12 @@ idt77252_open(struct atm_vcc *vcc) index = VPCI2VC(card, vpi, vci); if (!card->vcs[index]) { - card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL); + card->vcs[index] = kzalloc(sizeof(struct vc_map), GFP_KERNEL); if (!card->vcs[index]) { printk("%s: can't alloc vc in open()\n", card->name); up(&card->mutex); return -ENOMEM; } - memset(card->vcs[index], 0, sizeof(struct vc_map)); - card->vcs[index]->card = card; card->vcs[index]->index = index; @@ -2926,13 +2920,11 @@ open_card_oam(struct idt77252_dev *card) for (vci = 3; vci < 5; vci++) { index = VPCI2VC(card, vpi, vci); - vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL); + vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL); if (!vc) { printk("%s: can't alloc vc\n", card->name); return -ENOMEM; } - memset(vc, 0, sizeof(struct vc_map)); - vc->index = index; card->vcs[index] = vc; @@ -2995,12 +2987,11 @@ open_card_ubr0(struct idt77252_dev *card) { struct vc_map *vc; - vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL); + vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL); if (!vc) { printk("%s: can't alloc vc\n", card->name); return -ENOMEM; } - memset(vc, 0, sizeof(struct vc_map)); card->vcs[0] = vc; vc->class = SCHED_UBR0; @@ -3695,14 +3686,12 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) goto err_out_disable_pdev; } - card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL); + card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL); if (!card) { printk("idt77252-%d: can't allocate private data\n", index); err = -ENOMEM; goto err_out_disable_pdev; } - memset(card, 0, sizeof(struct idt77252_dev)); - card->revision = revision; card->index = index; card->pcidev = pcidev; diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index fe60a59b7fc..b9568e10965 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1482,16 +1482,10 @@ static inline void vcc_table_deallocate(const struct lanai_dev *lanai) static inline struct lanai_vcc *new_lanai_vcc(void) { struct lanai_vcc *lvcc; - lvcc = (struct lanai_vcc *) kmalloc(sizeof(*lvcc), GFP_KERNEL); + lvcc = kzalloc(sizeof(*lvcc), GFP_KERNEL); if (likely(lvcc != NULL)) { - lvcc->vbase = NULL; - lvcc->rx.atmvcc = lvcc->tx.atmvcc = NULL; - lvcc->nref = 0; - memset(&lvcc->stats, 0, sizeof lvcc->stats); - lvcc->rx.buf.start = lvcc->tx.buf.start = NULL; skb_queue_head_init(&lvcc->tx.backlog); #ifdef DEBUG - lvcc->tx.unqueue = NULL; lvcc->vci = -1; #endif } diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 2c65e82f0d6..c491ec455ca 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -603,9 +603,8 @@ static int start_rx(struct atm_dev *dev) DPRINTK("start_rx\n"); zatm_dev = ZATM_DEV(dev); size = sizeof(struct atm_vcc *)*zatm_dev->chans; - zatm_dev->rx_map = (struct atm_vcc **) kmalloc(size,GFP_KERNEL); + zatm_dev->rx_map = kzalloc(size,GFP_KERNEL); if (!zatm_dev->rx_map) return -ENOMEM; - memset(zatm_dev->rx_map,0,size); /* set VPI/VCI split (use all VCIs and give what's left to VPIs) */ zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR); /* prepare free buffer pools */ @@ -951,9 +950,8 @@ static int open_tx_first(struct atm_vcc *vcc) skb_queue_head_init(&zatm_vcc->tx_queue); init_waitqueue_head(&zatm_vcc->tx_wait); /* initialize ring */ - zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL); + zatm_vcc->ring = kzalloc(RING_SIZE,GFP_KERNEL); if (!zatm_vcc->ring) return -ENOMEM; - memset(zatm_vcc->ring,0,RING_SIZE); loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS; loop[0] = uPD98401_TXPD_V; loop[1] = loop[2] = 0; -- GitLab From 3a4e5e2033eb7558ebe307e46f5fb6e63b92cab8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 3 Oct 2006 16:27:55 -0700 Subject: [PATCH 0398/1619] [ATM]: [ambassador] Change the return type to reflect reality Signed-off-by: Jeff Garzik Signed-off-by: Chas Williams Signed-off-by: David S. Miller --- drivers/atm/ambassador.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 4521a249dd5..da599e6e9d3 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -915,8 +915,8 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id, /********** make rate (not quite as much fun as Horizon) **********/ -static unsigned int make_rate (unsigned int rate, rounding r, - u16 * bits, unsigned int * actual) { +static int make_rate (unsigned int rate, rounding r, + u16 * bits, unsigned int * actual) { unsigned char exp = -1; // hush gcc unsigned int man = -1; // hush gcc -- GitLab From 3e0c0ac84c01f41fb266bcdd2802708409901bed Mon Sep 17 00:00:00 2001 From: Chas Williams Date: Tue, 3 Oct 2006 16:28:31 -0700 Subject: [PATCH 0399/1619] [ATM]: [zatm] always *pcr in alloc_shaper() Signed-off-by: Chas Williams Signed-off-by: David S. Miller --- drivers/atm/zatm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index c491ec455ca..083c5d3f2e1 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -800,6 +800,7 @@ static int alloc_shaper(struct atm_dev *dev,int *pcr,int min,int max,int ubr) i = m = 1; zatm_dev->ubr_ref_cnt++; zatm_dev->ubr = shaper; + *pcr = 0; } else { if (min) { -- GitLab From 2473ffe3cae0f86341958e3cf962bb4fc261d028 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 3 Oct 2006 16:29:52 -0700 Subject: [PATCH 0400/1619] [NET_SCHED]: Remove old estimator implementation Remove unused file, estimators live in net/core/gen_estimator.c now. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/estimator.c | 196 ------------------------------------------ 1 file changed, 196 deletions(-) delete mode 100644 net/sched/estimator.c diff --git a/net/sched/estimator.c b/net/sched/estimator.c deleted file mode 100644 index 0ebc98e9be2..00000000000 --- a/net/sched/estimator.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * net/sched/estimator.c Simple rate estimator. - * - * 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. - * - * Authors: Alexey Kuznetsov, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - This code is NOT intended to be used for statistics collection, - its purpose is to provide a base for statistical multiplexing - for controlled load service. - If you need only statistics, run a user level daemon which - periodically reads byte counters. - - Unfortunately, rate estimation is not a very easy task. - F.e. I did not find a simple way to estimate the current peak rate - and even failed to formulate the problem 8)8) - - So I preferred not to built an estimator into the scheduler, - but run this task separately. - Ideally, it should be kernel thread(s), but for now it runs - from timers, which puts apparent top bounds on the number of rated - flows, has minimal overhead on small, but is enough - to handle controlled load service, sets of aggregates. - - We measure rate over A=(1<next) { - struct tc_stats *st = e->stats; - u64 nbytes; - u32 npackets; - u32 rate; - - spin_lock(e->stats_lock); - nbytes = st->bytes; - npackets = st->packets; - rate = (nbytes - e->last_bytes)<<(7 - idx); - e->last_bytes = nbytes; - e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log; - st->bps = (e->avbps+0xF)>>5; - - rate = (npackets - e->last_packets)<<(12 - idx); - e->last_packets = npackets; - e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log; - e->stats->pps = (e->avpps+0x1FF)>>10; - spin_unlock(e->stats_lock); - } - - mod_timer(&elist[idx].timer, jiffies + ((HZ<interval < -2 || parm->interval > 3) - return -EINVAL; - - est = kzalloc(sizeof(*est), GFP_KERNEL); - if (est == NULL) - return -ENOBUFS; - - est->interval = parm->interval + 2; - est->stats = stats; - est->stats_lock = stats_lock; - est->ewma_log = parm->ewma_log; - est->last_bytes = stats->bytes; - est->avbps = stats->bps<<5; - est->last_packets = stats->packets; - est->avpps = stats->pps<<10; - - est->next = elist[est->interval].list; - if (est->next == NULL) { - init_timer(&elist[est->interval].timer); - elist[est->interval].timer.data = est->interval; - elist[est->interval].timer.expires = jiffies + ((HZ<interval)/4); - elist[est->interval].timer.function = est_timer; - add_timer(&elist[est->interval].timer); - } - write_lock_bh(&est_lock); - elist[est->interval].list = est; - write_unlock_bh(&est_lock); - return 0; -} - -void qdisc_kill_estimator(struct tc_stats *stats) -{ - int idx; - struct qdisc_estimator *est, **pest; - - for (idx=0; idx <= EST_MAX_INTERVAL; idx++) { - int killed = 0; - pest = &elist[idx].list; - while ((est=*pest) != NULL) { - if (est->stats != stats) { - pest = &est->next; - continue; - } - - write_lock_bh(&est_lock); - *pest = est->next; - write_unlock_bh(&est_lock); - - kfree(est); - killed++; - } - if (killed && elist[idx].list == NULL) - del_timer(&elist[idx].timer); - } -} - -EXPORT_SYMBOL(qdisc_kill_estimator); -EXPORT_SYMBOL(qdisc_new_estimator); -- GitLab From 80246ab36ec8baf7d107254adb166baa555a59f8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 Oct 2006 16:49:53 -0700 Subject: [PATCH 0401/1619] [TCP]: Kill warning in tcp_clean_rtx_queue(). GCC can't tell we always initialize 'tv' in all the cases we actually use it, so explicitly set it up with zeros. Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3f884cea14f..cf06accbe68 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2259,7 +2259,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) u32 pkts_acked = 0; void (*rtt_sample)(struct sock *sk, u32 usrtt) = icsk->icsk_ca_ops->rtt_sample; - struct timeval tv; + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; while ((skb = skb_peek(&sk->sk_write_queue)) && skb != sk->sk_send_head) { -- GitLab From 0a69452cb45add0841c2bc1e75c25f6bd4f1d8d9 Mon Sep 17 00:00:00 2001 From: Diego Beltrami Date: Tue, 3 Oct 2006 23:47:05 -0700 Subject: [PATCH 0402/1619] [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 diff --git a/include/linux/in.h b/include/linux/in.h index d79fc75fa7c..2619859f6e1 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 6b25d36fc54..ecee9bb27d0 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 d3c527616b5..d17a6302a0e 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 430afd05826..8ae7f744917 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 d172a980444..5572071af73 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 f66049e28ae..15645c51520 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 13b29360d10..b5c205b5766 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 2017d36024d..3839b706142 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 00000000000..89cf59ea7bb --- /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 a2d211da2ab..a460e8132b4 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 0213c6612b5..87274e47fe3 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 a2860e35efd..71f59f18ede 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 00000000000..edcfffa9e87 --- /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 c59a78d2923..d54b3a70d5d 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: -- GitLab From 038b0a6d8d32db934bba6a24e74e76e4e327a94f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 4 Oct 2006 03:38:54 -0400 Subject: [PATCH 0403/1619] 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(-) diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index fd4a8fa0c93..a94e6d93e2e 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 4342cea1a92..f6cfe8ce3f9 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 748175921f9..cec83783206 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 44a86c33796..0d1a1db4006 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 36eecd7161f..971c3e2d8e3 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 50e513681ae..98208740e7c 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 c6e0d51fbea..65e867ba2df 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 91e301924f2..6ef3c487982 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 272fe43bcec..35a954a44b1 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 62a8efd2325..0315615b74d 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 9e399211108..e310e4d7299 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 ef7482faad8..249ca9e57bc 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 fa958e9d6dd..7ca0e6170a4 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 93751fee793..1992db4c252 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 2291afe9f23..7530a95c15a 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 5e20e740cde..2494091a078 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 e1ce050d8fe..1ab84ced7b5 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 93c802bac26..fea1e17a365 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 756228ddd03..b986065cd0f 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 14cfc85e44b..2271d20ffed 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 2f9c9b5dd26..ce319ef64bc 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 b4633150f01..658bc4529c9 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 f6c3e30b1b4..5f62ade5be3 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 7e55884135e..44a9aebc4f5 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 e569d17b4ae..8abab3bc2b6 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 01f80b5c45d..ef6ad9e1a60 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 0c28f11d667..9a4d40b3d6a 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 6cfc984380d..28b2fefa451 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 ceef9bc181e..c7d6ad51382 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 3e7fe1e1491..31084466eae 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 3e79e62f7b0..eaad2328fea 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 9670a89c77f..a0580042930 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 8c676d763bb..5446bab08ec 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 effcbf78f85..46c3532992a 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 4c1fede6470..193a5d7921b 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 3f3859d12e0..2f194ba2989 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 033ad6e2827..0984c707169 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 e4f2b9df5e1..cb6f084844f 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 628482671c1..106896c3b60 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 9bd410b8fec..fa54351ac26 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 f3038461d4c..11de090eb90 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 0073527a703..8c880c0ca38 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 f5a5c0cd062..a6c0a138b0d 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 4d9ff5ce4cb..67914fe7f31 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 d33f8a07cca..54d51b40460 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 97bf87e8cdd..74bef2a2d37 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 718350aba1e..826118ee53d 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 238bbf6de07..7f920453577 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 5cc5ab63293..e21cd6afa70 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 d247ef45c37..a0d148ea63d 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 300a54a6523..c1c5604752f 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 ccea2d7885e..788da5439a2 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 6f13e7c71a8..ed9c59082d0 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 e4bfcfe8550..7a4897e27f4 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 fda4a394069..f0b0668458b 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 d86ee14260c..d0b690197fd 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 e7539a8451e..88e5e77bf51 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 d8869a6ef1b..b26986c0c3d 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 8a27353733a..df2397dba3e 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 4567f1eeb4a..5126a99b596 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 49ed5ddf070..8cde431348c 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 ce7f233fc49..eee97bb81ba 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 f030e44262b..0e00cf93f90 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 4aa9808ba26..2a32e5e8e9c 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 27bbf54b1e5..0d2cce62113 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 4cd2ff546ef..c17eddcf89b 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 6e84963dfc2..27eb29ce666 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 511116aebaf..759b0705316 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 b331e970002..239c98054de 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 c7b195c7e51..b5f124a2f6a 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 26506388a6a..68e1bf63cd0 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 84a23b14f77..4d1929dfa28 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 97d88e7902f..66f43c90682 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 69971b78bea..e299ee5a753 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 d5244f07053..171b3e9dc86 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 71b9796258e..643dab58572 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 f4d1a4d3cdc..cd06f47c0ea 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 2aa565c136e..d6ff88f3513 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 2fd5a67fd43..82ef182de6a 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 cfb09b07ae9..f760045d6d3 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 cbabfdf78e0..f61fb8e4f12 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 c3454af5e3a..6d77e4797a4 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 0ebb03b60e7..727a5d46d2f 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 b6cd3cca2f4..50be90975d0 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 967b22fa7d0..0ea0ddc875a 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 09ed1f6b0ea..2c5948116bd 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 0025535cac8..55e586d352d 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 99f87efe0f5..36b88f6c5f8 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 4abc193314e..ada68e65b5f 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 b8c22255f6a..9f8082f8dd2 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 65c9d2ec60b..21653244565 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 a61ef50f3df..dab63468688 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 14c07f08657..1ceec22b60b 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 3cf4d641a51..c9caff57db8 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 5426b1e5595..5c0dec39cf6 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 7719bd75810..4d47d79bcea 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 d1ecb2c6de9..73e32420991 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 57e31e5eaed..8fd71a5fc61 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 38d94987de8..a4150c4519c 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 8f89948832f..aaac94db0d8 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 8f90b90a502..5dbd7dc2936 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 6f8515db5b0..8e1e6e48e0a 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 2de6e497c14..f4872c87106 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 db2731ba88e..3a55fc6abcd 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 d965d074cd6..371ed4f69a9 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 952a28d485c..3e276e958ef 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 0cb7b9b520e..965c43659e3 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 68c74bbf8b0..c1cec236ecf 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 608cd760907..5f6950c2d1d 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 11b7378ff21..a82157db468 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 e9f06116c4d..599878c8e71 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 cef00744a9d..d231efa624d 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 1328e10caa3..baaae3dbf2e 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 21dc68eff51..a43e24245b7 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 94b47c8d0ab..f14e99276db 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 f91028c5386..67260eb3188 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 2f0b7772419..0b20dfacbf5 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 ee2ccad7048..734adc9d520 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 ece936ac29c..8f6f32fc61f 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 7511df3588e..ba8021427b8 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 3b35cb77953..a8f894c7819 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 c1adc9e4b23..7502109d37f 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 f336ba6778d..5c025d1190c 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 28643c4dc85..7ee992146ae 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 5fc14563ee3..20eb6e95a3a 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 aacdceb8f44..a5d2cdfff46 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 16332cc5794..ebb20ff7ac5 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 83601d4009e..64554acad63 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 cb2e2a604d1..0a315200b33 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 4640d1000d8..923e22db18d 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 bfde82f5d18..fc6cc147996 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 b88a09497c2..c6f2f488a40 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 a44124c7e85..a287836e39f 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 fb48feca835..bf26c3c5699 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 c1113d6e941..5686e2164e3 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 e7ba0c30e07..c04b3a14a3e 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 8106f3b29e4..6e4e48c5092 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 76b08ae9ed8..20c6f39ea38 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 60408646176..ec1114b33d8 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 24e47f3bbd1..b872779d7cd 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 1d656a64519..8dfefe41a8d 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 e8d40030cab..28659a919d6 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 c093642fb98..b67ce935404 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 bee02fd8dab..7d0ba18ad57 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 b13322dccf4..c1b264dff28 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 6c47e3b9484..f0510209ccb 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 4d68ddce18b..03620251ae1 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 4da41efb131..89ed545b446 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 4f55573762b..86ee46b09b8 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 7aefa301321..b759eab9b51 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 e4041f4fa4d..0b3f1a2bb2c 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 a91f5e55b52..479ffb0a22d 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 7f53cd1d8b1..f28c6e064e8 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 e7f2e7fa066..735705d137f 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 0c1faa950af..da8d6bf4645 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 948bd8f643e..6dcea9dd8c9 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 3f2a343c601..c2bff04c84e 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 3dbd6f4e747..f3514351aed 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 a2b6a9f96e5..45b124e012f 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 8ac6b732163..877f5093969 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 a99d87d82b7..6b0e63cacd9 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 34f5bfaddfc..d8c1057e8b0 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 99d116caecd..7ccdc8fc5a3 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 d31f8146952..f580942b5c0 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 fe59850be86..93537ab7c2a 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 24a9acd2816..0435c43d970 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 01c592cee04..1b968f7ecb3 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 ea51aafaf40..20628aa07a2 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 ea1c0207aef..6c910498924 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 a3d6ae33fe8..4539269b3d9 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 597db7aee63..de10cedee1c 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 aa3c50db66c..954647f41df 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 5548e3cff7c..5ef6e617911 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 317f22589a0..9130fcf9655 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 1dec3958cc7..38d9aa0f16a 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 6e22472df95..4c89af9ea03 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 ac1785f2b7e..75a751fb996 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 /* -- GitLab From 39666962a3c598f221bc99e835d9d6046a700d85 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 4 Oct 2006 08:01:59 -0300 Subject: [PATCH 0404/1619] V4L/DVB (4676a): Remove Kconfig item for DiB7000M support Support for DiB7000M frontend were not included on 2.6.19, since still not completed. Removing Kconfig item. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 67cefdd2334..2cc5caa26a0 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -69,7 +69,6 @@ config DVB_USB_DIBUSB_MC config DVB_USB_DIB0700 tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" depends on DVB_USB - select DVB_DIB7000M select DVB_DIB3000MC select DVB_TUNER_MT2060 help -- GitLab From 17b10a73e697da71faa3e54e35421aca4531aa9b Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Mon, 2 Oct 2006 19:55:07 -0300 Subject: [PATCH 0405/1619] V4L/DVB (4701): Saa713x audio fixes This change fixes the following issues: - resolve the SECAM D/K vs SECAM-L sound conflict It is now possible to select the SECAM version either by the VIDEOIOC_S_STD IO control or by the new secam= insmod option. The driver now adapts its audio standard search list to the selected standard. - don't trigger a sound standard search when a LINE input is selected. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-tvaudio.c | 93 ++++++++----------- drivers/media/video/saa7134/saa7134-video.c | 57 +++++++++++- drivers/media/video/saa7134/saa7134.h | 1 - 3 files changed, 95 insertions(+), 56 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index d31220d2049..dd759d6d8d2 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -72,12 +72,12 @@ static struct mainscan { int carr; } mainscan[] = { { - .name = "M", - .std = V4L2_STD_NTSC | V4L2_STD_PAL_M, + .name = "MN", + .std = V4L2_STD_MN, .carr = 4500, },{ - .name = "BG", - .std = V4L2_STD_PAL_BG, + .name = "BGH", + .std = V4L2_STD_B | V4L2_STD_GH, .carr = 5500, },{ .name = "I", @@ -85,7 +85,7 @@ static struct mainscan { .carr = 6000, },{ .name = "DKL", - .std = V4L2_STD_PAL_DK | V4L2_STD_SECAM, + .std = V4L2_STD_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC, .carr = 6500, } }; @@ -93,76 +93,70 @@ static struct mainscan { static struct saa7134_tvaudio tvaudio[] = { { .name = "PAL-B/G FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_BG, .mode = TVAUDIO_FM_BG_STEREO, .carr1 = 5500, .carr2 = 5742, },{ .name = "PAL-D/K1 FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 6258, .mode = TVAUDIO_FM_BG_STEREO, },{ .name = "PAL-D/K2 FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 6742, .mode = TVAUDIO_FM_BG_STEREO, },{ .name = "PAL-D/K3 FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 5742, .mode = TVAUDIO_FM_BG_STEREO, },{ .name = "PAL-B/G NICAM", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_BG, .carr1 = 5500, .carr2 = 5850, .mode = TVAUDIO_NICAM_FM, },{ .name = "PAL-I NICAM", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_I, .carr1 = 6000, .carr2 = 6552, .mode = TVAUDIO_NICAM_FM, },{ .name = "PAL-D/K NICAM", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 5850, .mode = TVAUDIO_NICAM_FM, },{ .name = "SECAM-L NICAM", - .std = V4L2_STD_SECAM, + .std = V4L2_STD_SECAM_L, .carr1 = 6500, .carr2 = 5850, .mode = TVAUDIO_NICAM_AM, },{ - .name = "SECAM-L MONO", - .std = V4L2_STD_SECAM, + .name = "SECAM-D/K NICAM", + .std = V4L2_STD_SECAM_DK, .carr1 = 6500, - .carr2 = -1, - .mode = TVAUDIO_AM_MONO, + .carr2 = 5850, + .mode = TVAUDIO_NICAM_FM, },{ - .name = "SECAM-D/K", - .std = V4L2_STD_SECAM, - .carr1 = 6500, - .carr2 = -1, - .mode = TVAUDIO_FM_MONO, + .name = "NTSC-A2 FM-stereo", + .std = V4L2_STD_NTSC, + .carr1 = 4500, + .carr2 = 4724, + .mode = TVAUDIO_FM_K_STEREO, },{ .name = "NTSC-M", .std = V4L2_STD_NTSC, .carr1 = 4500, .carr2 = -1, .mode = TVAUDIO_FM_MONO, - },{ - .name = "NTSC-A2 FM-stereo", - .std = V4L2_STD_NTSC, - .carr1 = 4500, - .carr2 = 4724, - .mode = TVAUDIO_FM_K_STEREO, } }; #define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio)) @@ -340,12 +334,6 @@ static void tvaudio_setmode(struct saa7134_dev *dev, saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); saa_writeb(SAA7134_NICAM_CONFIG, 0x00); break; - case TVAUDIO_AM_MONO: - saa_writeb(SAA7134_DEMODULATOR, 0x12); - saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); - saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); - saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); - break; case TVAUDIO_FM_SAT_STEREO: /* not implemented (yet) */ break; @@ -390,7 +378,6 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) } printk("\n"); } - if (dev->tvnorm->id & scan->std) { tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); saa_readl(SAA7134_LEVEL_READOUT1 >> 2); @@ -426,7 +413,6 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au switch (audio->mode) { case TVAUDIO_FM_MONO: - case TVAUDIO_AM_MONO: return V4L2_TUNER_SUB_MONO; case TVAUDIO_FM_K_STEREO: case TVAUDIO_FM_BG_STEREO: @@ -495,7 +481,6 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au switch (audio->mode) { case TVAUDIO_FM_MONO: - case TVAUDIO_AM_MONO: /* nothing to do ... */ break; case TVAUDIO_FM_K_STEREO: @@ -556,6 +541,7 @@ static int tvaudio_thread(void *data) if (1 == nscan) { /* only one candidate -- skip scan ;) */ + dprintk("only one main carrier candidate - skipping scan\n"); max1 = 12345; carrier = default_carrier; } else { @@ -603,7 +589,6 @@ static int tvaudio_thread(void *data) dev->automute = 0; saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00); saa7134_tvaudio_setmute(dev); - /* find the exact tv audio norm */ for (audio = UNSET, i = 0; i < TVAUDIO; i++) { if (dev->tvnorm->id != UNSET && @@ -611,7 +596,7 @@ static int tvaudio_thread(void *data) continue; if (tvaudio[i].carr1 != carrier) continue; - + /* Note: at least the primary carrier is right here */ if (UNSET == audio) audio = i; tvaudio_setmode(dev,&tvaudio[i],"trying"); @@ -626,6 +611,7 @@ static int tvaudio_thread(void *data) if (UNSET == audio) continue; tvaudio_setmode(dev,&tvaudio[audio],"using"); + tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO); dev->tvaudio = &tvaudio[audio]; @@ -750,7 +736,6 @@ static int mute_input_7133(struct saa7134_dev *dev) int mask; struct saa7134_input *in; - /* Hac 0506 route OSS sound simultanously */ xbarin = 0x03; switch (dev->input->amux) { case TV: @@ -834,18 +819,16 @@ static int tvaudio_thread_ddep(void *data) } else { /* (let chip) scan for sound carrier */ norms = 0; - if (dev->tvnorm->id & V4L2_STD_PAL) { - dprintk("PAL scan\n"); - norms |= 0x2c; /* B/G + D/K + I */ - } - if (dev->tvnorm->id & V4L2_STD_NTSC) { - dprintk("NTSC scan\n"); - norms |= 0x40; /* M */ - } - if (dev->tvnorm->id & V4L2_STD_SECAM) { - dprintk("SECAM scan\n"); - norms |= 0x18; /* L + D/K */ - } + if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH)) + norms |= 0x04; + if (dev->tvnorm->id & V4L2_STD_PAL_I) + norms |= 0x20; + if (dev->tvnorm->id & V4L2_STD_DK) + norms |= 0x08; + if (dev->tvnorm->id & V4L2_STD_MN) + norms |= 0x40; + if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) + norms |= 0x10; if (0 == norms) norms = 0x7c; /* all */ dprintk("scanning:%s%s%s%s%s\n", @@ -1034,7 +1017,11 @@ int saa7134_tvaudio_fini(struct saa7134_dev *dev) int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) { - if (dev->thread.pid >= 0) { + if (dev->input->amux != TV) { + dprintk("sound IF not in use, skipping scan\n"); + dev->automute = 0; + saa7134_tvaudio_setmute(dev); + } else if (dev->thread.pid >= 0) { dev->thread.mode = UNSET; dev->thread.scan2++; wake_up_interruptible(&dev->thread.wq); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 2c171af9a9f..557530aef94 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -43,12 +43,16 @@ static unsigned int gbuffers = 8; static unsigned int noninterlaced = 1; static unsigned int gbufsize = 720*576*4; static unsigned int gbufsize_max = 720*576*4; +static char secam[] = "--"; module_param(video_debug, int, 0644); MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); module_param(gbuffers, int, 0444); MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); module_param(noninterlaced, int, 0644); MODULE_PARM_DESC(noninterlaced,"capture non interlaced video"); +module_param_string(secam, secam, sizeof(secam), 0644); +MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); + #define dprintk(fmt, arg...) if (video_debug) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) @@ -279,7 +283,43 @@ static struct saa7134_tvnorm tvnorms[] = { .id = V4L2_STD_SECAM, NORM_625_50, - .sync_control = 0x18, /* old: 0x58, */ + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + + },{ + .name = "SECAM-DK", + .id = V4L2_STD_SECAM_DK, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + + },{ + .name = "SECAM-L", + .id = V4L2_STD_SECAM_L, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + + },{ + .name = "SECAM-Lc", + .id = V4L2_STD_SECAM_LC, + NORM_625_50, + + .sync_control = 0x18, .luma_control = 0x1b, .chroma_ctrl1 = 0xd1, .chroma_gain = 0x80, @@ -1769,6 +1809,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *id = arg; unsigned int i; + v4l2_std_id fixup; for (i = 0; i < TVNORMS; i++) if (*id == tvnorms[i].id) @@ -1779,7 +1820,19 @@ static int video_do_ioctl(struct inode *inode, struct file *file, break; if (i == TVNORMS) return -EINVAL; - + if (*id & V4L2_STD_SECAM) { + if (secam[0] == 'L' || secam[0] == 'l') + if (secam[1] == 'C' || secam[1] == 'c') + fixup = V4L2_STD_SECAM_LC; + else + fixup = V4L2_STD_SECAM_L; + else + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; + } mutex_lock(&dev->lock); if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 701a9094210..4a20d253a07 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -61,7 +61,6 @@ enum saa7134_tvaudio_mode { TVAUDIO_FM_K_STEREO = 4, TVAUDIO_NICAM_AM = 5, TVAUDIO_NICAM_FM = 6, - TVAUDIO_AM_MONO = 7 }; enum saa7134_audio_in { -- GitLab From 6b14ff9e901935a685ac430828452b53936dcbad Mon Sep 17 00:00:00 2001 From: Hermann Pitton Date: Mon, 2 Oct 2006 20:18:26 -0300 Subject: [PATCH 0406/1619] V4L/DVB (4702): Fix: set antenna input for DVB-T for Asus P7131 Dual hybrid This patch forces the correct antenna input input in DVB-T mode for this card. Signed-off-by: Hermann Pitton Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 32 +++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index fb741fa465a..f72a91f3025 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -874,6 +874,34 @@ static struct tda1004x_config philips_tiger_config = { /* ------------------------------------------------------------------ */ +static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x6a}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + /* make sure the DVB-T antenna input is set */ + saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); + return 0; +} + +static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x68}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_tuner_sleep( 0x61, fe); + /* reset antenna inputs for analog usage */ + saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); + return 0; +} + +/* ------------------------------------------------------------------ */ + static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { int ret; @@ -1148,8 +1176,8 @@ static int dvb_init(struct saa7134_dev *dev) &philips_tiger_config, &dev->i2c_adap); if (dev->dvb.frontend) { - dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; - dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep; dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; } break; -- GitLab From cf146ca4c2d56f275235526d9ada6c007313c7c7 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Mon, 2 Oct 2006 20:49:24 -0300 Subject: [PATCH 0407/1619] V4L/DVB (4703): Add support for the ASUS EUROPA2 OEM board This is a analog DVB-T hybrid board Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 35 +++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 12 +++++++ drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 49 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 6fb82ac3bef..53ce6a39083 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -98,3 +98,4 @@ 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300] 98 -> Proteus Pro 2309 [0919:2003] 99 -> AVerMedia TV Hybrid A16AR [1461:2c00] +100 -> Asus Europa2 OEM [1043:4860] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index fe3c83ca3de..c9d8e3b9cc3 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2994,6 +2994,34 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_ASUS_EUROPA2_HYBRID] = { + .name = "Asus Europa2 OEM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3596,6 +3624,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, .subdevice = 0x2c00, .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1043, + .subdevice = 0x4860, + .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -3871,6 +3905,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_EUROPA: case SAA7134_BOARD_VIDEOMATE_DVBT_300: + case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: /* The Philips EUROPA based hybrid boards have the tuner connected through * the channel decoder. We have to make it transparent to find it */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index f72a91f3025..1ba53b525ad 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1268,6 +1268,18 @@ static int dvb_init(struct saa7134_dev *dev) } } break; + case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: + dev->dvb.frontend = tda10046_attach(&medion_cardbus, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; + dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; + dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params; + } + break; + default: printk("%s: Huh? unknown DVB card?\n",dev->name); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 4a20d253a07..7cf96b43025 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -226,6 +226,7 @@ struct saa7134_format { #define SAA7134_BOARD_FLYDVBS_LR300 97 #define SAA7134_BOARD_PROTEUS_2309 98 #define SAA7134_BOARD_AVERMEDIA_A16AR 99 +#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- GitLab From 9448025be057f6b64c4bab01894c8e6b1a406e6e Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Mon, 2 Oct 2006 21:00:32 -0300 Subject: [PATCH 0408/1619] V4L/DVB (4704): SAA713x: fixed compile warning in SECAM fixup The variable fixup could be used uninitialized. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 557530aef94..203302f2182 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1820,15 +1820,18 @@ static int video_do_ioctl(struct inode *inode, struct file *file, break; if (i == TVNORMS) return -EINVAL; - if (*id & V4L2_STD_SECAM) { - if (secam[0] == 'L' || secam[0] == 'l') + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if (secam[0] == 'L' || secam[0] == 'l') { if (secam[1] == 'C' || secam[1] == 'c') fixup = V4L2_STD_SECAM_LC; else fixup = V4L2_STD_SECAM_L; - else + } else { if (secam[0] == 'D' || secam[0] == 'd') fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; + } for (i = 0; i < TVNORMS; i++) if (fixup == tvnorms[i].id) break; -- GitLab From a868b45dad04854e07bb1c7c81a73930098bc370 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 3 Oct 2006 16:01:17 -0300 Subject: [PATCH 0409/1619] V4L/DVB (4706): Do not enable VIDEO_V4L2 unconditionally The VIDEO_V4L2 config setting is enabled unconditionally, even for configurations with no support for this subsystem whatsoever. The following patch adds the necessary dependency. Signed-off-by: Maciej W. Rozycki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index ed4aa4e7912..9f7e1fe8c97 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -54,6 +54,7 @@ config VIDEO_V4L1_COMPAT config VIDEO_V4L2 bool + depends on VIDEO_DEV default y source "drivers/media/video/Kconfig" -- GitLab From e491cbc8b2eabc8856bf890006604edd91b1cce2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 3 Oct 2006 20:44:12 -0300 Subject: [PATCH 0410/1619] V4L/DVB (4707): 4linux: complete conversion to hotplug safe PCI API Signed-off-by: Alan Cox Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 10 ++++++---- drivers/media/video/zr36120.c | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 9f21d0ba0f0..653822ce391 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -1278,9 +1278,7 @@ find_zr36057 (void) zoran_num = 0; while (zoran_num < BUZ_MAX && - (dev = - pci_find_device(PCI_VENDOR_ID_ZORAN, - PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { + (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { card_num = card[zoran_num]; zr = &zoran[zoran_num]; memset(zr, 0, sizeof(struct zoran)); // Just in case if previous cycle failed @@ -1541,7 +1539,8 @@ find_zr36057 (void) goto zr_detach_vfe; } } - + /* Success so keep the pci_dev referenced */ + pci_dev_get(zr->pci_dev); zoran_num++; continue; @@ -1563,6 +1562,9 @@ find_zr36057 (void) iounmap(zr->zr36057_mem); continue; } + if (dev) /* Clean up ref count on early exit */ + pci_dev_put(dev); + if (zoran_num == 0) { dprintk(1, KERN_INFO "No known MJPEG cards found.\n"); } diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c index 9240638a013..b5ffe53c40d 100644 --- a/drivers/media/video/zr36120.c +++ b/drivers/media/video/zr36120.c @@ -1840,16 +1840,16 @@ int __init find_zoran(void) struct zoran *ztv; struct pci_dev *dev = NULL; unsigned char revision; - int zoran_num=0; + int zoran_num = 0; - while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) + while ((dev = pci_get_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) { /* Ok, a ZR36120/ZR36125 found! */ ztv = &zorans[zoran_num]; ztv->dev = dev; if (pci_enable_device(dev)) - return -EIO; + continue; pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); printk(KERN_INFO "zoran: Zoran %x (rev %d) ", @@ -1867,17 +1867,18 @@ int __init find_zoran(void) { iounmap(ztv->zoran_mem); printk(KERN_ERR "zoran: Bad irq number or handler\n"); - return -EINVAL; + continue; } if (result==-EBUSY) printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); if (result < 0) { iounmap(ztv->zoran_mem); - return result; + continue; } /* Enable bus-mastering */ pci_set_master(dev); - + /* Keep a reference */ + pci_dev_get(dev); zoran_num++; } if(zoran_num) @@ -2041,6 +2042,9 @@ void release_zoran(int max) if (ztv->zoran_mem) iounmap(ztv->zoran_mem); + /* Drop PCI device */ + pci_dev_put(ztv->dev); + video_unregister_device(&ztv->video_dev); video_unregister_device(&ztv->vbi_dev); } @@ -2057,13 +2061,12 @@ int __init zr36120_init(void) handle_chipset(); zoran_cards = find_zoran(); - if (zoran_cards<0) - /* no cards found, no need for a driver */ + if (zoran_cards <= 0) return -EIO; /* initialize Zorans */ for (card=0; card Date: Tue, 3 Oct 2006 19:10:33 -0300 Subject: [PATCH 0411/1619] V4L/DVB (4708): Add tveeprom support for Philips FM1236/FM1216ME MK5 Add new Philips tuners: Philips FM1236 MK5 and Philips FM1216ME MK5. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index cd1502ac956..e6baaee038b 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -222,8 +222,8 @@ hauppauge_tuner[] = { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, { TUNER_ABSENT, "Philips 8275A"}, { TUNER_ABSENT, "Microtune MT2060"}, - { TUNER_ABSENT, "Philips FM1236 MK5"}, - { TUNER_ABSENT, "Philips FM1216ME MK5"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, { TUNER_ABSENT, "TCL M2523_3DI_E"}, { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ -- GitLab From 13962753190a43fcc2b4a38d064f05d667691cc8 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 4 Oct 2006 08:09:10 -0300 Subject: [PATCH 0412/1619] V4L/DVB (4711): Radio: No need to return void The module_exit function has return-type void and pci_unregister_driver() returns void anyway. Signed-off-by: Tobias Klauser Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index cfab57d6bc4..eb14106f66f 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -449,7 +449,7 @@ static int __init gemtek_pci_init_module( void ) static void __exit gemtek_pci_cleanup_module( void ) { - return pci_unregister_driver( &gemtek_pci_driver ); + pci_unregister_driver(&gemtek_pci_driver); } MODULE_AUTHOR( "Vladimir Shebordaev " ); -- GitLab From e1634208b77872ac0884da6d92f0d46f9a61eaa7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 4 Oct 2006 08:13:14 -0300 Subject: [PATCH 0413/1619] V4L/DVB (4712): Fix warning when compiling on x86_i64 drivers/media/dvb/dvb-usb/usb-urb.c: In function 'usb_allocate_stream_buffers': drivers/media/dvb/dvb-usb/usb-urb.c:125: warning: format '%u' expects type 'unsigned int', but argument 4 has type 'long long unsigned int' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/usb-urb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c index 8728cf347a7..572b2d9aa66 100644 --- a/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/drivers/media/dvb/dvb-usb/usb-urb.c @@ -122,8 +122,9 @@ static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, usb_free_stream_buffers(stream); return -ENOMEM; } - deb_mem("buffer %d: %p (dma: %u)\n", - stream->buf_num, stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); + deb_mem("buffer %d: %p (dma: %Lu)\n", + stream->buf_num, +stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); memset(stream->buf_list[stream->buf_num],0,size); stream->state |= USB_STATE_URB_BUF; } -- GitLab From 4b8a311bb161a3bd2ab44311f42c526b6dc76270 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 28 Sep 2006 17:46:21 -0400 Subject: [PATCH 0414/1619] [PATCH] arch filter lists with < or > should not be accepted Currently the kernel audit system represents arch's as numbers and will gladly accept comparisons between archs using >, <, >=, <= when the only thing that makes sense is = or !=. I'm told that the next revision of auditctl will do this checking but this will provide enforcement in the kernel even for old userspace. A simple command to show the issue would be to run auditctl -d entry,always -F arch>i686 -S chmod with this patch the kernel will reject this with -EINVAL Please comment/ack/nak as soon as possible. -Eric kernel/auditfilter.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) Signed-off-by: Al Viro --- kernel/auditfilter.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 1a58a81fb09..4f40d923af8 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -411,7 +411,6 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) case AUDIT_FSGID: case AUDIT_LOGINUID: case AUDIT_PERS: - case AUDIT_ARCH: case AUDIT_MSGTYPE: case AUDIT_PPID: case AUDIT_DEVMAJOR: @@ -423,6 +422,14 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) case AUDIT_ARG2: case AUDIT_ARG3: break; + /* arch is only allowed to be = or != */ + case AUDIT_ARCH: + if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL) + && (f->op != AUDIT_NEGATE) && (f->op)) { + err = -EINVAL; + goto exit_free; + } + break; case AUDIT_PERM: if (f->val & ~15) goto exit_free; -- GitLab From 419c58f11fb732cc8bd1335fa43e0decb34e0be3 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Fri, 29 Sep 2006 00:08:50 -0400 Subject: [PATCH 0415/1619] [PATCH] PPID filtering fix On Thu, Sep 28, 2006 at 04:03:06PM -0400, Eric Paris wrote: > After some looking I did not see a way to get into audit_log_exit > without having set the ppid. So I am dropping the set from there and > only doing it at the beginning. > > Please comment/ack/nak as soon as possible. Ehh... That's one hell of an overhead to be had ;-/ Let's be lazy. Signed-off-by: Al Viro --- kernel/auditsc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 10514763175..b61c0191f3d 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -278,8 +278,11 @@ static int audit_filter_rules(struct task_struct *tsk, result = audit_comparator(tsk->pid, f->op, f->val); break; case AUDIT_PPID: - if (ctx) + if (ctx) { + if (!ctx->ppid) + ctx->ppid = sys_getppid(); result = audit_comparator(ctx->ppid, f->op, f->val); + } break; case AUDIT_UID: result = audit_comparator(tsk->uid, f->op, f->val); @@ -795,7 +798,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts /* tsk == current */ context->pid = tsk->pid; - context->ppid = sys_getppid(); /* sic. tsk == current in all cases */ + if (!context->ppid) + context->ppid = sys_getppid(); context->uid = tsk->uid; context->gid = tsk->gid; context->euid = tsk->euid; @@ -1137,6 +1141,7 @@ void audit_syscall_entry(int arch, int major, context->ctime = CURRENT_TIME; context->in_syscall = 1; context->auditable = !!(state == AUDIT_RECORD_CONTEXT); + context->ppid = 0; } /** -- GitLab From ac9910ce017ff5f86f3a25e969b2c4f5d6ac438f Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Thu, 28 Sep 2006 14:31:32 -0400 Subject: [PATCH 0416/1619] [PATCH] name_count array overrun Hi, This patch removes the rdev logging from the previous patch The below patch closes an unbounded use of name_count. This can lead to oopses in some new file systems. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- kernel/auditsc.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index b61c0191f3d..42f2f117971 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1357,7 +1357,13 @@ void __audit_inode_child(const char *dname, const struct inode *inode, } update_context: - idx = context->name_count++; + idx = context->name_count; + if (context->name_count == AUDIT_NAMES) { + printk(KERN_DEBUG "name_count maxed and losing %s\n", + found_name ?: "(null)"); + return; + } + context->name_count++; #if AUDIT_DEBUG context->ino_count++; #endif @@ -1375,7 +1381,16 @@ update_context: /* A parent was not found in audit_names, so copy the inode data for the * provided parent. */ if (!found_name) { - idx = context->name_count++; + idx = context->name_count; + if (context->name_count == AUDIT_NAMES) { + printk(KERN_DEBUG + "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu", + MAJOR(parent->i_sb->s_dev), + MINOR(parent->i_sb->s_dev), + parent->i_ino); + return; + } + context->name_count++; #if AUDIT_DEBUG context->ino_count++; #endif -- GitLab From c8e649ba908954447e9a095677f6a6c8e50a37b2 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Fri, 29 Sep 2006 11:56:49 -0400 Subject: [PATCH 0417/1619] [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(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index c3aa0975181..b2ca666d999 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 */ -- GitLab From 4068d93cd17561bcbfc821c831cb048385320bd6 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:15:47 -0400 Subject: [PATCH 0418/1619] [PARISC] Untangle header include mess asm/processor.h on parisc wants spinlocks for cpuinfo, but linux/spinlock_types.h needs lockdep, and lockdep wants prefetch. This leads to a horrible circular dependancy, because is including something which depends on things which are not defined until the end of the file. Kludge around this by moving prefetch related code into and including it before , however this is just a temporary solution until this mess can be cleaned up. Signed-off-by: Kyle McMartin --- include/asm-parisc/prefetch.h | 36 ++++++++++++++++++++++++++++++++++ include/asm-parisc/processor.h | 28 ++------------------------ 2 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 include/asm-parisc/prefetch.h diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h new file mode 100644 index 00000000000..f5a2e7ae266 --- /dev/null +++ b/include/asm-parisc/prefetch.h @@ -0,0 +1,36 @@ +/* + * include/asm-parisc/prefetch.h + * + * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book. + * In addition, many implementations do hardware prefetching of both + * instructions and data. + * + * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load + * to gr0 but not in a way that Linux can use. If the load would cause an + * interruption (eg due to prefetching 0), it is suppressed on PA2.0 + * processors, but not on 7300LC. + * + */ + +#ifndef __ASM_PARISC_PREFETCH_H +#define __ASM_PARISC_PREFETCH_H + +#ifndef __ASSEMBLY__ +#ifdef CONFIG_PREFETCH + +#define ARCH_HAS_PREFETCH +extern inline void prefetch(const void *addr) +{ + __asm__("ldw 0(%0), %%r0" : : "r" (addr)); +} + +#define ARCH_HAS_PREFETCHW +extern inline void prefetchw(const void *addr) +{ + __asm__("ldd 0(%0), %%r0" : : "r" (addr)); +} + +#endif /* CONFIG_PREFETCH */ +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_PARISC_PROCESSOR_H */ diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index b73626f040d..c72b8fa4968 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -9,6 +9,8 @@ #define __ASM_PARISC_PROCESSOR_H #ifndef __ASSEMBLY__ +#include /* lockdep.h needs */ + #include #include @@ -328,32 +330,6 @@ extern unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0]) #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30]) - -/* - * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book. - * In addition, many implementations do hardware prefetching of both - * instructions and data. - * - * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load - * to gr0 but not in a way that Linux can use. If the load would cause an - * interruption (eg due to prefetching 0), it is suppressed on PA2.0 - * processors, but not on 7300LC. - */ -#ifdef CONFIG_PREFETCH -#define ARCH_HAS_PREFETCH -#define ARCH_HAS_PREFETCHW - -extern inline void prefetch(const void *addr) -{ - __asm__("ldw 0(%0), %%r0" : : "r" (addr)); -} - -extern inline void prefetchw(const void *addr) -{ - __asm__("ldd 0(%0), %%r0" : : "r" (addr)); -} -#endif - #define cpu_relax() barrier() #endif /* __ASSEMBLY__ */ -- GitLab From 32104b29cdf93f78ac37e681bd4547413466d13c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 20:37:26 -0400 Subject: [PATCH 0419/1619] [PARISC] PA7200 also supports prefetch for read It seems PA7200 processors also suppress traps on loads to %r0. This means we can prefetch for read on these cpus. Of course, we can't support prefetch for write, since that requires LOAD DOUBLEWORD which was added with PA2.0 Signed-off-by: Kyle McMartin --- arch/parisc/Kconfig | 2 +- include/asm-parisc/prefetch.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 6dd0ea8f88e..d2101237442 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -127,7 +127,7 @@ config PA11 config PREFETCH def_bool y - depends on PA8X00 + depends on PA8X00 || PA7200 config 64BIT bool "64-bit kernel" diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h index f5a2e7ae266..5d021726fa3 100644 --- a/include/asm-parisc/prefetch.h +++ b/include/asm-parisc/prefetch.h @@ -24,11 +24,14 @@ extern inline void prefetch(const void *addr) __asm__("ldw 0(%0), %%r0" : : "r" (addr)); } +/* LDD is a PA2.0 addition. */ +#ifdef CONFIG_PA20 #define ARCH_HAS_PREFETCHW extern inline void prefetchw(const void *addr) { __asm__("ldd 0(%0), %%r0" : : "r" (addr)); } +#endif /* CONFIG_PA20 */ #endif /* CONFIG_PREFETCH */ #endif /* __ASSEMBLY__ */ -- GitLab From c51d476af36d1e9634e77afccc4d48e344acf243 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 20:39:48 -0400 Subject: [PATCH 0420/1619] [PARISC] Remove variables decls duplicated from asm-generic/sections.h Signed-off-by: Kyle McMartin --- arch/parisc/mm/init.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 25ad28d63e8..0667f2b4f97 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -31,10 +31,7 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -extern char _text; /* start of kernel code, defined by linker */ extern int data_start; -extern char _end; /* end of BSS, defined by linker */ -extern char __init_begin, __init_end; #ifdef CONFIG_DISCONTIGMEM struct node_map_data node_data[MAX_NUMNODES] __read_mostly; @@ -319,8 +316,8 @@ static void __init setup_bootmem(void) reserve_bootmem_node(NODE_DATA(0), 0UL, (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE)); - reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text), - (unsigned long)(&_end - &_text)); + reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text), + (unsigned long)(_end - _text)); reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT), ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT)); @@ -355,8 +352,8 @@ static void __init setup_bootmem(void) #endif data_resource.start = virt_to_phys(&data_start); - data_resource.end = virt_to_phys(&_end)-1; - code_resource.start = virt_to_phys(&_text); + data_resource.end = virt_to_phys(_end) - 1; + code_resource.start = virt_to_phys(_text); code_resource.end = virt_to_phys(&data_start)-1; /* We don't know which region the kernel will be in, so try @@ -385,12 +382,12 @@ void free_initmem(void) */ local_irq_disable(); - memset(&__init_begin, 0x00, - (unsigned long)&__init_end - (unsigned long)&__init_begin); + memset(__init_begin, 0x00, + (unsigned long)__init_end - (unsigned long)__init_begin); flush_data_cache(); asm volatile("sync" : : ); - flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end); + flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end); asm volatile("sync" : : ); local_irq_enable(); @@ -398,8 +395,8 @@ void free_initmem(void) /* align __init_begin and __init_end to page size, ignoring linker script where we might have tried to save RAM */ - init_begin = PAGE_ALIGN((unsigned long)(&__init_begin)); - init_end = PAGE_ALIGN((unsigned long)(&__init_end)); + init_begin = PAGE_ALIGN((unsigned long)(__init_begin)); + init_end = PAGE_ALIGN((unsigned long)(__init_end)); for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); @@ -578,7 +575,7 @@ static void __init map_pages(unsigned long start_vaddr, unsigned long start_padd extern const unsigned long fault_vector_20; extern void * const linux_gateway_page; - ro_start = __pa((unsigned long)&_text); + ro_start = __pa((unsigned long)_text); ro_end = __pa((unsigned long)&data_start); fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; -- GitLab From f86e45131f9d41b1617fbaac7aa1ef23e8d0ab48 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 21:09:31 -0400 Subject: [PATCH 0421/1619] [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(+) diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 88dafa246d8..952bee79a8f 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); -- GitLab From 3d73cf5e18c47d416db4d0734245d3fb087603d9 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:17:19 -0400 Subject: [PATCH 0422/1619] [PARISC] Abstract shift register left in .S Abstract existing shift register left macros as shift register right are. This lends itself to a nice clean up of some #ifdef blocks in entry.S Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 19 ++++--------------- include/asm-parisc/assembly.h | 6 ++++-- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 192357a3b9f..d55b45d54f4 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -30,6 +30,7 @@ #include +#include /* for L1_CACHE_SHIFT */ #include /* for LDREG/STREG defines */ #include #include @@ -478,11 +479,7 @@ bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ copy \pmd,%r9 -#ifdef CONFIG_64BIT - shld %r9,PxD_VALUE_SHIFT,\pmd -#else - shlw %r9,PxD_VALUE_SHIFT,\pmd -#endif + SHLREG %r9,PxD_VALUE_SHIFT,\pmd EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */ shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd @@ -970,11 +967,7 @@ intr_return: /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount ** irq_stat[] is defined using ____cacheline_aligned. */ -#ifdef CONFIG_64BIT - shld %r1, 6, %r20 -#else - shlw %r1, 5, %r20 -#endif + SHLREG %r1,L1_CACHE_SHIFT,%r20 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ #endif /* CONFIG_SMP */ @@ -2115,11 +2108,7 @@ syscall_check_bh: ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */ -#ifdef CONFIG_64BIT - shld %r26, 6, %r20 -#else - shlw %r26, 5, %r20 -#endif + SHLREG %r26,L1_CACHE_SHIFT,%r20 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ #endif /* CONFIG_SMP */ diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index 1a7bfe699e0..5a1e0e8b1c3 100644 --- a/include/asm-parisc/assembly.h +++ b/include/asm-parisc/assembly.h @@ -29,7 +29,8 @@ #define LDREGX ldd,s #define LDREGM ldd,mb #define STREGM std,ma -#define SHRREG shrd +#define SHRREG shrd +#define SHLREG shld #define RP_OFFSET 16 #define FRAME_SIZE 128 #define CALLEE_REG_FRAME_SIZE 144 @@ -39,7 +40,8 @@ #define LDREGX ldwx,s #define LDREGM ldwm #define STREGM stwm -#define SHRREG shr +#define SHRREG shr +#define SHLREG shlw #define RP_OFFSET 20 #define FRAME_SIZE 64 #define CALLEE_REG_FRAME_SIZE 128 -- GitLab From 6f03495d65db4cecc8dc8f2266768f83af0c2710 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:18:57 -0400 Subject: [PATCH 0423/1619] [PARISC] Add asm-parisc/mckinley.h bus header Add header for McKinley bus related code. Remove extern decl of proc_mckinley_root in drivers/parisc/sba_iommu.c Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 5 +---- include/asm-parisc/mckinley.h | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 include/asm-parisc/mckinley.h diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 8b473281551..d80ce476189 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -38,15 +38,12 @@ #include #include +#include /* for proc_mckinley_root */ #include /* for proc_runway_root */ #include /* for PDC_MODEL_* */ #include /* for is_pdc_pat() */ #include - -/* declared in arch/parisc/kernel/setup.c */ -extern struct proc_dir_entry * proc_mckinley_root; - #define MODULE_NAME "SBA" #ifdef CONFIG_PROC_FS diff --git a/include/asm-parisc/mckinley.h b/include/asm-parisc/mckinley.h new file mode 100644 index 00000000000..d1ea6f12915 --- /dev/null +++ b/include/asm-parisc/mckinley.h @@ -0,0 +1,9 @@ +#ifndef ASM_PARISC_MCKINLEY_H +#define ASM_PARISC_MCKINLEY_H +#ifdef __KERNEL__ + +/* declared in arch/parisc/kernel/setup.c */ +extern struct proc_dir_entry * proc_mckinley_root; + +#endif /*__KERNEL__*/ +#endif /*ASM_PARISC_MCKINLEY_H*/ -- GitLab From 5cfe87d3f543d05a84a509d232330261f1b7bccf Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:25:45 -0400 Subject: [PATCH 0424/1619] [PARISC] Fix up parisc irq handling for genirq changes Clean up enough to get things compiling again in the interim. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/irq.c | 2 +- include/asm-parisc/irq.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 5b8803cc3d6..c53bfeb4bf9 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -209,7 +209,7 @@ int show_interrupts(struct seq_file *p, void *v) ** Then use that to get the Transaction address and data. */ -int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data) +int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data) { if (irq_desc[irq].action) return -EBUSY; diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h index 5cae260615a..6e29cfa2812 100644 --- a/include/asm-parisc/irq.h +++ b/include/asm-parisc/irq.h @@ -31,7 +31,7 @@ static __inline__ int irq_canonicalize(int irq) return (irq == 2) ? 9 : irq; } -struct hw_interrupt_type; +struct irq_chip; /* * Some useful "we don't have to do anything here" handlers. Should @@ -46,7 +46,7 @@ extern unsigned int txn_alloc_data(unsigned int); extern unsigned long txn_alloc_addr(unsigned int); extern unsigned long txn_affinity_addr(unsigned int irq, int cpu); -extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); +extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *); extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest); /* soft power switch support (power.c) */ -- GitLab From e45da35e180a4fc91307648d021a598495742c32 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Sat, 16 Sep 2006 14:35:51 -0400 Subject: [PATCH 0425/1619] [PARISC] Document that D-class can also use serial_mux Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin --- drivers/serial/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 653098bc2dd..8edee745888 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -556,10 +556,11 @@ config SERIAL_MUX default y ---help--- Saying Y here will enable the hardware MUX serial driver for - the Nova and K class systems. The hardware MUX is not 8250/16550 - compatible therefore the /dev/ttyB0 device is shared between the - Serial MUX and the PDC software console. The following steps - need to be completed to use the Serial MUX: + the Nova, K class systems and D class with a 'remote control card'. + The hardware MUX is not 8250/16550 compatible therefore the + /dev/ttyB0 device is shared between the Serial MUX and the PDC + software console. The following steps need to be completed to use + the Serial MUX: 1. create the device entry (mknod /dev/ttyB0 c 11 0) 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 -- GitLab From 20f4d3cb9b94ce3fec9a6135b9ad075b82b24f41 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 23 Aug 2006 09:00:04 -0700 Subject: [PATCH 0426/1619] [PARISC] parisc specific kmap API implementation for pa8800 This patch fixes the pa8800 at a gross level (there are still other subtle incoherency issues which can still cause crashes and HPMCs). What it does is try to force eject inequivalent aliases before they become visible to the L2 cache (which is where we get the incoherence problems). A new function (parisc_requires_coherency) is introduced in asm/processor.h to identify the pa8x00 processors (8800 and 8900) which have the issue. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 45 ++++++++++++++++++++++++++++++++- include/asm-parisc/cacheflush.h | 30 +++++++++++++++++++--- include/asm-parisc/page.h | 22 +++------------- include/asm-parisc/processor.h | 13 ++++++++++ 4 files changed, 87 insertions(+), 23 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index bc7c4a4e26a..7e8d697aef3 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -91,7 +91,8 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) flush_kernel_dcache_page(page); clear_bit(PG_dcache_dirty, &page->flags); - } + } else if (parisc_requires_coherency()) + flush_kernel_dcache_page(page); } void @@ -370,3 +371,45 @@ void parisc_setup_cache_timing(void) printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); } + +extern void purge_kernel_dcache_page(unsigned long); +extern void clear_user_page_asm(void *page, unsigned long vaddr); + +void +clear_user_page(void *page, unsigned long vaddr, struct page *pg) +{ + purge_kernel_dcache_page((unsigned long)page); + purge_tlb_start(); + pdtlb_kernel(page); + purge_tlb_end(); + clear_user_page_asm(page, vaddr); +} + +void flush_kernel_dcache_page_addr(void *addr) +{ + flush_kernel_dcache_page_asm(addr); + purge_tlb_start(); + pdtlb_kernel(addr); + purge_tlb_end(); +} +EXPORT_SYMBOL(flush_kernel_dcache_page_addr); + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg) +{ + /* no coherency needed (all in kmap/kunmap) */ + copy_user_page_asm(vto, vfrom); + if (!parisc_requires_coherency()) + flush_kernel_dcache_page_asm(vto); +} +EXPORT_SYMBOL(copy_user_page); + +#ifdef CONFIG_PA8X00 + +void kunmap_parisc(void *addr) +{ + if (parisc_requires_coherency()) + flush_kernel_dcache_page_addr(addr); +} +EXPORT_SYMBOL(kunmap_parisc); +#endif diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h index 0b459cdfbd6..2bc41f2e027 100644 --- a/include/asm-parisc/cacheflush.h +++ b/include/asm-parisc/cacheflush.h @@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsigned long vmaddr) } #define ARCH_HAS_FLUSH_ANON_PAGE -static inline void -flush_kernel_dcache_page(struct page *page) +#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE +void flush_kernel_dcache_page_addr(void *addr); +static inline void flush_kernel_dcache_page(struct page *page) { - flush_kernel_dcache_page_asm(page_address(page)); + flush_kernel_dcache_page_addr(page_address(page)); } -#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void); #endif +#ifdef CONFIG_PA8X00 +/* Only pa8800, pa8900 needs this */ +#define ARCH_HAS_KMAP + +void kunmap_parisc(void *addr); + +static inline void *kmap(struct page *page) +{ + might_sleep(); + return page_address(page); +} + +#define kunmap(page) kunmap_parisc(page_address(page)) + +#define kmap_atomic(page, idx) page_address(page) + +#define kunmap_atomic(addr, idx) kunmap_parisc(addr) + +#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn)) +#define kmap_atomic_to_page(ptr) virt_to_page(ptr) +#endif + #endif /* _PARISC_CACHEFLUSH_H */ diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h index 57d6d82756d..3567208191e 100644 --- a/include/asm-parisc/page.h +++ b/include/asm-parisc/page.h @@ -26,24 +26,10 @@ struct page; -extern void purge_kernel_dcache_page(unsigned long); -extern void copy_user_page_asm(void *to, void *from); -extern void clear_user_page_asm(void *page, unsigned long vaddr); - -static inline void -copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg) -{ - copy_user_page_asm(vto, vfrom); - flush_kernel_dcache_page_asm(vto); - /* XXX: ppc flushes icache too, should we? */ -} - -static inline void -clear_user_page(void *page, unsigned long vaddr, struct page *pg) -{ - purge_kernel_dcache_page((unsigned long)page); - clear_user_page_asm(page, vaddr); -} +void copy_user_page_asm(void *to, void *from); +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg); +void clear_user_page(void *page, unsigned long vaddr, struct page *pg); /* * These are used to make use of C type-checking.. diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index c72b8fa4968..4313618c98e 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -332,6 +332,19 @@ extern unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() +/* Used as a macro to identify the combined VIPT/PIPT cached + * CPUs which require a guarantee of coherency (no inequivalent + * aliases with different data, whether clean or not) to operate */ +static inline int parisc_requires_coherency(void) +{ +#ifdef CONFIG_PA8X00 + /* FIXME: also pa8900 - when we see one */ + return boot_cpu_data.cpu_type == mako; +#else + return 0; +#endif +} + #endif /* __ASSEMBLY__ */ #endif /* __ASM_PARISC_PROCESSOR_H */ -- GitLab From 8f611c453c6a41eee73645c80ccb10493e74b630 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sat, 16 Sep 2006 14:38:22 -0400 Subject: [PATCH 0427/1619] [PARISC] Prevent multiple includes of asm-parisc/parisc-device.h Signed-off-by: Kyle McMartin --- include/asm-parisc/parisc-device.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h index 1d247e32a60..e12624d8941 100644 --- a/include/asm-parisc/parisc-device.h +++ b/include/asm-parisc/parisc-device.h @@ -1,3 +1,6 @@ +#ifndef _ASM_PARISC_PARISC_DEVICE_H_ +#define _ASM_PARISC_PARISC_DEVICE_H_ + #include struct parisc_device { @@ -57,3 +60,5 @@ parisc_get_drvdata(struct parisc_device *d) } extern struct bus_type parisc_bus_type; + +#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ -- GitLab From df570b9c284701d08b22aa00cbfcf870b7f1b7c1 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 27 Aug 2006 11:04:26 -0400 Subject: [PATCH 0428/1619] [PARISC] Switch is_compat_task to use TIF_32BIT Stop using PER_LINUX32 to designate processes needing compaterizing. Convert is_compat_task to use TIF_32BIT and set TIF_32BIT in binfmt_elf32.c Signed-off-by: Kyle McMartin --- arch/parisc/kernel/binfmt_elf32.c | 24 +----------------------- arch/parisc/kernel/signal.c | 5 ++--- include/asm-parisc/compat.h | 4 ++-- include/asm-parisc/processor.h | 2 +- 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index d1833f164bb..1e64e7b8811 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c @@ -87,7 +87,7 @@ struct elf_prpsinfo32 */ #define SET_PERSONALITY(ex, ibcs2) \ - current->personality = PER_LINUX32; \ + set_thread_flag(TIF_32BIT); \ current->thread.map_base = DEFAULT_MAP_BASE32; \ current->thread.task_size = DEFAULT_TASK_SIZE32 \ @@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) } #include "../../../fs/binfmt_elf.c" - -/* Set up a separate execution domain for ELF32 binaries running - * on an ELF64 kernel */ - -static struct exec_domain parisc32_exec_domain = { - .name = "Linux/ELF32", - .pers_low = PER_LINUX32, - .pers_high = PER_LINUX32, -}; - -static int __init parisc32_exec_init(void) -{ - /* steal the identity signal mappings from the default domain */ - parisc32_exec_domain.signal_map = default_exec_domain.signal_map; - parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; - - register_exec_domain(&parisc32_exec_domain); - - return 0; -} - -__initcall(parisc32_exec_init); diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index bb83880c5ee..ee6653edeb7 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -433,13 +432,13 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (in_syscall) { regs->gr[31] = haddr; #ifdef __LP64__ - if (personality(current->personality) == PER_LINUX) + if (!test_thread_flag(TIF_32BIT)) sigframe_size |= 1; #endif } else { unsigned long psw = USER_PSW; #ifdef __LP64__ - if (personality(current->personality) == PER_LINUX) + if (!test_thread_flag(TIF_32BIT)) psw |= PSW_W; #endif diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index 71b4eeea205..fe857902353 100644 --- a/include/asm-parisc/compat.h +++ b/include/asm-parisc/compat.h @@ -5,7 +5,7 @@ */ #include #include -#include +#include #define COMPAT_USER_HZ 100 @@ -152,7 +152,7 @@ static __inline__ void __user *compat_alloc_user_space(long len) static inline int __is_compat_task(struct task_struct *t) { - return personality(t->personality) == PER_LINUX32; + return test_ti_thread_flag(t->thread_info, TIF_32BIT); } static inline int is_compat_task(void) diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index 4313618c98e..fd7866dc8c8 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -278,7 +278,7 @@ on downward growing arches, it looks like this: */ #ifdef __LP64__ -#define USER_WIDE_MODE (personality(current->personality) == PER_LINUX) +#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT)) #else #define USER_WIDE_MODE 0 #endif -- GitLab From 75a4958154f5d0028d5464f2479b4297d55cf4a3 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 27 Aug 2006 11:12:13 -0400 Subject: [PATCH 0429/1619] [PARISC] Allow overriding personality with sys_personality And now suddenly, linux32 works on parisc... Signed-off-by: Kyle McMartin --- arch/parisc/kernel/sys_parisc.c | 45 ++++++++++++++++++++++++++++++ arch/parisc/kernel/syscall_table.S | 4 +-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 8b5df98e2b3..1db5588ceac 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include int sys_pipe(int __user *fildes) { @@ -248,3 +250,46 @@ asmlinkage int sys_free_hugepages(unsigned long addr) { return -EINVAL; } + +long parisc_personality(unsigned long personality) +{ + long err; + + if (personality(current->personality) == PER_LINUX32 + && personality == PER_LINUX) + personality = PER_LINUX32; + + err = sys_personality(personality); + if (err == PER_LINUX32) + err = PER_LINUX; + + return err; +} + +static inline int override_machine(char __user *mach) { +#ifdef CONFIG_COMPAT + if (personality(current->personality) == PER_LINUX32) { + if (__put_user(0, mach + 6) || + __put_user(0, mach + 7)) + return -EFAULT; + } + + return 0; +#else /*!CONFIG_COMPAT*/ + return 0; +#endif /*CONFIG_COMPAT*/ +} + +long parisc_newuname(struct new_utsname __user *utsname) +{ + int err = 0; + + down_read(&uts_sem); + if (copy_to_user(utsname, &system_utsname, sizeof(*utsname))) + err = -EFAULT; + up_read(&uts_sem); + + err = override_machine(utsname->machine); + + return (long)err; +} diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index e27b432f90a..701d66a596e 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -132,7 +132,7 @@ ENTRY_SAME(socketpair) ENTRY_SAME(setpgid) ENTRY_SAME(send) - ENTRY_SAME(newuname) + ENTRY_OURS(newuname) ENTRY_SAME(umask) /* 60 */ ENTRY_SAME(chroot) ENTRY_SAME(ustat) @@ -221,7 +221,7 @@ ENTRY_SAME(fchdir) ENTRY_SAME(bdflush) ENTRY_SAME(sysfs) /* 135 */ - ENTRY_SAME(personality) + ENTRY_OURS(personality) ENTRY_SAME(ni_syscall) /* for afs_syscall */ ENTRY_SAME(setfsuid) ENTRY_SAME(setfsgid) -- GitLab From 136ce40e9f1f24ca1dbf7714c669a7bca56440ea Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 28 Aug 2006 11:53:30 -0600 Subject: [PATCH 0430/1619] [PARISC] Clean up asm-parisc/serial.h Russell King pointed out that asm/serial.h is anachronistic and we were misusing BASE_BAUD. So fix BASE_BAUD for PCI 16550 UARTs, move LASI_BASE_BAUD into 8250_gsc, and fix the obsolete comment about reserving serial port slots. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/serial/8250_gsc.c | 4 ++-- include/asm-parisc/serial.h | 16 ++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 1ebe6b585d2..c5d0addfda4 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -22,7 +22,6 @@ #include #include #include -#include /* for LASI_BASE_BAUD */ #include "8250.h" @@ -54,7 +53,8 @@ serial_init_chip(struct parisc_device *dev) memset(&port, 0, sizeof(port)); port.iotype = UPIO_MEM; - port.uartclk = LASI_BASE_BAUD * 16; + /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */ + port.uartclk = 7272727; port.mapbase = address; port.membase = ioremap_nocache(address, 16); port.irq = dev->irq; diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h index 82fd820d684..d7e3cc60dbc 100644 --- a/include/asm-parisc/serial.h +++ b/include/asm-parisc/serial.h @@ -3,20 +3,8 @@ */ /* - * This assumes you have a 7.272727 MHz clock for your UART. - * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock - * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO + * This is used for 16550-compatible UARTs */ +#define BASE_BAUD ( 1843200 / 16 ) -#define LASI_BASE_BAUD ( 7272727 / 16 ) -#define BASE_BAUD LASI_BASE_BAUD - -/* - * We don't use the ISA probing code, so these entries are just to reserve - * space. Some example (maximal) configurations: - * - 712 w/ additional Lasi & RJ16 ports: 4 - * - J5k w/ PCI serial cards: 2 + 4 * card ~= 34 - * A500 w/ PCI serial cards: 5 + 4 * card ~= 17 - */ - #define SERIAL_PORT_DFNS -- GitLab From 9c2c54574e724589858ad656a507be29f9034943 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 28 Aug 2006 15:42:07 -0400 Subject: [PATCH 0431/1619] [PARISC] [BUGFIX] nullify branch delay slot of the jump back to intr_restore in intr_do_preempt. This prevents the execution of an unwanted insn... Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index d55b45d54f4..340b5e8d67b 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1069,7 +1069,7 @@ intr_do_preempt: BL preempt_schedule_irq, %r2 nop - b intr_restore /* ssm PSW_SM_I done by intr_restore */ + b,n intr_restore /* ssm PSW_SM_I done by intr_restore */ #endif /* CONFIG_PREEMPT */ .import do_signal,code -- GitLab From 6e071852a10ec02570c472052f07b5facb5ad857 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sat, 2 Sep 2006 07:54:58 -0600 Subject: [PATCH 0432/1619] [PARISC] Improve rwlock implementation Rewrite rwlock implementation to avoid various deadlocks in the current scheme. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/spinlock.h | 98 ++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index e1825530365..8980a876cc4 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -56,50 +56,70 @@ static inline int __raw_spin_trylock(raw_spinlock_t *x) } /* - * Read-write spinlocks, allowing multiple readers - * but only one writer. + * Read-write spinlocks, allowing multiple readers but only one writer. + * The spinlock is held by the writer, preventing any readers or other + * writers from grabbing the rwlock. Readers use the lock to serialise their + * access to the counter (which records how many readers currently hold the + * lock). Linux rwlocks are unfair to writers; they can be starved for + * an indefinite time by readers. They can also be taken in interrupt context, + * so we have to disable interrupts when acquiring the spin lock to be sure + * that an interrupting reader doesn't get an inconsistent view of the lock. */ -#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) - -/* read_lock, read_unlock are pretty straightforward. Of course it somehow - * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */ - static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { + unsigned long flags; + local_irq_save(flags); __raw_spin_lock(&rw->lock); - rw->counter++; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { + unsigned long flags; + local_irq_save(flags); __raw_spin_lock(&rw->lock); - rw->counter--; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } -/* write_lock is less trivial. We optimistically grab the lock and check - * if we surprised any readers. If so we release the lock and wait till - * they're all gone before trying again - * - * Also note that we don't use the _irqsave / _irqrestore suffixes here. - * If we're called with interrupts enabled and we've got readers (or other - * writers) in interrupt handlers someone fucked up and we'd dead-lock - * sooner or later anyway. prumpf */ +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) +{ + unsigned long flags; + retry: + local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + rw->counter++; + __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); + return 1; + } + + local_irq_restore(flags); + /* If write-locked, we fail to acquire the lock */ + if (rw->counter < 0) + return 0; + + /* Wait until we have a realistic chance at the lock */ + while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) + cpu_relax(); + + goto retry; +} -static __inline__ void __raw_write_lock(raw_rwlock_t *rw) +static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { + unsigned long flags; retry: + local_irq_save(flags); __raw_spin_lock(&rw->lock); - if(rw->counter != 0) { - /* this basically never happens */ + if (rw->counter != 0) { __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); while (rw->counter != 0) cpu_relax(); @@ -107,31 +127,35 @@ retry: goto retry; } - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ + rw->counter = -1; /* mark as write-locked */ + mb(); + local_irq_restore(flags); } -/* write_unlock is absolutely trivial - we don't have to wait for anything */ - -static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) +static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) { rw->counter = 0; __raw_spin_unlock(&rw->lock); } -static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) +static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - if (rw->counter != 0) { - /* this basically never happens */ - __raw_spin_unlock(&rw->lock); - - return 0; + unsigned long flags; + int result = 0; + + local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + if (rw->counter == 0) { + rw->counter = -1; + result = 1; + } else { + /* Read-locked. Oh well. */ + __raw_spin_unlock(&rw->lock); + } } + local_irq_restore(flags); - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ - return 1; + return result; } /* -- GitLab From 342a0497c23c278633f8674ab62f71e5049b7080 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Thu, 7 Sep 2006 13:05:17 -0400 Subject: [PATCH 0433/1619] [PARISC] Implement futex_atomic_cmpxchg_inatomic Implement trivial futex_atomic_cmpxchg_inatomic for testing. Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin --- include/asm-parisc/futex.h | 71 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h index 6a332a9f099..d84bbb283fd 100644 --- a/include/asm-parisc/futex.h +++ b/include/asm-parisc/futex.h @@ -1,6 +1,71 @@ -#ifndef _ASM_FUTEX_H -#define _ASM_FUTEX_H +#ifndef _ASM_PARISC_FUTEX_H +#define _ASM_PARISC_FUTEX_H -#include +#ifdef __KERNEL__ +#include +#include +#include + +static inline int +futex_atomic_op_inuser (int encoded_op, int __user *uaddr) +{ + int op = (encoded_op >> 28) & 7; + int cmp = (encoded_op >> 24) & 15; + int oparg = (encoded_op << 8) >> 20; + int cmparg = (encoded_op << 20) >> 20; + int oldval = 0, ret; + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) + oparg = 1 << oparg; + + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + inc_preempt_count(); + + switch (op) { + case FUTEX_OP_SET: + case FUTEX_OP_ADD: + case FUTEX_OP_OR: + case FUTEX_OP_ANDN: + case FUTEX_OP_XOR: + default: + ret = -ENOSYS; + } + + dec_preempt_count(); + + if (!ret) { + switch (cmp) { + case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; + case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; + case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; + case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; + case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; + case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; + default: ret = -ENOSYS; + } + } + return ret; +} + +/* Non-atomic version */ +static inline int +futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) +{ + int err = 0; + int uval; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + err = get_user(uval, uaddr); + if (err) return -EFAULT; + if (uval == oldval) + err = put_user(newval, uaddr); + if (err) return -EFAULT; + return uval; +} + +#endif #endif -- GitLab From 9cf8f370f0777a24808b3485f3b5abb8e736d3e8 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 1 Sep 2006 14:50:25 -0700 Subject: [PATCH 0434/1619] [PARISC] Use CONFIG_HZ to determine interval timer rate (aka clock ticks) This isn't likely to be causing problems for other bits of kernel code. I can't find any other user of CONFIG_HZ outside of arch specific code. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- include/asm-parisc/param.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h index 07cb9b93cfe..32e03d87785 100644 --- a/include/asm-parisc/param.h +++ b/include/asm-parisc/param.h @@ -2,13 +2,9 @@ #define _ASMPARISC_PARAM_H #ifdef __KERNEL__ -# ifdef CONFIG_PA20 -# define HZ 1000 /* Faster machines */ -# else -# define HZ 100 /* Internal kernel timer frequency */ -# endif -# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ -# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ +#define HZ CONFIG_HZ +#define USER_HZ 100 /* some user API use "ticks" */ +#define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif #ifndef HZ -- GitLab From 7908a0c72ee78ba5476c2a773d808c77593719c6 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 1 Sep 2006 14:18:39 -0700 Subject: [PATCH 0435/1619] [PARISC] Prevent processor_probe() from clobbering cpu_data[0] processor_probe() shouldn't clobber cpu_data[0] cpu_data[0].it_value (used by timer_interrupt()) is already set. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/processor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 99d7fca9310..fb81e5687e7 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -143,8 +143,9 @@ static int __init processor_probe(struct parisc_device *dev) p = &cpu_data[cpuid]; boot_cpu_data.cpu_count++; - /* initialize counters */ - memset(p, 0, sizeof(struct cpuinfo_parisc)); + /* initialize counters - CPU 0 gets it_value set in time_init() */ + if (cpuid) + memset(p, 0, sizeof(struct cpuinfo_parisc)); p->loops_per_jiffy = loops_per_jiffy; p->dev = dev; /* Save IODC data in case we need it */ -- GitLab From 56f335c89e28c488b1bfea3e5e697fce805c784d Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Sun, 3 Sep 2006 00:02:16 -0700 Subject: [PATCH 0436/1619] [PARISC] Add new function to start local Interval Timer, start_cpu_itimer() I couldn't find where the itimer was getting started for slave CPUs. CPU 0 (master) itimer was started in time_init() (arch/parisc/kernel/time.c). start_cpu_itimer() code was striped from time_init(). Slaves now start their itimer in smp_cpu_init(). This is a first step towards making gettimeoffset() work for SMP. Next step will be to determine the CR16 (cycle counter) offsets for each CPU relative to the master (CPU 0). Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/smp.c | 4 +++- arch/parisc/kernel/time.c | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 98e40959a56..f33e8de438d 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -430,8 +430,9 @@ smp_do_timer(struct pt_regs *regs) static void __init smp_cpu_init(int cpunum) { - extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */ + extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */ extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ + extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */ /* Set modes and Enable floating point coprocessor */ (void) init_per_cpu(cpunum); @@ -457,6 +458,7 @@ smp_cpu_init(int cpunum) enter_lazy_tlb(&init_mm, current); init_IRQ(); /* make sure no IRQ's are enabled or pending */ + start_cpu_itimer(); } diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index ab641d67f55..47831c2cd09 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -223,22 +223,24 @@ unsigned long long sched_clock(void) } +void __init start_cpu_itimer(void) +{ + unsigned int cpu = smp_processor_id(); + unsigned long next_tick = mfctl(16) + clocktick; + + mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */ + + cpu_data[cpu].it_value = next_tick; +} + void __init time_init(void) { - unsigned long next_tick; static struct pdc_tod tod_data; clocktick = (100 * PAGE0->mem_10msec) / HZ; halftick = clocktick / 2; - /* Setup clock interrupt timing */ - - next_tick = mfctl(16); - next_tick += clocktick; - cpu_data[smp_processor_id()].it_value = next_tick; - - /* kick off Itimer (CR16) */ - mtctl(next_tick, 16); + start_cpu_itimer(); /* get CPU 0 started */ if(pdc_tod_read(&tod_data) == 0) { write_seqlock_irq(&xtime_lock); -- GitLab From 65ee8f0a7fc2f2267b983f1f0349acb8f19db6e6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 8 Sep 2006 05:43:44 -0600 Subject: [PATCH 0437/1619] [PARISC] Enable interrupts while spinning Use the __raw_spin_lock_flags routine so we can take an interrupt while spinning. This re-fixes a bug jejb found on 2005-10-20: CPU0 does a flush_tlb_all holding the vmlist_lock for write. CPU1 tries a cat of /proc/meminfo which tries to acquire vmlist_lock for read CPU1 is now spinning with interrupts disabled CPU0 tries to execute a smp_call_function to flush the local tlb caches This is now a deadlock because CPU1 is spinning with interrupts disabled and can never receive the IPI Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/spinlock.h | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index 8980a876cc4..f3d2090a18d 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -57,35 +57,42 @@ static inline int __raw_spin_trylock(raw_spinlock_t *x) /* * Read-write spinlocks, allowing multiple readers but only one writer. - * The spinlock is held by the writer, preventing any readers or other - * writers from grabbing the rwlock. Readers use the lock to serialise their - * access to the counter (which records how many readers currently hold the - * lock). Linux rwlocks are unfair to writers; they can be starved for - * an indefinite time by readers. They can also be taken in interrupt context, - * so we have to disable interrupts when acquiring the spin lock to be sure - * that an interrupting reader doesn't get an inconsistent view of the lock. + * Linux rwlocks are unfair to writers; they can be starved for an indefinite + * time by readers. With care, they can also be taken in interrupt context. + * + * In the PA-RISC implementation, we have a spinlock and a counter. + * Readers use the lock to serialise their access to the counter (which + * records how many readers currently hold the lock). + * Writers hold the spinlock, preventing any readers or other writers from + * grabbing the rwlock. */ +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock */ static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { unsigned long flags; local_irq_save(flags); - __raw_spin_lock(&rw->lock); + __raw_spin_lock_flags(&rw->lock, flags); rw->counter++; __raw_spin_unlock(&rw->lock); local_irq_restore(flags); } +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock */ static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { unsigned long flags; local_irq_save(flags); - __raw_spin_lock(&rw->lock); + __raw_spin_lock_flags(&rw->lock, flags); rw->counter--; __raw_spin_unlock(&rw->lock); local_irq_restore(flags); } +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock */ static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) { unsigned long flags; @@ -110,12 +117,14 @@ static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) goto retry; } +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to read_trylock() this lock */ static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { unsigned long flags; retry: local_irq_save(flags); - __raw_spin_lock(&rw->lock); + __raw_spin_lock_flags(&rw->lock, flags); if (rw->counter != 0) { __raw_spin_unlock(&rw->lock); @@ -138,6 +147,8 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) __raw_spin_unlock(&rw->lock); } +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to read_trylock() this lock */ static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { unsigned long flags; -- GitLab From bed583f76e1d5fbb5a6fdf27a0f7b2ae235f7e99 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 8 Sep 2006 23:29:22 -0700 Subject: [PATCH 0438/1619] [PARISC] Rewrite timer_interrupt() and gettimeoffset() using "unsigned" math. It's just a bit easier to follow and timer code is complex enough. So far, only tested on A500-5x (64-bit SMP), ie: gettimeoffset() code hasn't been tested at all. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 140 ++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 44 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 47831c2cd09..fd425e1abe6 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -32,8 +32,8 @@ #include -static long clocktick __read_mostly; /* timer cycles per tick */ -static long halftick __read_mostly; +static unsigned long clocktick __read_mostly; /* timer cycles per tick */ +static unsigned long halftick __read_mostly; #ifdef CONFIG_SMP extern void smp_do_timer(struct pt_regs *regs); @@ -41,34 +41,77 @@ extern void smp_do_timer(struct pt_regs *regs); irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - long now; - long next_tick; - int nticks; + unsigned long now; + unsigned long next_tick; + unsigned long cycles_elapsed; + unsigned long cycles_remainder; + unsigned long ticks_elapsed = 1; /* at least one elapsed */ int cpu = smp_processor_id(); profile_tick(CPU_PROFILING, regs); - now = mfctl(16); - /* initialize next_tick to time at last clocktick */ + /* Initialize next_tick to the expected tick time. */ next_tick = cpu_data[cpu].it_value; - /* since time passes between the interrupt and the mfctl() - * above, it is never true that last_tick + clocktick == now. If we - * never miss a clocktick, we could set next_tick = last_tick + clocktick - * but maybe we'll miss ticks, hence the loop. - * - * Variables are *signed*. + /* Get current interval timer. + * CR16 reads as 64 bits in CPU wide mode. + * CR16 reads as 32 bits in CPU narrow mode. */ + now = mfctl(16); - nticks = 0; - while((next_tick - now) < halftick) { - next_tick += clocktick; - nticks++; + cycles_elapsed = now - next_tick; + + /* Determine how much time elapsed. */ + if (now < next_tick) { + /* Scenario 2: CR16 wrapped after clock tick. + * 1's complement will give us the "elapse cycles". + * + * This "cr16 wrapped" cruft is primarily for 32-bit kernels. + * So think "unsigned long is u32" when reading the code. + * And yes, of course 64-bit will someday wrap, but only + * every 198841 days on a 1GHz machine. + */ + cycles_elapsed = ~cycles_elapsed; /* off by one cycle - don't care */ } + + ticks_elapsed += cycles_elapsed / clocktick; + cycles_remainder = cycles_elapsed % clocktick; + + /* Can we differentiate between "early CR16" (aka Scenario 1) and + * "long delay" (aka Scenario 3)? I don't think so. + * + * We expected timer_interrupt to be delivered at least a few hundred + * cycles after the IT fires. But it's arbitrary how much time passes + * before we call it "late". I've picked one second. + */ + if (ticks_elapsed > HZ) { + /* Scenario 3: very long delay? bad in any case */ + printk (KERN_CRIT "timer_interrupt(CPU %d): delayed! run ntpdate" + " ticks %ld cycles %lX rem %lX" + " next/now %lX/%lX\n", + cpu, + ticks_elapsed, cycles_elapsed, cycles_remainder, + next_tick, now ); + + ticks_elapsed = 1; /* hack to limit damage in loop below */ + } + + + /* Determine when (in CR16 cycles) next IT interrupt will fire. + * We want IT to fire modulo clocktick even if we miss/skip some. + * But those interrupts don't in fact get delivered that regularly. + */ + next_tick = now + (clocktick - cycles_remainder); + + /* Program the IT when to deliver the next interrupt. */ + /* Only bottom 32-bits of next_tick are written to cr16. */ mtctl(next_tick, 16); cpu_data[cpu].it_value = next_tick; - while (nticks--) { + /* Now that we are done mucking with unreliable delivery of interrupts, + * go do system house keeping. + */ + while (ticks_elapsed--) { #ifdef CONFIG_SMP smp_do_timer(regs); #else @@ -121,21 +164,41 @@ gettimeoffset (void) * Once parisc-linux learns the cr16 difference between processors, * this could be made to work. */ - long last_tick; - long elapsed_cycles; + unsigned long now; + unsigned long prev_tick; + unsigned long next_tick; + unsigned long elapsed_cycles; + unsigned long usec; - /* it_value is the intended time of the next tick */ - last_tick = cpu_data[smp_processor_id()].it_value; + next_tick = cpu_data[smp_processor_id()].it_value; + now = mfctl(16); /* Read the hardware interval timer. */ - /* Subtract one tick and account for possible difference between - * when we expected the tick and when it actually arrived. - * (aka wall vs real) - */ - last_tick -= clocktick * (jiffies - wall_jiffies + 1); - elapsed_cycles = mfctl(16) - last_tick; + prev_tick = next_tick - clocktick; + + /* Assume Scenario 1: "now" is later than prev_tick. */ + elapsed_cycles = now - prev_tick; + + if (now < prev_tick) { + /* Scenario 2: CR16 wrapped! + * 1's complement is close enough. + */ + elapsed_cycles = ~elapsed_cycles; + } - /* the precision of this math could be improved */ - return elapsed_cycles / (PAGE0->mem_10msec / 10000); + if (elapsed_cycles > (HZ * clocktick)) { + /* Scenario 3: clock ticks are missing. */ + printk (KERN_CRIT "gettimeoffset(CPU %d): missing ticks!" + "cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", + cpuid, + elapsed_cycles, prev_tick, now, next_tick, clocktick); + } + + /* FIXME: Can we improve the precision? Not with PAGE0. */ + usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; + + /* add in "lost" jiffies */ + usec += clocktick * (jiffies - wall_jiffies); + return usec; #else return 0; #endif @@ -146,6 +209,7 @@ do_gettimeofday (struct timeval *tv) { unsigned long flags, seq, usec, sec; + /* Hold xtime_lock and adjust timeval. */ do { seq = read_seqbegin_irqsave(&xtime_lock, flags); usec = gettimeoffset(); @@ -153,25 +217,13 @@ do_gettimeofday (struct timeval *tv) usec += (xtime.tv_nsec / 1000); } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - if (unlikely(usec > LONG_MAX)) { - /* This can happen if the gettimeoffset adjustment is - * negative and xtime.tv_nsec is smaller than the - * adjustment */ - printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec); - usec += USEC_PER_SEC; - --sec; - /* This should never happen, it means the negative - * time adjustment was more than a second, so there's - * something seriously wrong */ - BUG_ON(usec > LONG_MAX); - } - - + /* Move adjusted usec's into sec's. */ while (usec >= USEC_PER_SEC) { usec -= USEC_PER_SEC; ++sec; } + /* Return adjusted result. */ tv->tv_sec = sec; tv->tv_usec = usec; } -- GitLab From 6b799d9222fef265802b0b6dcc4fb982cc8f55ca Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Mon, 4 Sep 2006 13:56:11 -0700 Subject: [PATCH 0439/1619] [PARISC] remove halftick and copy clocktick to local var (gcc can optimize usage) Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 46 ++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index fd425e1abe6..c43e847a4b8 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -33,7 +33,6 @@ #include static unsigned long clocktick __read_mostly; /* timer cycles per tick */ -static unsigned long halftick __read_mostly; #ifdef CONFIG_SMP extern void smp_do_timer(struct pt_regs *regs); @@ -48,6 +47,9 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned long ticks_elapsed = 1; /* at least one elapsed */ int cpu = smp_processor_id(); + /* gcc can optimize for "read-only" case with a local clocktick */ + unsigned long local_ct = clocktick; + profile_tick(CPU_PROFILING, regs); /* Initialize next_tick to the expected tick time. */ @@ -74,8 +76,16 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) cycles_elapsed = ~cycles_elapsed; /* off by one cycle - don't care */ } - ticks_elapsed += cycles_elapsed / clocktick; - cycles_remainder = cycles_elapsed % clocktick; + if (likely(cycles_elapsed < local_ct)) { + /* ticks_elapsed = 1 -- We already assumed one tick elapsed. */ + cycles_remainder = cycles_elapsed; + } else { + /* more than one tick elapsed. Do "expensive" math. */ + ticks_elapsed += cycles_elapsed / local_ct; + + /* Faster version of "remainder = elapsed % clocktick" */ + cycles_remainder = cycles_elapsed - (ticks_elapsed * local_ct); + } /* Can we differentiate between "early CR16" (aka Scenario 1) and * "long delay" (aka Scenario 3)? I don't think so. @@ -86,14 +96,12 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ if (ticks_elapsed > HZ) { /* Scenario 3: very long delay? bad in any case */ - printk (KERN_CRIT "timer_interrupt(CPU %d): delayed! run ntpdate" + printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" " ticks %ld cycles %lX rem %lX" " next/now %lX/%lX\n", cpu, ticks_elapsed, cycles_elapsed, cycles_remainder, next_tick, now ); - - ticks_elapsed = 1; /* hack to limit damage in loop below */ } @@ -101,12 +109,19 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * We want IT to fire modulo clocktick even if we miss/skip some. * But those interrupts don't in fact get delivered that regularly. */ - next_tick = now + (clocktick - cycles_remainder); + next_tick = now + (local_ct - cycles_remainder); + + /* Skip one clocktick on purpose if we are likely to miss next_tick. + * We'll catch what we missed on the tick after that. + * We should never need 0x1000 cycles to read CR16, calc the + * new next_tick, then write CR16 back. */ + if (!((local_ct - cycles_remainder) >> 12)) + next_tick += local_ct; /* Program the IT when to deliver the next interrupt. */ /* Only bottom 32-bits of next_tick are written to cr16. */ - mtctl(next_tick, 16); cpu_data[cpu].it_value = next_tick; + mtctl(next_tick, 16); /* Now that we are done mucking with unreliable delivery of interrupts, * go do system house keeping. @@ -169,35 +184,37 @@ gettimeoffset (void) unsigned long next_tick; unsigned long elapsed_cycles; unsigned long usec; + unsigned long cpuid = smp_processor_id(); + unsigned long local_ct = clocktick; - next_tick = cpu_data[smp_processor_id()].it_value; + next_tick = cpu_data[cpuid].it_value; now = mfctl(16); /* Read the hardware interval timer. */ - prev_tick = next_tick - clocktick; + prev_tick = next_tick - local_ct; /* Assume Scenario 1: "now" is later than prev_tick. */ elapsed_cycles = now - prev_tick; if (now < prev_tick) { /* Scenario 2: CR16 wrapped! - * 1's complement is close enough. + * ones complement is off-by-one. Don't care. */ elapsed_cycles = ~elapsed_cycles; } - if (elapsed_cycles > (HZ * clocktick)) { + if (elapsed_cycles > (HZ * local_ct)) { /* Scenario 3: clock ticks are missing. */ printk (KERN_CRIT "gettimeoffset(CPU %d): missing ticks!" "cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", cpuid, - elapsed_cycles, prev_tick, now, next_tick, clocktick); + elapsed_cycles, prev_tick, now, next_tick, local_ct); } /* FIXME: Can we improve the precision? Not with PAGE0. */ usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; /* add in "lost" jiffies */ - usec += clocktick * (jiffies - wall_jiffies); + usec += local_ct * (jiffies - wall_jiffies); return usec; #else return 0; @@ -290,7 +307,6 @@ void __init time_init(void) static struct pdc_tod tod_data; clocktick = (100 * PAGE0->mem_10msec) / HZ; - halftick = clocktick / 2; start_cpu_itimer(); /* get CPU 0 started */ -- GitLab From 6e5dc42b5add25c94ce0e95da87122f91b4bfdb3 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Sun, 10 Sep 2006 12:57:55 -0700 Subject: [PATCH 0440/1619] [PARISC] Further updates to timer_interrupt() This version (relative to the current tree): o eliminates "while (ticks_elapsed)" loop. It's not needed. o drop "ticks_elapsed" completely from timer_interrupt(). o Estimates elapsed cycles (based on HZ) to see which kind of math we want to use to calculate "cycles_remainder". o Fixes a bug where we would loose a tick if we decided we wanted to skip one interrupt. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 127 +++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 62 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index c43e847a4b8..9d642d820fe 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -43,12 +43,11 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned long now; unsigned long next_tick; unsigned long cycles_elapsed; - unsigned long cycles_remainder; - unsigned long ticks_elapsed = 1; /* at least one elapsed */ - int cpu = smp_processor_id(); + unsigned long cycles_remainder; + unsigned int cpu = smp_processor_id(); /* gcc can optimize for "read-only" case with a local clocktick */ - unsigned long local_ct = clocktick; + unsigned long cpt = clocktick; profile_tick(CPU_PROFILING, regs); @@ -63,28 +62,16 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) cycles_elapsed = now - next_tick; - /* Determine how much time elapsed. */ - if (now < next_tick) { - /* Scenario 2: CR16 wrapped after clock tick. - * 1's complement will give us the "elapse cycles". - * - * This "cr16 wrapped" cruft is primarily for 32-bit kernels. - * So think "unsigned long is u32" when reading the code. - * And yes, of course 64-bit will someday wrap, but only - * every 198841 days on a 1GHz machine. + if ((cycles_elapsed >> 5) < cpt) { + /* use "cheap" math (add/subtract) instead + * of the more expensive div/mul method */ - cycles_elapsed = ~cycles_elapsed; /* off by one cycle - don't care */ - } - - if (likely(cycles_elapsed < local_ct)) { - /* ticks_elapsed = 1 -- We already assumed one tick elapsed. */ cycles_remainder = cycles_elapsed; + while (cycles_remainder > cpt) { + cycles_remainder -= cpt; + } } else { - /* more than one tick elapsed. Do "expensive" math. */ - ticks_elapsed += cycles_elapsed / local_ct; - - /* Faster version of "remainder = elapsed % clocktick" */ - cycles_remainder = cycles_elapsed - (ticks_elapsed * local_ct); + cycles_remainder = cycles_elapsed % cpt; } /* Can we differentiate between "early CR16" (aka Scenario 1) and @@ -94,51 +81,65 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * cycles after the IT fires. But it's arbitrary how much time passes * before we call it "late". I've picked one second. */ - if (ticks_elapsed > HZ) { +/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ +#if HZ == 1000 + if (cycles_elapsed > (cpt << 10) ) +#elif HZ == 250 + if (cycles_elapsed > (cpt << 8) ) +#elif HZ == 100 + if (cycles_elapsed > (cpt << 7) ) +#else +#warn WTF is HZ set to anyway? + if (cycles_elapsed > (HZ * cpt) ) +#endif + { /* Scenario 3: very long delay? bad in any case */ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" - " ticks %ld cycles %lX rem %lX" + " cycles %lX rem %lX " " next/now %lX/%lX\n", cpu, - ticks_elapsed, cycles_elapsed, cycles_remainder, + cycles_elapsed, cycles_remainder, next_tick, now ); } + /* convert from "division remainder" to "remainder of clock tick" */ + cycles_remainder = cpt - cycles_remainder; /* Determine when (in CR16 cycles) next IT interrupt will fire. * We want IT to fire modulo clocktick even if we miss/skip some. * But those interrupts don't in fact get delivered that regularly. */ - next_tick = now + (local_ct - cycles_remainder); + next_tick = now + cycles_remainder; + + cpu_data[cpu].it_value = next_tick; /* Skip one clocktick on purpose if we are likely to miss next_tick. - * We'll catch what we missed on the tick after that. - * We should never need 0x1000 cycles to read CR16, calc the - * new next_tick, then write CR16 back. */ - if (!((local_ct - cycles_remainder) >> 12)) - next_tick += local_ct; + * We want to avoid the new next_tick being less than CR16. + * If that happened, itimer wouldn't fire until CR16 wrapped. + * We'll catch the tick we missed on the tick after that. + */ + if (!(cycles_remainder >> 13)) + next_tick += cpt; /* Program the IT when to deliver the next interrupt. */ /* Only bottom 32-bits of next_tick are written to cr16. */ - cpu_data[cpu].it_value = next_tick; mtctl(next_tick, 16); - /* Now that we are done mucking with unreliable delivery of interrupts, - * go do system house keeping. + + /* Done mucking with unreliable delivery of interrupts. + * Go do system house keeping. */ - while (ticks_elapsed--) { #ifdef CONFIG_SMP - smp_do_timer(regs); + smp_do_timer(regs); #else - update_process_times(user_mode(regs)); + update_process_times(user_mode(regs)); #endif - if (cpu == 0) { - write_seqlock(&xtime_lock); - do_timer(1); - write_sequnlock(&xtime_lock); - } + if (cpu == 0) { + write_seqlock(&xtime_lock); + do_timer(regs); + write_sequnlock(&xtime_lock); } - + /* check soft power switch status */ if (cpu == 0 && !atomic_read(&power_tasklet.count)) tasklet_schedule(&power_tasklet); @@ -164,14 +165,12 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); -/*** converted from ia64 ***/ /* * Return the number of micro-seconds that elapsed since the last * update to wall time (aka xtime). The xtime_lock * must be at least read-locked when calling this routine. */ -static inline unsigned long -gettimeoffset (void) +static inline unsigned long gettimeoffset (void) { #ifndef CONFIG_SMP /* @@ -185,36 +184,40 @@ gettimeoffset (void) unsigned long elapsed_cycles; unsigned long usec; unsigned long cpuid = smp_processor_id(); - unsigned long local_ct = clocktick; + unsigned long cpt = clocktick; next_tick = cpu_data[cpuid].it_value; now = mfctl(16); /* Read the hardware interval timer. */ - prev_tick = next_tick - local_ct; + prev_tick = next_tick - cpt; /* Assume Scenario 1: "now" is later than prev_tick. */ elapsed_cycles = now - prev_tick; - if (now < prev_tick) { - /* Scenario 2: CR16 wrapped! - * ones complement is off-by-one. Don't care. - */ - elapsed_cycles = ~elapsed_cycles; - } - - if (elapsed_cycles > (HZ * local_ct)) { +/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ +#if HZ == 1000 + if (elapsed_cycles > (cpt << 10) ) +#elif HZ == 250 + if (elapsed_cycles > (cpt << 8) ) +#elif HZ == 100 + if (elapsed_cycles > (cpt << 7) ) +#else +#warn WTF is HZ set to anyway? + if (elapsed_cycles > (HZ * cpt) ) +#endif + { /* Scenario 3: clock ticks are missing. */ - printk (KERN_CRIT "gettimeoffset(CPU %d): missing ticks!" - "cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", - cpuid, - elapsed_cycles, prev_tick, now, next_tick, local_ct); + printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!" + " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", + cpuid, elapsed_cycles / cpt, + elapsed_cycles, prev_tick, now, next_tick, cpt); } /* FIXME: Can we improve the precision? Not with PAGE0. */ usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; /* add in "lost" jiffies */ - usec += local_ct * (jiffies - wall_jiffies); + usec += cpt * (jiffies - wall_jiffies); return usec; #else return 0; -- GitLab From 7085689ed135f94108e46c372015c6f5cd3372a3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 9 Sep 2006 12:36:25 -0700 Subject: [PATCH 0441/1619] [PARISC] Allow nested interrupts Our prior mode of operation didn't allow nested interrupts because it makes the interrupt code much simpler. However, nested interrupts are better for latency. This code uses the EIEM register to simulate level interrupts and thus achieve nesting. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin --- arch/parisc/kernel/irq.c | 149 ++++++++++++++++++++++----------------- arch/parisc/kernel/smp.c | 3 + drivers/parisc/iosapic.c | 3 +- include/asm-parisc/irq.h | 2 + 4 files changed, 93 insertions(+), 64 deletions(-) diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index c53bfeb4bf9..9bdd0197ceb 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -45,6 +45,17 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); */ static volatile unsigned long cpu_eiem = 0; +/* +** ack bitmap ... habitually set to 1, but reset to zero +** between ->ack() and ->end() of the interrupt to prevent +** re-interruption of a processing interrupt. +*/ +static volatile unsigned long global_ack_eiem = ~0UL; +/* +** Local bitmap, same as above but for per-cpu interrupts +*/ +static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL; + static void cpu_disable_irq(unsigned int irq) { unsigned long eirr_bit = EIEM_MASK(irq); @@ -62,13 +73,6 @@ static void cpu_enable_irq(unsigned int irq) cpu_eiem |= eirr_bit; - /* FIXME: while our interrupts aren't nested, we cannot reset - * the eiem mask if we're already in an interrupt. Once we - * implement nested interrupts, this can go away - */ - if (!in_interrupt()) - set_eiem(cpu_eiem); - /* This is just a simple NOP IPI. But what it does is cause * all the other CPUs to do a set_eiem(cpu_eiem) at the end * of the interrupt handler */ @@ -84,13 +88,45 @@ static unsigned int cpu_startup_irq(unsigned int irq) void no_ack_irq(unsigned int irq) { } void no_end_irq(unsigned int irq) { } +void cpu_ack_irq(unsigned int irq) +{ + unsigned long mask = EIEM_MASK(irq); + int cpu = smp_processor_id(); + + /* Clear in EIEM so we can no longer process */ + if (CHECK_IRQ_PER_CPU(irq_desc[irq].status)) + per_cpu(local_ack_eiem, cpu) &= ~mask; + else + global_ack_eiem &= ~mask; + + /* disable the interrupt */ + set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); + /* and now ack it */ + mtctl(mask, 23); +} + +void cpu_end_irq(unsigned int irq) +{ + unsigned long mask = EIEM_MASK(irq); + int cpu = smp_processor_id(); + + /* set it in the eiems---it's no longer in process */ + if (CHECK_IRQ_PER_CPU(irq_desc[irq].status)) + per_cpu(local_ack_eiem, cpu) |= mask; + else + global_ack_eiem |= mask; + + /* enable the interrupt */ + set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); +} + #ifdef CONFIG_SMP int cpu_check_affinity(unsigned int irq, cpumask_t *dest) { int cpu_dest; /* timer and ipi have to always be received on all CPUs */ - if (irq == TIMER_IRQ || irq == IPI_IRQ) { + if (CHECK_IRQ_PER_CPU(irq)) { /* Bad linux design decision. The mask has already * been set; we must reset it */ irq_desc[irq].affinity = CPU_MASK_ALL; @@ -119,8 +155,8 @@ static struct hw_interrupt_type cpu_interrupt_type = { .shutdown = cpu_disable_irq, .enable = cpu_enable_irq, .disable = cpu_disable_irq, - .ack = no_ack_irq, - .end = no_end_irq, + .ack = cpu_ack_irq, + .end = cpu_end_irq, #ifdef CONFIG_SMP .set_affinity = cpu_set_affinity_irq, #endif @@ -298,82 +334,69 @@ unsigned int txn_alloc_data(unsigned int virt_irq) return virt_irq - CPU_IRQ_BASE; } +static inline int eirr_to_irq(unsigned long eirr) +{ +#ifdef CONFIG_64BIT + int bit = fls64(eirr); +#else + int bit = fls(eirr); +#endif + return (BITS_PER_LONG - bit) + TIMER_IRQ; +} + /* ONLY called from entry.S:intr_extint() */ void do_cpu_irq_mask(struct pt_regs *regs) { unsigned long eirr_val; - - irq_enter(); - - /* - * Don't allow TIMER or IPI nested interrupts. - * Allowing any single interrupt to nest can lead to that CPU - * handling interrupts with all enabled interrupts unmasked. - */ - set_eiem(0UL); - - /* 1) only process IRQs that are enabled/unmasked (cpu_eiem) - * 2) We loop here on EIRR contents in order to avoid - * nested interrupts or having to take another interrupt - * when we could have just handled it right away. - */ - for (;;) { - unsigned long bit = (1UL << (BITS_PER_LONG - 1)); - unsigned int irq; - eirr_val = mfctl(23) & cpu_eiem; - if (!eirr_val) - break; - - mtctl(eirr_val, 23); /* reset bits we are going to process */ - - /* Work our way from MSb to LSb...same order we alloc EIRs */ - for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) { + int irq, cpu = smp_processor_id(); #ifdef CONFIG_SMP - cpumask_t dest = irq_desc[irq].affinity; + cpumask_t dest; #endif - if (!(bit & eirr_val)) - continue; - /* clear bit in mask - can exit loop sooner */ - eirr_val &= ~bit; + local_irq_disable(); + irq_enter(); -#ifdef CONFIG_SMP - /* FIXME: because generic set affinity mucks - * with the affinity before sending it to us - * we can get the situation where the affinity is - * wrong for our CPU type interrupts */ - if (irq != TIMER_IRQ && irq != IPI_IRQ && - !cpu_isset(smp_processor_id(), dest)) { - int cpu = first_cpu(dest); - - printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", - irq, smp_processor_id(), cpu); - gsc_writel(irq + CPU_IRQ_BASE, - cpu_data[cpu].hpa); - continue; - } -#endif + eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem & + per_cpu(local_ack_eiem, cpu); + if (!eirr_val) + goto set_out; + irq = eirr_to_irq(eirr_val); - __do_IRQ(irq, regs); - } +#ifdef CONFIG_SMP + dest = irq_desc[irq].affinity; + if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) && + !cpu_isset(smp_processor_id(), dest)) { + int cpu = first_cpu(dest); + + printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", + irq, smp_processor_id(), cpu); + gsc_writel(irq + CPU_IRQ_BASE, + cpu_data[cpu].hpa); + goto set_out; } +#endif + __do_IRQ(irq, regs); - set_eiem(cpu_eiem); /* restore original mask */ + out: irq_exit(); -} + return; + set_out: + set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); + goto out; +} static struct irqaction timer_action = { .handler = timer_interrupt, .name = "timer", - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU, }; #ifdef CONFIG_SMP static struct irqaction ipi_action = { .handler = ipi_interrupt, .name = "IPI", - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_PERCPU, }; #endif diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index f33e8de438d..faad338f310 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) this_cpu, which); return IRQ_NONE; } /* Switch */ + /* let in any pending interrupts */ + local_irq_enable(); + local_irq_disable(); } /* while (ops) */ } return IRQ_HANDLED; diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 1fbda77cefc..90489ade632 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -692,6 +692,7 @@ static void iosapic_end_irq(unsigned int irq) DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq, vi->eoi_addr, vi->eoi_data); iosapic_eoi(vi->eoi_addr, vi->eoi_data); + cpu_end_irq(irq); } static unsigned int iosapic_startup_irq(unsigned int irq) @@ -728,7 +729,7 @@ static struct hw_interrupt_type iosapic_interrupt_type = { .shutdown = iosapic_disable_irq, .enable = iosapic_enable_irq, .disable = iosapic_disable_irq, - .ack = no_ack_irq, + .ack = cpu_ack_irq, .end = iosapic_end_irq, #ifdef CONFIG_SMP .set_affinity = iosapic_set_affinity_irq, diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h index 6e29cfa2812..399c81981ed 100644 --- a/include/asm-parisc/irq.h +++ b/include/asm-parisc/irq.h @@ -39,6 +39,8 @@ struct irq_chip; */ void no_ack_irq(unsigned int irq); void no_end_irq(unsigned int irq); +void cpu_ack_irq(unsigned int irq); +void cpu_end_irq(unsigned int irq); extern int txn_alloc_irq(unsigned int nbits); extern int txn_claim_irq(int); -- GitLab From 8a63674f70ac443d166b746d6c04154f8ee9de7b Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 12 Sep 2006 05:17:59 -0600 Subject: [PATCH 0442/1619] [PARISC] Add hardware found in the rp8400 Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/hardware.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c index 3058bffd8a2..18ba4cb9159 100644 --- a/arch/parisc/kernel/hardware.c +++ b/arch/parisc/kernel/hardware.c @@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_list[] __initdata = { {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"}, {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"}, {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"}, + {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"}, {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, @@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_list[] __initdata = { {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, + {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"}, {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, + {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"}, {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, -- GitLab From 7886089e3c06518c5e65675a932922f915e20e77 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 12 Sep 2006 05:19:15 -0600 Subject: [PATCH 0443/1619] [PARISC] Remove some obsolete comments and I checked that Reo is similar to Ike Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index d80ce476189..e0d6fbc66ef 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1717,7 +1717,6 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, if (IS_ASTRO(sba_dev->iodc)) { int err; - /* PAT_PDC (L-class) also reports the same goofy base */ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET); num_ioc = 1; @@ -1730,10 +1729,6 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, } else if (IS_PLUTO(sba_dev->iodc)) { int err; - /* We use a negative value for IOC HPA so it gets - * corrected when we add it with IKE's IOC offset. - * Doesnt look clean, but fewer code. - */ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET); num_ioc = 1; @@ -1749,14 +1744,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, err = request_resource(&iomem_resource, &(sba_dev->iommu_resv)); WARN_ON(err < 0); } else { - /* IS_IKE (ie N-class, L3000, L1500) */ + /* IKE, REO */ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0)); sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1)); num_ioc = 2; /* TODO - LOOKUP Ike/Stretch chipset mem map */ } - /* XXX: What about Reo? */ + /* XXX: What about Reo Grande? */ sba_dev->num_ioc = num_ioc; for (i = 0; i < num_ioc; i++) { -- GitLab From ba9877b6734fb0313bca99ae2077613f24ff5b5c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:28:58 -0400 Subject: [PATCH 0444/1619] [PARISC] Pretty print the name of the lba type on kernel boot (it's pretty useless telling a user they have a whole bunch of TR%d.%d LBAs) Signed-off-by: Kyle McMartin --- drivers/parisc/lba_pci.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 3fe4a77fa16..33d1806a39c 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1542,8 +1542,8 @@ lba_driver_probe(struct parisc_device *dev) default: version = "TR4+"; } - printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xf, dev->hpa.start); + printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n", + version, func_class & 0xf, dev->hpa.start); if (func_class < 2) { printk(KERN_WARNING "Can't support LBA older than " @@ -1563,14 +1563,18 @@ lba_driver_probe(struct parisc_device *dev) } } else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) { + int major, minor; + func_class &= 0xff; - version = kmalloc(6, GFP_KERNEL); - snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf)); + major = func_class >> 4, minor = func_class & 0xf; + /* We could use one printk for both Elroy and Mercury, * but for the mask for func_class. */ - printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xff, dev->hpa.start); + printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n", + IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major, + minor, func_class, dev->hpa.start); + cfg_ops = &mercury_cfg_ops; } else { printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start); -- GitLab From 1b240f415f42204ff5a885c1c552b26a2ee780a1 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:30:19 -0400 Subject: [PATCH 0445/1619] [PARISC] Generalize IS_ASTRO et al to take a parisc_device like IS_ELROY. Also remove the useless caching of the parisc_device_id in struct sba_device. Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index e0d6fbc66ef..5fbc11e4bc5 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -117,9 +117,17 @@ #define SBA_FUNC_ID 0x0000 /* function id */ #define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ -#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT) -#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT) -#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT) +static inline int IS_ASTRO(struct parisc_device *d) { + return d->id.hversion == ASTRO_RUNWAY_PORT; +} + +static inline int IS_IKE(struct parisc_device *d) { + return d->id.hversion == IKE_MERCED_PORT; +} + +static inline int IS_PLUTO(struct parisc_device *d) { + return d->id.hversion == PLUTO_MCKINLEY_PORT; +} #define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ @@ -269,7 +277,6 @@ struct ioc { struct sba_device { struct sba_device *next; /* list of SBA's in system */ struct parisc_device *dev; /* dev found in bus walk */ - struct parisc_device_id *iodc; /* data about dev from firmware */ const char *name; void __iomem *sba_hpa; /* base address */ spinlock_t sba_lock; @@ -1698,7 +1705,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, } #endif - if (!IS_PLUTO(sba_dev->iodc)) { + if (!IS_PLUTO(sba_dev->dev)) { ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL); DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl); @@ -1715,7 +1722,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, #endif } /* if !PLUTO */ - if (IS_ASTRO(sba_dev->iodc)) { + if (IS_ASTRO(sba_dev->dev)) { int err; sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET); num_ioc = 1; @@ -1726,7 +1733,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, err = request_resource(&iomem_resource, &(sba_dev->chip_resv)); BUG_ON(err < 0); - } else if (IS_PLUTO(sba_dev->iodc)) { + } else if (IS_PLUTO(sba_dev->dev)) { int err; sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET); @@ -1766,7 +1773,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, * Overrides bit 1 in DMA Hint Sets. * Improves netperf UDP_STREAM by ~10% for bcm5701. */ - if (IS_PLUTO(sba_dev->iodc)) { + if (IS_PLUTO(sba_dev->dev)) { void __iomem *rope_cfg; unsigned long cfg_val; @@ -1795,7 +1802,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400) ); - if (IS_PLUTO(sba_dev->iodc)) { + if (IS_PLUTO(sba_dev->dev)) { sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i); } else { sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i); @@ -2059,7 +2066,7 @@ sba_driver_callback(struct parisc_device *dev) /* Read HW Rev First */ func_class = READ_REG(sba_addr + SBA_FCLASS); - if (IS_ASTRO(&dev->id)) { + if (IS_ASTRO(dev)) { unsigned long fclass; static char astro_rev[]="Astro ?.?"; @@ -2070,11 +2077,11 @@ sba_driver_callback(struct parisc_device *dev) astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3); version = astro_rev; - } else if (IS_IKE(&dev->id)) { + } else if (IS_IKE(dev)) { static char ike_rev[] = "Ike rev ?"; ike_rev[8] = '0' + (char) (func_class & 0xff); version = ike_rev; - } else if (IS_PLUTO(&dev->id)) { + } else if (IS_PLUTO(dev)) { static char pluto_rev[]="Pluto ?.?"; pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4); pluto_rev[8] = '0' + (char) (func_class & 0x0f); @@ -2089,7 +2096,7 @@ sba_driver_callback(struct parisc_device *dev) global_ioc_cnt = count_parisc_driver(&sba_driver); /* Astro and Pluto have one IOC per SBA */ - if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id))) + if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev))) global_ioc_cnt *= 2; } @@ -2109,7 +2116,6 @@ sba_driver_callback(struct parisc_device *dev) sba_dev->dev = dev; sba_dev->hw_rev = func_class; - sba_dev->iodc = &dev->id; sba_dev->name = dev->name; sba_dev->sba_hpa = sba_addr; -- GitLab From b0eecc4da9c0a5261711e0d83280fd5d1e3db742 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:31:41 -0400 Subject: [PATCH 0446/1619] [PARISC] Stash the lba_device in its struct device drvdata Signed-off-by: Kyle McMartin --- drivers/parisc/lba_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 33d1806a39c..a596dbc804a 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1604,6 +1604,7 @@ lba_driver_probe(struct parisc_device *dev) lba_dev->hba.dev = dev; lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */ + parisc_set_drvdata(dev, lba_dev); /* ------------ Second : initialize common stuff ---------- */ pci_bios = &lba_bios_ops; -- GitLab From 1790cf9111f61d360d861901b97eba4de3b5414c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:32:49 -0400 Subject: [PATCH 0447/1619] [PARISC] Create shared header Pull out struct sba_device and struct lba_device into a common ropes.h header. Also fold the parisc portion of iosapic.h into this file. (Then delete the useless portion of iosapic.h) Signed-off-by: Kyle McMartin --- drivers/parisc/iosapic.c | 2 +- drivers/parisc/lba_pci.c | 40 +--------- drivers/parisc/sba_iommu.c | 109 +------------------------ include/asm-parisc/iosapic.h | 53 ------------- include/asm-parisc/ropes.h | 150 +++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 201 deletions(-) delete mode 100644 include/asm-parisc/iosapic.h create mode 100644 include/asm-parisc/ropes.h diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 90489ade632..c2949b4367e 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -146,7 +146,7 @@ #include #endif -#include +#include #include "./iosapic_private.h" #define MODULE_NAME "iosapic" diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index a596dbc804a..98f03686a71 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -46,9 +46,9 @@ #include #include +#include #include /* for register_parisc_driver() stuff */ #include -#include /* for iosapic_register() */ #include /* read/write stuff */ #undef DEBUG_LBA /* general stuff */ @@ -169,44 +169,6 @@ #define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL) static void __iomem *astro_iop_base __read_mostly; -#define ELROY_HVERS 0x782 -#define MERCURY_HVERS 0x783 -#define QUICKSILVER_HVERS 0x784 - -static inline int IS_ELROY(struct parisc_device *d) -{ - return (d->id.hversion == ELROY_HVERS); -} - -static inline int IS_MERCURY(struct parisc_device *d) -{ - return (d->id.hversion == MERCURY_HVERS); -} - -static inline int IS_QUICKSILVER(struct parisc_device *d) -{ - return (d->id.hversion == QUICKSILVER_HVERS); -} - - -/* -** lba_device: Per instance Elroy data structure -*/ -struct lba_device { - struct pci_hba_data hba; - - spinlock_t lba_lock; - void *iosapic_obj; - -#ifdef CONFIG_64BIT - void __iomem * iop_base; /* PA_VIEW - for IO port accessor funcs */ -#endif - - int flags; /* state/functionality enabled */ - int hw_rev; /* HW revision of chip */ -}; - - static u32 lba_t32; /* lba flags */ diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 5fbc11e4bc5..12776b7e3a8 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -38,6 +38,7 @@ #include #include +#include #include /* for proc_mckinley_root */ #include /* for proc_runway_root */ #include /* for PDC_MODEL_* */ @@ -46,11 +47,6 @@ #define MODULE_NAME "SBA" -#ifdef CONFIG_PROC_FS -/* depends on proc fs support. But costs CPU performance */ -#undef SBA_COLLECT_STATS -#endif - /* ** The number of debug flags is a clue - this code is fragile. ** Don't even think about messing with it unless you have @@ -89,46 +85,13 @@ #define DBG_RES(x...) #endif -#if defined(CONFIG_64BIT) -/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ -#define ZX1_SUPPORT -#endif - #define SBA_INLINE __inline__ - -/* -** The number of pdir entries to "free" before issueing -** 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 -** less interesting). -*/ -#define DELAYED_RESOURCE_CNT 16 - #define DEFAULT_DMA_HINT_REG 0 -#define ASTRO_RUNWAY_PORT 0x582 -#define IKE_MERCED_PORT 0x803 -#define REO_MERCED_PORT 0x804 -#define REOG_MERCED_PORT 0x805 -#define PLUTO_MCKINLEY_PORT 0x880 - #define SBA_FUNC_ID 0x0000 /* function id */ #define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ -static inline int IS_ASTRO(struct parisc_device *d) { - return d->id.hversion == ASTRO_RUNWAY_PORT; -} - -static inline int IS_IKE(struct parisc_device *d) { - return d->id.hversion == IKE_MERCED_PORT; -} - -static inline int IS_PLUTO(struct parisc_device *d) { - return d->id.hversion == PLUTO_MCKINLEY_PORT; -} - #define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ #define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE) @@ -145,10 +108,6 @@ static inline int IS_PLUTO(struct parisc_device *d) { #define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */ #define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */ -#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */ - -#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */ - /* ** Offsets into MBIB (Function 0 on Ike and hopefully Astro) @@ -196,9 +155,6 @@ static inline int IS_PLUTO(struct parisc_device *d) { #define IOC_TCNFG 0x318 #define IOC_PDIR_BASE 0x320 -/* AGP GART driver looks for this */ -#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL - /* ** IOC supports 4/8/16/64KB page sizes (see TCNFG register) @@ -228,69 +184,6 @@ static inline int IS_PLUTO(struct parisc_device *d) { #define SBA_PERF_CNT2 0x208 #define SBA_PERF_CNT3 0x210 - -struct ioc { - void __iomem *ioc_hpa; /* I/O MMU base address */ - char *res_map; /* resource map, bit == pdir entry */ - u64 *pdir_base; /* physical base address */ - unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ - unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ -#ifdef ZX1_SUPPORT - unsigned long iovp_mask; /* help convert IOVA to IOVP */ -#endif - unsigned long *res_hint; /* next avail IOVP - circular search */ - spinlock_t res_lock; - unsigned int res_bitshift; /* from the LEFT! */ - unsigned int res_size; /* size of resource map in bytes */ -#ifdef SBA_HINT_SUPPORT -/* FIXME : DMA HINTs not used */ - unsigned long hint_mask_pdir; /* bits used for DMA hints */ - unsigned int hint_shift_pdir; -#endif -#if DELAYED_RESOURCE_CNT > 0 - int saved_cnt; - struct sba_dma_pair { - dma_addr_t iova; - size_t size; - } saved[DELAYED_RESOURCE_CNT]; -#endif - -#ifdef SBA_COLLECT_STATS -#define SBA_SEARCH_SAMPLE 0x100 - unsigned long avg_search[SBA_SEARCH_SAMPLE]; - unsigned long avg_idx; /* current index into avg_search */ - unsigned long used_pages; - unsigned long msingle_calls; - unsigned long msingle_pages; - unsigned long msg_calls; - unsigned long msg_pages; - unsigned long usingle_calls; - unsigned long usingle_pages; - unsigned long usg_calls; - unsigned long usg_pages; -#endif - - /* STUFF We don't need in performance path */ - unsigned int pdir_size; /* in bytes, determined by IOV Space size */ -}; - -struct sba_device { - struct sba_device *next; /* list of SBA's in system */ - struct parisc_device *dev; /* dev found in bus walk */ - const char *name; - void __iomem *sba_hpa; /* base address */ - spinlock_t sba_lock; - unsigned int flags; /* state/functionality enabled */ - unsigned int hw_rev; /* HW revision of chip */ - - struct resource chip_resv; /* MMIO reserved for chip */ - struct resource iommu_resv; /* MMIO reserved for iommu */ - - unsigned int num_ioc; /* number of on-board IOC's */ - struct ioc ioc[MAX_IOC]; -}; - - static struct sba_device *sba_list; static unsigned long ioc_needs_fdc = 0; diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h deleted file mode 100644 index 613390e6805..00000000000 --- a/include/asm-parisc/iosapic.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -** This file is private to iosapic driver. -** If stuff needs to be used by another driver, move it to a common file. -** -** WARNING: fields most data structures here are ordered to make sure -** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8) -*/ - - -/* -** I/O SAPIC init function -** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC. -** Call setup as part of per instance initialization. -** (ie *not* init_module() function unless only one is present.) -** fixup_irq is to initialize PCI IRQ line support and -** virtualize pcidev->irq value. To be called by pci_fixup_bus(). -*/ -extern void *iosapic_register(unsigned long hpa); -extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev); - - -#ifdef __IA64__ -/* -** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter. -** and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field. -** -** IA64: PIB is handled by "Local SAPIC" (integrated in the processor). -*/ -struct local_sapic_info { - struct local_sapic_info *lsi_next; /* point to next CPU info */ - int *lsi_cpu_id; /* point to logical CPU id */ - unsigned long *lsi_id_eid; /* point to IA-64 CPU id */ - int *lsi_status; /* point to CPU status */ - void *lsi_private; /* point to special info */ -}; - -/* -** "root" data structure which ties everything together. -** Should always be able to start with sapic_root and locate -** the desired information. -*/ -struct sapic_info { - struct sapic_info *si_next; /* info is per cell */ - int si_cellid; /* cell id */ - unsigned int si_status; /* status */ - char *si_pib_base; /* intr blk base address */ - local_sapic_info_t *si_local_info; - io_sapic_info_t *si_io_info; - extint_info_t *si_extint_info;/* External Intr info */ -}; - -#endif /* IA64 */ - diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h new file mode 100644 index 00000000000..413dfcca15c --- /dev/null +++ b/include/asm-parisc/ropes.h @@ -0,0 +1,150 @@ +#ifndef _ASM_PARISC_ROPES_H_ +#define _ASM_PARISC_ROPES_H_ + +#ifdef CONFIG_64BIT +/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ +#define ZX1_SUPPORT +#endif + +#ifdef CONFIG_PROC_FS +/* depends on proc fs support. But costs CPU performance */ +#undef SBA_COLLECT_STATS +#endif + +/* +** The number of pdir entries to "free" before issueing +** 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 +** less interesting). +*/ +#define DELAYED_RESOURCE_CNT 16 + +#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */ +#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */ + +struct ioc { + void __iomem *ioc_hpa; /* I/O MMU base address */ + char *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ + unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ +#ifdef ZX1_SUPPORT + unsigned long iovp_mask; /* help convert IOVA to IOVP */ +#endif + unsigned long *res_hint; /* next avail IOVP - circular search */ + spinlock_t res_lock; + unsigned int res_bitshift; /* from the LEFT! */ + unsigned int res_size; /* size of resource map in bytes */ +#ifdef SBA_HINT_SUPPORT +/* FIXME : DMA HINTs not used */ + unsigned long hint_mask_pdir; /* bits used for DMA hints */ + unsigned int hint_shift_pdir; +#endif +#if DELAYED_RESOURCE_CNT > 0 + int saved_cnt; + struct sba_dma_pair { + dma_addr_t iova; + size_t size; + } saved[DELAYED_RESOURCE_CNT]; +#endif + +#ifdef SBA_COLLECT_STATS +#define SBA_SEARCH_SAMPLE 0x100 + unsigned long avg_search[SBA_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; +#endif + /* STUFF We don't need in performance path */ + unsigned int pdir_size; /* in bytes, determined by IOV Space size */ +}; + +struct sba_device { + struct sba_device *next; /* list of SBA's in system */ + struct parisc_device *dev; /* dev found in bus walk */ + const char *name; + void __iomem *sba_hpa; /* base address */ + spinlock_t sba_lock; + unsigned int flags; /* state/functionality enabled */ + unsigned int hw_rev; /* HW revision of chip */ + + struct resource chip_resv; /* MMIO reserved for chip */ + struct resource iommu_resv; /* MMIO reserved for iommu */ + + unsigned int num_ioc; /* number of on-board IOC's */ + struct ioc ioc[MAX_IOC]; +}; + +#define ASTRO_RUNWAY_PORT 0x582 +#define IKE_MERCED_PORT 0x803 +#define REO_MERCED_PORT 0x804 +#define REOG_MERCED_PORT 0x805 +#define PLUTO_MCKINLEY_PORT 0x880 + +static inline int IS_ASTRO(struct parisc_device *d) { + return d->id.hversion == ASTRO_RUNWAY_PORT; +} + +static inline int IS_IKE(struct parisc_device *d) { + return d->id.hversion == IKE_MERCED_PORT; +} + +static inline int IS_PLUTO(struct parisc_device *d) { + return d->id.hversion == PLUTO_MCKINLEY_PORT; +} + +#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL + +/* +** lba_device: Per instance Elroy data structure +*/ +struct lba_device { + struct pci_hba_data hba; + + spinlock_t lba_lock; + void *iosapic_obj; + +#ifdef CONFIG_64BIT + void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */ +#endif + + int flags; /* state/functionality enabled */ + int hw_rev; /* HW revision of chip */ +}; + +#define ELROY_HVERS 0x782 +#define MERCURY_HVERS 0x783 +#define QUICKSILVER_HVERS 0x784 + +static inline int IS_ELROY(struct parisc_device *d) { + return (d->id.hversion == ELROY_HVERS); +} + +static inline int IS_MERCURY(struct parisc_device *d) { + return (d->id.hversion == MERCURY_HVERS); +} + +static inline int IS_QUICKSILVER(struct parisc_device *d) { + return (d->id.hversion == QUICKSILVER_HVERS); +} + +/* +** I/O SAPIC init function +** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC. +** Call setup as part of per instance initialization. +** (ie *not* init_module() function unless only one is present.) +** fixup_irq is to initialize PCI IRQ line support and +** virtualize pcidev->irq value. To be called by pci_fixup_bus(). +*/ +extern void *iosapic_register(unsigned long hpa); +extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev); + +#endif /*_ASM_PARISC_ROPES_H_*/ -- GitLab From 983daeec99f07fca0a8a9180ba1ca65bbd40c820 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 25 Aug 2006 12:28:24 -0400 Subject: [PATCH 0448/1619] [PARISC] Move LBA and SBA register defines to the common ropes.h header. This will allow the use of more constants in the agpgart driver. Signed-off-by: Kyle McMartin --- drivers/parisc/lba_pci.c | 65 --------------- drivers/parisc/sba_iommu.c | 97 +--------------------- include/asm-parisc/ropes.h | 162 ++++++++++++++++++++++++++++++++++++- 3 files changed, 162 insertions(+), 162 deletions(-) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 98f03686a71..ba6769934c7 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -100,71 +100,6 @@ #define MODULE_NAME "LBA" -#define LBA_FUNC_ID 0x0000 /* function id */ -#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ -#define LBA_CAPABLE 0x0030 /* capabilities register */ - -#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ -#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ - -#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ -#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ -#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ - -#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ -#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ -#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ -#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ - -#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ - -#define LBA_STAT_CTL 0x0108 /* Status & Control */ -#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */ -#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */ -#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */ -#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ - -#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ -#define LBA_LMMIO_MASK 0x0208 - -#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ -#define LBA_GMMIO_MASK 0x0218 - -#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ -#define LBA_WLMMIO_MASK 0x0228 - -#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ -#define LBA_WGMMIO_MASK 0x0238 - -#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ -#define LBA_IOS_MASK 0x0248 - -#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ -#define LBA_ELMMIO_MASK 0x0258 - -#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ -#define LBA_EIOS_MASK 0x0268 - -#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */ -#define LBA_DMA_CTL 0x0278 /* firmware sets this */ - -#define LBA_IBASE 0x0300 /* SBA DMA support */ -#define LBA_IMASK 0x0308 - -/* FIXME: ignore DMA Hint stuff until we can measure performance */ -#define LBA_HINT_CFG 0x0310 -#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ - -#define LBA_BUS_MODE 0x0620 - -/* ERROR regs are needed for config cycle kluges */ -#define LBA_ERROR_CONFIG 0x0680 -#define LBA_SMART_MODE 0x20 -#define LBA_ERROR_STATUS 0x0688 -#define LBA_ROPE_CTL 0x06A0 - -#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ - /* non-postable I/O port space, densely packed */ #define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL) static void __iomem *astro_iop_base __read_mostly; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 12776b7e3a8..eed99bdcfb6 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -89,101 +89,6 @@ #define DEFAULT_DMA_HINT_REG 0 -#define SBA_FUNC_ID 0x0000 /* function id */ -#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ - -#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ - -#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE) -#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE) -/* Ike's IOC's occupy functions 2 and 3 */ -#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE) - -#define IOC_CTRL 0x8 /* IOC_CTRL offset */ -#define IOC_CTRL_TC (1 << 0) /* TOC Enable */ -#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */ -#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */ -#define IOC_CTRL_RM (1 << 8) /* Real Mode */ -#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */ -#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */ -#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */ - - -/* -** Offsets into MBIB (Function 0 on Ike and hopefully Astro) -** Firmware programs this stuff. Don't touch it. -*/ -#define LMMIO_DIRECT0_BASE 0x300 -#define LMMIO_DIRECT0_MASK 0x308 -#define LMMIO_DIRECT0_ROUTE 0x310 - -#define LMMIO_DIST_BASE 0x360 -#define LMMIO_DIST_MASK 0x368 -#define LMMIO_DIST_ROUTE 0x370 - -#define IOS_DIST_BASE 0x390 -#define IOS_DIST_MASK 0x398 -#define IOS_DIST_ROUTE 0x3A0 - -#define IOS_DIRECT_BASE 0x3C0 -#define IOS_DIRECT_MASK 0x3C8 -#define IOS_DIRECT_ROUTE 0x3D0 - -/* -** Offsets into I/O TLB (Function 2 and 3 on Ike) -*/ -#define ROPE0_CTL 0x200 /* "regbus pci0" */ -#define ROPE1_CTL 0x208 -#define ROPE2_CTL 0x210 -#define ROPE3_CTL 0x218 -#define ROPE4_CTL 0x220 -#define ROPE5_CTL 0x228 -#define ROPE6_CTL 0x230 -#define ROPE7_CTL 0x238 - -#define IOC_ROPE0_CFG 0x500 /* pluto only */ -#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */ - - - -#define HF_ENABLE 0x40 - - -#define IOC_IBASE 0x300 /* IO TLB */ -#define IOC_IMASK 0x308 -#define IOC_PCOM 0x310 -#define IOC_TCNFG 0x318 -#define IOC_PDIR_BASE 0x320 - - -/* -** IOC supports 4/8/16/64KB page sizes (see TCNFG register) -** It's safer (avoid memory corruption) to keep DMA page mappings -** equivalently sized to VM PAGE_SIZE. -** -** We really can't avoid generating a new mapping for each -** page since the Virtual Coherence Index has to be generated -** and updated for each page. -** -** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse. -*/ -#define IOVP_SIZE PAGE_SIZE -#define IOVP_SHIFT PAGE_SHIFT -#define IOVP_MASK PAGE_MASK - -#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ -#define SBA_PERF_MASK1 0x718 -#define SBA_PERF_MASK2 0x730 - - -/* -** Offsets into PCI Performance Counters (functions 12 and 13) -** Controlled by PERF registers in function 2 & 3 respectively. -*/ -#define SBA_PERF_CNT1 0x200 -#define SBA_PERF_CNT2 0x208 -#define SBA_PERF_CNT3 0x210 - static struct sba_device *sba_list; static unsigned long ioc_needs_fdc = 0; @@ -638,7 +543,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */ - pa |= 0x8000000000000000ULL; /* set "valid" bit */ + pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */ /* diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h index 413dfcca15c..2e3de0ae04d 100644 --- a/include/asm-parisc/ropes.h +++ b/include/asm-parisc/ropes.h @@ -101,7 +101,102 @@ static inline int IS_PLUTO(struct parisc_device *d) { return d->id.hversion == PLUTO_MCKINLEY_PORT; } -#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL +#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */ +#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */ +#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2) + +#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL + +#define SBA_AGPGART_COOKIE 0x0000badbadc0ffeeULL + +#define SBA_FUNC_ID 0x0000 /* function id */ +#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ + +#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ + +#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE) +#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE) +/* Ike's IOC's occupy functions 2 and 3 */ +#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE) + +#define IOC_CTRL 0x8 /* IOC_CTRL offset */ +#define IOC_CTRL_TC (1 << 0) /* TOC Enable */ +#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */ +#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */ +#define IOC_CTRL_RM (1 << 8) /* Real Mode */ +#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */ +#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */ +#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */ + +/* +** Offsets into MBIB (Function 0 on Ike and hopefully Astro) +** Firmware programs this stuff. Don't touch it. +*/ +#define LMMIO_DIRECT0_BASE 0x300 +#define LMMIO_DIRECT0_MASK 0x308 +#define LMMIO_DIRECT0_ROUTE 0x310 + +#define LMMIO_DIST_BASE 0x360 +#define LMMIO_DIST_MASK 0x368 +#define LMMIO_DIST_ROUTE 0x370 + +#define IOS_DIST_BASE 0x390 +#define IOS_DIST_MASK 0x398 +#define IOS_DIST_ROUTE 0x3A0 + +#define IOS_DIRECT_BASE 0x3C0 +#define IOS_DIRECT_MASK 0x3C8 +#define IOS_DIRECT_ROUTE 0x3D0 + +/* +** Offsets into I/O TLB (Function 2 and 3 on Ike) +*/ +#define ROPE0_CTL 0x200 /* "regbus pci0" */ +#define ROPE1_CTL 0x208 +#define ROPE2_CTL 0x210 +#define ROPE3_CTL 0x218 +#define ROPE4_CTL 0x220 +#define ROPE5_CTL 0x228 +#define ROPE6_CTL 0x230 +#define ROPE7_CTL 0x238 + +#define IOC_ROPE0_CFG 0x500 /* pluto only */ +#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */ + +#define HF_ENABLE 0x40 + +#define IOC_IBASE 0x300 /* IO TLB */ +#define IOC_IMASK 0x308 +#define IOC_PCOM 0x310 +#define IOC_TCNFG 0x318 +#define IOC_PDIR_BASE 0x320 + +/* +** IOC supports 4/8/16/64KB page sizes (see TCNFG register) +** It's safer (avoid memory corruption) to keep DMA page mappings +** equivalently sized to VM PAGE_SIZE. +** +** We really can't avoid generating a new mapping for each +** page since the Virtual Coherence Index has to be generated +** and updated for each page. +** +** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse. +*/ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ +#define SBA_PERF_MASK1 0x718 +#define SBA_PERF_MASK2 0x730 + +/* +** Offsets into PCI Performance Counters (functions 12 and 13) +** Controlled by PERF registers in function 2 & 3 respectively. +*/ +#define SBA_PERF_CNT1 0x200 +#define SBA_PERF_CNT2 0x208 +#define SBA_PERF_CNT3 0x210 /* ** lba_device: Per instance Elroy data structure @@ -147,4 +242,69 @@ static inline int IS_QUICKSILVER(struct parisc_device *d) { extern void *iosapic_register(unsigned long hpa); extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev); +#define LBA_FUNC_ID 0x0000 /* function id */ +#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ +#define LBA_CAPABLE 0x0030 /* capabilities register */ + +#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ +#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ + +#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ +#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ +#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ + +#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ +#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ +#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ +#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ + +#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ + +#define LBA_STAT_CTL 0x0108 /* Status & Control */ +#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */ +#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */ +#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */ +#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ + +#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ +#define LBA_LMMIO_MASK 0x0208 + +#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ +#define LBA_GMMIO_MASK 0x0218 + +#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ +#define LBA_WLMMIO_MASK 0x0228 + +#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ +#define LBA_WGMMIO_MASK 0x0238 + +#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ +#define LBA_IOS_MASK 0x0248 + +#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ +#define LBA_ELMMIO_MASK 0x0258 + +#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ +#define LBA_EIOS_MASK 0x0268 + +#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */ +#define LBA_DMA_CTL 0x0278 /* firmware sets this */ + +#define LBA_IBASE 0x0300 /* SBA DMA support */ +#define LBA_IMASK 0x0308 + +/* FIXME: ignore DMA Hint stuff until we can measure performance */ +#define LBA_HINT_CFG 0x0310 +#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ + +#define LBA_BUS_MODE 0x0620 + +/* ERROR regs are needed for config cycle kluges */ +#define LBA_ERROR_CONFIG 0x0680 +#define LBA_SMART_MODE 0x20 +#define LBA_ERROR_STATUS 0x0688 +#define LBA_ROPE_CTL 0x06A0 + +#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ + #endif /*_ASM_PARISC_ROPES_H_*/ -- GitLab From 08a6436816f7a16113c73be767ee8d50440e494e Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:33:40 -0400 Subject: [PATCH 0449/1619] [PARISC] Add support for Quicksilver AGPGART Signed-off-by: Kyle McMartin --- drivers/char/agp/Kconfig | 10 +- drivers/char/agp/Makefile | 1 + drivers/char/agp/parisc-agp.c | 416 ++++++++++++++++++++++++++++++++++ drivers/parisc/sba_iommu.c | 35 ++- include/asm-parisc/agp.h | 25 ++ include/asm-parisc/ropes.h | 12 + 6 files changed, 487 insertions(+), 12 deletions(-) create mode 100644 drivers/char/agp/parisc-agp.c create mode 100644 include/asm-parisc/agp.h diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 22f8cf218cc..c603bf29158 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -1,6 +1,6 @@ config AGP tristate "/dev/agpgart (AGP Support)" - depends on ALPHA || IA64 || PPC || X86 + depends on ALPHA || IA64 || PARISC || PPC || X86 depends on PCI ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -122,6 +122,14 @@ config AGP_HP_ZX1 This option gives you AGP GART support for the HP ZX1 chipset for IA64 processors. +config AGP_PARISC + tristate "HP Quicksilver AGP support" + depends on AGP && PARISC && 64BIT + help + This option gives you AGP GART support for the HP Quicksilver + AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000 + workstation...) + config AGP_ALPHA_CORE tristate "Alpha AGP support" depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL) diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index d33a22f2fa0..3e581603d0a 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_AGP_AMD64) += amd64-agp.o obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o +obj-$(CONFIG_AGP_PARISC) += parisc-agp.o obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c new file mode 100644 index 00000000000..17c50b0f83f --- /dev/null +++ b/drivers/char/agp/parisc-agp.c @@ -0,0 +1,416 @@ +/* + * HP Quicksilver AGP GART routines + * + * Copyright (c) 2006, Kyle McMartin + * + * Based on drivers/char/agpgart/hp-agp.c which is + * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas + * + * 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 "agp.h" + +#define DRVNAME "quicksilver" +#define DRVPFX DRVNAME ": " + +#ifndef log2 +#define log2(x) ffz(~(x)) +#endif + +#define AGP8X_MODE_BIT 3 +#define AGP8X_MODE (1 << AGP8X_MODE_BIT) + +static struct _parisc_agp_info { + void __iomem *ioc_regs; + void __iomem *lba_regs; + + int lba_cap_offset; + + u64 *gatt; + u64 gatt_entries; + + u64 gart_base; + u64 gart_size; + + int io_page_size; + int io_pages_per_kpage; +} parisc_agp_info; + +static struct gatt_mask parisc_agp_masks[] = +{ + { + .mask = SBA_PDIR_VALID_BIT, + .type = 0 + } +}; + +static struct aper_size_info_fixed parisc_agp_sizes[] = +{ + {0, 0, 0}, /* filled in by parisc_agp_fetch_size() */ +}; + +static int +parisc_agp_fetch_size(void) +{ + int size; + + size = parisc_agp_info.gart_size / MB(1); + parisc_agp_sizes[0].size = size; + agp_bridge->current_size = (void *) &parisc_agp_sizes[0]; + + return size; +} + +static int +parisc_agp_configure(void) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + + agp_bridge->gart_bus_addr = info->gart_base; + agp_bridge->capndx = info->lba_cap_offset; + agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS); + + return 0; +} + +static void +parisc_agp_tlbflush(struct agp_memory *mem) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + + writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM); + readq(info->ioc_regs+IOC_PCOM); /* flush */ +} + +static int +parisc_agp_create_gatt_table(struct agp_bridge_data *bridge) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int i; + + for (i = 0; i < info->gatt_entries; i++) { + info->gatt[i] = (unsigned long)agp_bridge->scratch_page; + } + + return 0; +} + +static int +parisc_agp_free_gatt_table(struct agp_bridge_data *bridge) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + + info->gatt[0] = SBA_AGPGART_COOKIE; + + return 0; +} + +static int +parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int i, k; + off_t j, io_pg_start; + int io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = info->io_pages_per_kpage * pg_start; + io_pg_count = info->io_pages_per_kpage * mem->page_count; + if ((io_pg_start + io_pg_count) > info->gatt_entries) { + return -EINVAL; + } + + j = io_pg_start; + while (j < (io_pg_start + io_pg_count)) { + if (info->gatt[j]) + return -EBUSY; + j++; + } + + if (mem->is_flushed == FALSE) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = io_pg_start; i < mem->page_count; i++) { + unsigned long paddr; + + paddr = mem->memory[i]; + for (k = 0; + k < info->io_pages_per_kpage; + k++, j++, paddr += info->io_page_size) { + info->gatt[j] = + agp_bridge->driver->mask_memory(agp_bridge, + paddr, type); + } + } + + agp_bridge->driver->tlb_flush(mem); + + return 0; +} + +static int +parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int i, io_pg_start, io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = info->io_pages_per_kpage * pg_start; + io_pg_count = info->io_pages_per_kpage * mem->page_count; + for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) { + info->gatt[i] = agp_bridge->scratch_page; + } + + agp_bridge->driver->tlb_flush(mem); + return 0; +} + +static unsigned long +parisc_agp_mask_memory(struct agp_bridge_data *bridge, + unsigned long addr, int type) +{ + return SBA_PDIR_VALID_BIT | addr; +} + +static void +parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + u32 command; + + command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS); + + command = agp_collect_device_status(bridge, mode, command); + command |= 0x00000100; + + writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND); + + agp_device_command(command, (mode & AGP8X_MODE) != 0); +} + +struct agp_bridge_driver parisc_agp_driver = { + .owner = THIS_MODULE, + .size_type = FIXED_APER_SIZE, + .configure = parisc_agp_configure, + .fetch_size = parisc_agp_fetch_size, + .tlb_flush = parisc_agp_tlbflush, + .mask_memory = parisc_agp_mask_memory, + .masks = parisc_agp_masks, + .agp_enable = parisc_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = parisc_agp_create_gatt_table, + .free_gatt_table = parisc_agp_free_gatt_table, + .insert_memory = parisc_agp_insert_memory, + .remove_memory = parisc_agp_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .cant_use_aperture = 1, +}; + +static int __init +agp_ioc_init(void __iomem *ioc_regs) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + u64 *iova_base, *io_pdir, io_tlb_ps; + int io_tlb_shift; + + printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n"); + + info->ioc_regs = ioc_regs; + + io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG); + switch (io_tlb_ps) { + case 0: io_tlb_shift = 12; break; + case 1: io_tlb_shift = 13; break; + case 2: io_tlb_shift = 14; break; + case 3: io_tlb_shift = 16; break; + default: + printk(KERN_ERR DRVPFX "Invalid IOTLB page size " + "configuration 0x%llx\n", io_tlb_ps); + info->gatt = NULL; + info->gatt_entries = 0; + return -ENODEV; + } + info->io_page_size = 1 << io_tlb_shift; + info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size; + + iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1; + info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE; + + info->gart_size = PLUTO_GART_SIZE; + info->gatt_entries = info->gart_size / info->io_page_size; + + io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE)); + info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT]; + + if (info->gatt[0] != SBA_AGPGART_COOKIE) { + info->gatt = NULL; + info->gatt_entries = 0; + printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; " + "GART disabled\n"); + return -ENODEV; + } + + return 0; +} + +static int +lba_find_capability(int cap) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + u16 status; + u8 pos, id; + int ttl = 48; + + status = readw(info->lba_regs + PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + pos = readb(info->lba_regs + PCI_CAPABILITY_LIST); + while (ttl-- && pos >= 0x40) { + pos &= ~3; + id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT); + } + return 0; +} + +static int __init +agp_lba_init(void __iomem *lba_hpa) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int cap; + + info->lba_regs = lba_hpa; + info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP); + + cap = readl(lba_hpa + info->lba_cap_offset) & 0xff; + if (cap != PCI_CAP_ID_AGP) { + printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n", + cap, info->lba_cap_offset); + return -ENODEV; + } + + return 0; +} + +static int __init +parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa) +{ + struct pci_dev *fake_bridge_dev = NULL; + struct agp_bridge_data *bridge; + int error = 0; + + fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL); + if (!fake_bridge_dev) { + error = -ENOMEM; + goto fail; + } + + error = agp_ioc_init(ioc_hpa); + if (error) + goto fail; + + error = agp_lba_init(lba_hpa); + if (error) + goto fail; + + bridge = agp_alloc_bridge(); + if (!bridge) { + error = -ENOMEM; + goto fail; + } + bridge->driver = &parisc_agp_driver; + + fake_bridge_dev->vendor = PCI_VENDOR_ID_HP; + fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA; + bridge->dev = fake_bridge_dev; + + error = agp_add_bridge(bridge); + +fail: + return error; +} + +static struct device *next_device(struct klist_iter *i) { + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + +static int +parisc_agp_init(void) +{ + extern struct sba_device *sba_list; + + int err = -1; + struct parisc_device *sba = NULL, *lba = NULL; + struct lba_device *lbadev = NULL; + struct device *dev = NULL; + struct klist_iter i; + + if (!sba_list) + goto out; + + /* Find our parent Pluto */ + sba = sba_list->dev; + if (!IS_PLUTO(sba)) { + printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n"); + goto out; + } + + /* Now search our Pluto for our precious AGP device... */ + klist_iter_init(&sba->dev.klist_children, &i); + while ((dev = next_device(&i))) { + struct parisc_device *padev = to_parisc_device(dev); + if (IS_QUICKSILVER(padev)) + lba = padev; + } + klist_iter_exit(&i); + + if (!lba) { + printk(KERN_INFO DRVPFX "No AGP devices found.\n"); + goto out; + } + + lbadev = parisc_get_drvdata(lba); + + /* w00t, let's go find our cookies... */ + parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr); + + return 0; + +out: + return err; +} + +module_init(parisc_agp_init); + +MODULE_AUTHOR("Kyle McMartin "); +MODULE_LICENSE("GPL"); diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index eed99bdcfb6..294c1117098 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -89,7 +89,8 @@ #define DEFAULT_DMA_HINT_REG 0 -static struct sba_device *sba_list; +struct sba_device *sba_list; +EXPORT_SYMBOL_GPL(sba_list); static unsigned long ioc_needs_fdc = 0; @@ -102,8 +103,14 @@ static unsigned long piranha_bad_128k = 0; /* Looks nice and keeps the compiler happy */ #define SBA_DEV(d) ((struct sba_device *) (d)) +#ifdef CONFIG_AGP_PARISC +#define SBA_AGP_SUPPORT +#endif /*CONFIG_AGP_PARISC*/ + #ifdef SBA_AGP_SUPPORT -static int reserve_sba_gart = 1; +static int sba_reserve_agpgart = 1; +module_param(sba_reserve_agpgart, int, 1); +MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART"); #endif #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) @@ -1300,6 +1307,10 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM); #ifdef SBA_AGP_SUPPORT +{ + struct klist_iter i; + struct device *dev = NULL; + /* ** If an AGP device is present, only use half of the IOV space ** for PCI DMA. Unfortunately we can't know ahead of time @@ -1308,20 +1319,22 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ** We program the next pdir index after we stop w/ a key for ** the GART code to handshake on. */ - device=NULL; - for (lba = sba->child; lba; lba = lba->sibling) { + klist_iter_init(&sba->dev.klist_children, &i); + while (dev = next_device(&i)) { + struct parisc_device *lba = to_parisc_device(dev); if (IS_QUICKSILVER(lba)) - break; + agp_found = 1; } + klist_iter_exit(&sba->dev.klist_children, &i); - if (lba) { - DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__); + if (agp_found && sba_reserve_agpgart) { + printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n", + __FUNCTION__, (iova_space_size/2) >> 20); ioc->pdir_size /= 2; - ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE; - } else { - DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__); + ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE; } -#endif /* 0 */ +} +#endif /*SBA_AGP_SUPPORT*/ } diff --git a/include/asm-parisc/agp.h b/include/asm-parisc/agp.h new file mode 100644 index 00000000000..9f61d4eb6c0 --- /dev/null +++ b/include/asm-parisc/agp.h @@ -0,0 +1,25 @@ +#ifndef _ASM_PARISC_AGP_H +#define _ASM_PARISC_AGP_H + +/* + * PARISC specific AGP definitions. + * Copyright (c) 2006 Kyle McMartin + * + */ + +#define map_page_into_agp(page) /* nothing */ +#define unmap_page_from_agp(page) /* nothing */ +#define flush_agp_mappings() /* nothing */ +#define flush_agp_cache() mb() + +/* Convert a physical address to an address suitable for the GART. */ +#define phys_to_gart(x) (x) +#define gart_to_phys(x) (x) + +/* GATT allocation. Returns/accepts GATT kernel virtual address. */ +#define alloc_gatt_pages(order) \ + ((char *)__get_free_pages(GFP_KERNEL, (order))) +#define free_gatt_pages(table, order) \ + free_pages((unsigned long)(table), (order)) + +#endif /* _ASM_PARISC_AGP_H */ diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h index 2e3de0ae04d..5542dd00472 100644 --- a/include/asm-parisc/ropes.h +++ b/include/asm-parisc/ropes.h @@ -1,6 +1,8 @@ #ifndef _ASM_PARISC_ROPES_H_ #define _ASM_PARISC_ROPES_H_ +#include + #ifdef CONFIG_64BIT /* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ #define ZX1_SUPPORT @@ -231,6 +233,16 @@ static inline int IS_QUICKSILVER(struct parisc_device *d) { return (d->id.hversion == QUICKSILVER_HVERS); } +static inline int agp_mode_mercury(void __iomem *hpa) { + u64 bus_mode; + + bus_mode = readl(hpa + 0x0620); + if (bus_mode & 1) + return 1; + + return 0; +} + /* ** I/O SAPIC init function ** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC. -- GitLab From 01232e932988fcf6ad87be49f69e633dd652a46d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 19 Sep 2006 16:37:01 -0600 Subject: [PATCH 0450/1619] [PARISC] Fix iounmap compile warning iounmap's argument needs to be both const and volatile, otherwise we'll get warnings that we're discarding pointer qualifiers Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/mm/ioremap.c | 2 +- include/asm-parisc/io.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index 27384567a1d..47a1d2ac941 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c @@ -188,7 +188,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l } EXPORT_SYMBOL(__ioremap); -void iounmap(void __iomem *addr) +void iounmap(const volatile void __iomem *addr) { if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h index b9eb245b887..c1963ce19dd 100644 --- a/include/asm-parisc/io.h +++ b/include/asm-parisc/io.h @@ -134,7 +134,7 @@ extern inline void __iomem * ioremap(unsigned long offset, unsigned long size) } #define ioremap_nocache(off, sz) ioremap((off), (sz)) -extern void iounmap(void __iomem *addr); +extern void iounmap(const volatile void __iomem *addr); static inline unsigned char __raw_readb(const volatile void __iomem *addr) { -- GitLab From 32f468139209459c3293a0895cf5b8e66ccc30a5 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 19 Sep 2006 16:44:38 -0600 Subject: [PATCH 0451/1619] [PARISC] Fix HPUX compat compile with current GCC GCC no longer allows a cast as lvalue; fix the same way fs/readdir.c was Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/hpux/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 6e79dbf3f6b..2d58b92b57e 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -96,7 +96,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, put_user(namlen, &dirent->d_namlen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = (void __user *)dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; -- GitLab From d207ac0f7c9736782bfa51cff2109b74d26c3622 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 19 Sep 2006 19:32:42 -0600 Subject: [PATCH 0452/1619] [PARISC] Fix CONFIG_DEBUG_SPINLOCK Joel Soete points out that we refer to pa_tlb_lock but only define it if CONFIG_SMP which breaks a uniprocessor build with CONFIG_DEBUG_SPINLOCK enabled. No module refers to pa_tlb_lock, so we can delete the export. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 7e8d697aef3..e91c2be7236 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -35,15 +35,12 @@ int icache_stride __read_mostly; EXPORT_SYMBOL(dcache_stride); -#if defined(CONFIG_SMP) /* On some machines (e.g. ones with the Merced bus), there can be * only a single PxTLB broadcast at a time; this must be guaranteed * by software. We put a spinlock around all TLB flushes to * ensure this. */ DEFINE_SPINLOCK(pa_tlb_lock); -EXPORT_SYMBOL(pa_tlb_lock); -#endif struct pdc_cache_info cache_info __read_mostly; #ifndef CONFIG_PA20 -- GitLab From f312094556619aed849862089938c14aa6a5b84b Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 19 Sep 2006 19:37:09 -0600 Subject: [PATCH 0453/1619] [PARISC] Define pci_get_legacy_ide_irq We can compile at least one IDE driver that refers to this. We can't use the asm-generic file because we have our own definitions of pcibios_resource_to_bus etc. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/pci.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h index 8b631f47eb2..7b8ad118d2f 100644 --- a/include/asm-parisc/pci.h +++ b/include/asm-parisc/pci.h @@ -293,4 +293,9 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) /* We don't need to penalize isa irq's */ } +static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) +{ + return channel ? 15 : 14; +} + #endif /* __ASM_PARISC_PCI_H */ -- GitLab From 99b6e9be71b9ad2c50c0d160b5af18848fee466d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 20 Sep 2006 20:36:42 -0600 Subject: [PATCH 0454/1619] [PARISC] Make DMA routines more stubby We were pretending to use the GENERIC_ISA_DMA routines, but never selected that symbol. Since ISA DMA is known to not work right now, just remove the attempts to acquire the dma_spin_lock to fix compile warnings. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/dma.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h index 9979c3cb374..da2cf373e31 100644 --- a/include/asm-parisc/dma.h +++ b/include/asm-parisc/dma.h @@ -72,18 +72,13 @@ #define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ #define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG) -extern spinlock_t dma_spin_lock; - static __inline__ unsigned long claim_dma_lock(void) { - unsigned long flags; - spin_lock_irqsave(&dma_spin_lock, flags); - return flags; + return 0; } static __inline__ void release_dma_lock(unsigned long flags) { - spin_unlock_irqrestore(&dma_spin_lock, flags); } -- GitLab From 8d0b7d1055bedca784b143b0af9b37bd971b7cd2 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 20 Sep 2006 21:44:09 -0600 Subject: [PATCH 0455/1619] [PARISC] Export clear_user_page to modules Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index e91c2be7236..0be51e92a2f 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -372,8 +372,7 @@ void parisc_setup_cache_timing(void) extern void purge_kernel_dcache_page(unsigned long); extern void clear_user_page_asm(void *page, unsigned long vaddr); -void -clear_user_page(void *page, unsigned long vaddr, struct page *pg) +void clear_user_page(void *page, unsigned long vaddr, struct page *pg) { purge_kernel_dcache_page((unsigned long)page); purge_tlb_start(); @@ -381,6 +380,7 @@ clear_user_page(void *page, unsigned long vaddr, struct page *pg) purge_tlb_end(); clear_user_page_asm(page, vaddr); } +EXPORT_SYMBOL(clear_user_page); void flush_kernel_dcache_page_addr(void *addr) { -- GitLab From dc02747da7897cb89b62bb08aeb06fa0bb1e7319 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sun, 24 Sep 2006 13:35:50 -0600 Subject: [PATCH 0456/1619] [PARISC] Fix fs/binfmt_som.c Fix compilation (missing include of a.out.h) Fix security hole (need to call unshare_files) Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- fs/binfmt_som.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index 32b5d625ce9..5bcdaaf4eae 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -194,6 +195,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) unsigned long som_entry; struct som_hdr *som_ex; struct som_exec_auxhdr *hpuxhdr; + struct files_struct *files; /* Get the exec-header */ som_ex = (struct som_hdr *) bprm->buf; @@ -208,15 +210,27 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) size = som_ex->aux_header_size; if (size > SOM_PAGESIZE) goto out; - hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL); + hpuxhdr = kmalloc(size, GFP_KERNEL); if (!hpuxhdr) goto out; retval = kernel_read(bprm->file, som_ex->aux_header_location, (char *) hpuxhdr, size); + if (retval != size) { + if (retval >= 0) + retval = -EIO; + goto out_free; + } + + files = current->files; /* Refcounted so ok */ + retval = unshare_files(); if (retval < 0) goto out_free; -#error "Fix security hole before enabling me" + if (files == current->files) { + put_files_struct(files); + files = NULL; + } + retval = get_unused_fd(); if (retval < 0) goto out_free; -- GitLab From 22fced881122f7fc6f5f259dca03ac6d5c601404 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 30 Sep 2006 15:45:58 +0200 Subject: [PATCH 0457/1619] [PARISC] Honour "panic_on_oops" sysctl Signed-off-by: Helge Deller Signed-off-by: Kyle McMartin --- arch/parisc/kernel/traps.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 77b28cb8aca..65cd6ca32fe 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -245,6 +246,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) current->comm, current->pid, str, err); show_regs(regs); + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + ssleep(5); + panic("Fatal exception"); + } + /* Wot's wrong wif bein' racy? */ if (current->thread.flags & PARISC_KERNEL_DEATH) { printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); -- GitLab From 5f024a251f0b3b179bbc8fc62f3a650e49359db5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 1 Oct 2006 16:17:13 -0400 Subject: [PATCH 0458/1619] [PARISC] Kill wall_jiffies use wall_jiffies and jiffies are now equal, so this is a noop... Signed-off-by: Andrew Morton Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 9d642d820fe..b3496b592a2 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -215,9 +215,6 @@ static inline unsigned long gettimeoffset (void) /* FIXME: Can we improve the precision? Not with PAGE0. */ usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; - - /* add in "lost" jiffies */ - usec += cpt * (jiffies - wall_jiffies); return usec; #else return 0; -- GitLab From b119f13f56a7a47915278ab5eb3c666ca5dbb067 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Wed, 4 Oct 2006 02:15:19 -0700 Subject: [PATCH 0459/1619] [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(-) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index f7a52e19b4b..9e8bcb5fa99 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 d9e2b3f36c3..636094c29b1 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 02e4b697206..a4555fe3754 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 */ -- GitLab From 4e776b1d5e976d6bb2aafb177dde7d5f8d2bf37f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 4 Oct 2006 02:15:20 -0700 Subject: [PATCH 0460/1619] [PATCH] hdrcheck permission fix Don't require that scripts/hdrcheck.sh be executable - shit happens... Cc: Sam Ravnborg Acked-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/Makefile.headersinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst index cac8f21a339..6a026f69b56 100644 --- a/scripts/Makefile.headersinst +++ b/scripts/Makefile.headersinst @@ -97,7 +97,7 @@ quiet_cmd_unifdef = UNIFDEF $(patsubst $(INSTALL_HDR_PATH)/%,%,$@) | $(HDRSED) > $@ || : quiet_cmd_check = CHECK $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/.check.%,$(_dst)/%,$@) - cmd_check = $(srctree)/scripts/hdrcheck.sh \ + cmd_check = $(CONFIG_SHELL) $(srctree)/scripts/hdrcheck.sh \ $(INSTALL_HDR_PATH)/include $(subst /.check.,/,$@) $@ quiet_cmd_remove = REMOVE $(_dst)/$@ -- GitLab From e95be9a5326f0f6d314a7aa04a3c0c0e67fa976b Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 4 Oct 2006 02:15:21 -0700 Subject: [PATCH 0461/1619] [PATCH] docs: small kbuild cleanup While reading this I noticed that the contents of this document list section "3.8 Command line dependency" but it doesn't exist in the document. Signed-off-by: Daniel Walker Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kbuild/kconfig-language.txt | 2 +- Documentation/kbuild/makefiles.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt index 7f34778dd23..125093c3ef7 100644 --- a/Documentation/kbuild/kconfig-language.txt +++ b/Documentation/kbuild/kconfig-language.txt @@ -1,7 +1,7 @@ Introduction ------------ -The configuration database is collection of configuration options +The configuration database is a collection of configuration options organized in a tree structure: +- Code maturity level options diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index e2cbd59cf2d..50f4eddf899 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -390,7 +390,7 @@ more details, with real examples. The kernel may be built with several different versions of $(CC), each supporting a unique set of features and options. kbuild provide basic support to check for valid options for $(CC). - $(CC) is useally the gcc compiler, but other alternatives are + $(CC) is usually the gcc compiler, but other alternatives are available. as-option -- GitLab From b2abacf3a2699a8020829c85c16f358ba85cecaf Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Wed, 4 Oct 2006 02:15:22 -0700 Subject: [PATCH 0462/1619] [PATCH] mm: fix in kerneldoc Fixes an kerneldoc error. Signed-off-by: Henrik Kretzschmar Cc: "Randy.Dunlap" Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/filemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index ec469235985..f789500406f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1139,11 +1139,11 @@ success: } /** - * __generic_file_aio_read - generic filesystem read routine + * generic_file_aio_read - generic filesystem read routine * @iocb: kernel I/O control block * @iov: io vector request * @nr_segs: number of segments in the iovec - * @ppos: current file position + * @pos: current file position * * This is the "read()" routine for all filesystems * that can use the page cache directly. -- GitLab From e80ee884ae0e3794ef2b65a18a767d502ad712ee Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 4 Oct 2006 02:15:23 -0700 Subject: [PATCH 0463/1619] [PATCH] mm: micro optimise zone_watermark_ok Having min be a signed quantity means gcc can't turn high latency divides into shifts. There happen to be two such divides for GFP_ATOMIC (ie. networking, ie. important) allocations, one of which depends on the other. Fixing this makes code smaller as a bonus. Shame on somebody (probably me). Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4f59d90b81e..b5468de4986 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -900,7 +900,8 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark, int classzone_idx, int alloc_flags) { /* free_pages my go negative - that's OK */ - long min = mark, free_pages = z->free_pages - (1 << order) + 1; + unsigned long min = mark; + long free_pages = z->free_pages - (1 << order) + 1; int o; if (alloc_flags & ALLOC_HIGH) -- GitLab From fe1668ae5bf0145014c71797febd9ad5670d5d05 Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Wed, 4 Oct 2006 02:15:24 -0700 Subject: [PATCH 0464/1619] [PATCH] enforce proper tlb flush in unmap_hugepage_range Spotted by Hugh that hugetlb page is free'ed back to global pool before performing any TLB flush in unmap_hugepage_range(). This potentially allow threads to abuse free-alloc race condition. The generic tlb gather code is unsuitable to use by hugetlb, I just open coded a page gathering list and delayed put_page until tlb flush is performed. Cc: Hugh Dickins Signed-off-by: Ken Chen Acked-by: William Irwin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 7c7d03dbf73..1d709ff528e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -364,6 +364,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, pte_t *ptep; pte_t pte; struct page *page; + struct page *tmp; + LIST_HEAD(page_list); WARN_ON(!is_vm_hugetlb_page(vma)); BUG_ON(start & ~HPAGE_MASK); @@ -384,12 +386,16 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, continue; page = pte_page(pte); - put_page(page); + list_add(&page->lru, &page_list); add_mm_counter(mm, file_rss, (int) -(HPAGE_SIZE / PAGE_SIZE)); } spin_unlock(&mm->page_table_lock); flush_tlb_range(vma, start, end); + list_for_each_entry_safe(page, tmp, &page_list, lru) { + list_del(&page->lru); + put_page(page); + } } static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, -- GitLab From 88ca3b94e82e763ef90c8e57cacd51a3c143ea62 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 4 Oct 2006 02:15:25 -0700 Subject: [PATCH 0465/1619] [PATCH] page_alloc: fix kernel-doc and func. declaration Fix kernel-doc and function declaration (missing "void") in mm/page_alloc.c. Add mm/page_alloc.c to kernel-api.tmpl in DocBook. mm/page_alloc.c:2589:38: warning: non-ANSI function declaration of function 'remove_all_active_ranges' Signed-off-by: Randy Dunlap Acked-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/DocBook/kernel-api.tmpl | 1 + mm/page_alloc.c | 50 +++++++++++++-------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 49c745720f4..2b5ac604948 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -158,6 +158,7 @@ X!Ilib/string.c !Emm/filemap.c !Emm/memory.c !Emm/vmalloc.c +!Imm/page_alloc.c !Emm/mempool.c !Emm/page-writeback.c !Emm/truncate.c diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b5468de4986..a8c003e7b3d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2051,8 +2051,8 @@ int __init early_pfn_to_nid(unsigned long pfn) /** * 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 + * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed. + * @max_low_pfn: The highest PFN that will 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 @@ -2082,11 +2082,11 @@ void __init free_bootmem_with_active_regions(int nid, /** * 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 + * @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. + * function may be used instead of calling memory_present() manually. */ void __init sparse_memory_present_with_active_regions(int nid) { @@ -2156,14 +2156,14 @@ static void __init account_node_boundary(unsigned int nid, /** * 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 + * @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 + * PFNs will be 0. */ void __init get_pfn_range_for_nid(unsigned int nid, unsigned long *start_pfn, unsigned long *end_pfn) @@ -2216,7 +2216,7 @@ unsigned long __init zone_spanned_pages_in_node(int nid, /* * 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 + * 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, @@ -2269,7 +2269,7 @@ unsigned long __init __absent_pages_in_range(int nid, * @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 + * 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) @@ -2583,11 +2583,12 @@ void __init shrink_active_range(unsigned int nid, unsigned long old_end_pfn, /** * 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() +void __init remove_all_active_ranges(void) { memset(early_node_map, 0, sizeof(early_node_map)); nr_nodemap_entries = 0; @@ -2637,7 +2638,7 @@ unsigned long __init find_min_pfn_for_node(unsigned long nid) * find_min_pfn_with_active_regions - Find the minimum PFN registered * * It returns the minimum PFN based on information provided via - * add_active_range() + * add_active_range(). */ unsigned long __init find_min_pfn_with_active_regions(void) { @@ -2648,7 +2649,7 @@ unsigned long __init find_min_pfn_with_active_regions(void) * find_max_pfn_with_active_regions - Find the maximum PFN registered * * It returns the maximum PFN based on information provided via - * add_active_range() + * add_active_range(). */ unsigned long __init find_max_pfn_with_active_regions(void) { @@ -2663,10 +2664,7 @@ unsigned long __init find_max_pfn_with_active_regions(void) /** * 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 + * @max_zone_pfn: an array of max PFNs for each zone * * 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 @@ -2724,14 +2722,15 @@ 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 + * set_dma_reserve - set the specified number of pages reserved in the first zone + * @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 + * function may optionally be used to account for unfreeable pages in the + * first zone (e.g., ZONE_DMA). The effect will be lower watermarks and + * smaller per-cpu batchsize. */ void __init set_dma_reserve(unsigned long new_dma_reserve) { @@ -2844,10 +2843,11 @@ static void setup_per_zone_lowmem_reserve(void) calculate_totalreserve_pages(); } -/* - * setup_per_zone_pages_min - called when min_free_kbytes changes. Ensures - * that the pages_{min,low,high} values for each zone are set correctly - * with respect to min_free_kbytes. +/** + * setup_per_zone_pages_min - called when min_free_kbytes changes. + * + * Ensures that the pages_{min,low,high} values for each zone are set correctly + * with respect to min_free_kbytes. */ void setup_per_zone_pages_min(void) { -- GitLab From 1d2c8eea698514cfaa53fc991b960791d09508e1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 4 Oct 2006 02:15:25 -0700 Subject: [PATCH 0466/1619] [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(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index 70be57d8ae0..c4947b8a2c0 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 3dbd6f4e747..c23b99250df 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 e14fa84ef39..ace2aea69f1 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 c448c7f6fde..3c23760c582 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; -- GitLab From b3218a79aa3d58b975b066c300153a8520f7051c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 4 Oct 2006 02:15:27 -0700 Subject: [PATCH 0467/1619] [PATCH] char: kill unneeded memsets char, another tmp_buf cleanup No need to allocate one page as a side buffer. It's no more used. Clean this (de)allocs of this useless memory pages in char subtree. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/amiserial.c | 30 +----------------------------- drivers/char/cyclades.c | 28 +--------------------------- drivers/char/epca.c | 17 ++--------------- drivers/char/epca.h | 1 - drivers/char/generic_serial.c | 19 +------------------ drivers/char/riscom8.c | 10 +--------- drivers/char/serial167.c | 20 +------------------- 7 files changed, 7 insertions(+), 118 deletions(-) diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index d0e92ed0a36..486f97c3f4e 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -112,17 +112,6 @@ static struct serial_state rs_table[1]; #define NR_PORTS ARRAY_SIZE(rs_table) -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; - #include #define serial_isroot() (capable(CAP_SYS_ADMIN)) @@ -912,7 +901,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count if (serial_paranoia_check(info, tty->name, "rs_write")) return 0; - if (!info->xmit.buf || !tmp_buf) + if (!info->xmit.buf) return 0; local_save_flags(flags); @@ -1778,7 +1767,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp) { struct async_struct *info; int retval, line; - unsigned long page; line = tty->index; if ((line < 0) || (line >= NR_PORTS)) { @@ -1798,17 +1786,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp) #endif info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - return -ENOMEM; - } - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - /* * If the port is the middle of closing, bail out now */ @@ -2090,11 +2067,6 @@ static __exit void rs_exit(void) kfree(info); } - if (tmp_buf) { - free_page((unsigned long) tmp_buf); - tmp_buf = NULL; - } - release_mem_region(CUSTOM_PHYSADDR+0x30, 4); } diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index f85b4eb1661..87b2fb51087 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -747,18 +747,6 @@ static struct cyclades_port cy_port[NR_PORTS]; static int cy_next_channel; /* next minor available */ -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. This buffer is - * allocated when the first cy_open occurs. - */ -static unsigned char *tmp_buf; - /* * This is used to look up the divisor speeds and the timeouts * We're normally limited to 15 distinct baud rates. The extra @@ -2466,7 +2454,6 @@ cy_open(struct tty_struct *tty, struct file * filp) { struct cyclades_port *info; int retval, line; - unsigned long page; line = tty->index; if ((line < 0) || (NR_PORTS <= line)){ @@ -2545,15 +2532,6 @@ cy_open(struct tty_struct *tty, struct file * filp) printk("cyc:cy_open (%d): incrementing count to %d\n", current->pid, info->count); #endif - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } /* * If the port is the middle of closing, bail out now @@ -2832,7 +2810,7 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count) return 0; } - if (!info->xmit_buf || !tmp_buf) + if (!info->xmit_buf) return 0; CY_LOCK(info, flags); @@ -5490,10 +5468,6 @@ cy_cleanup_module(void) #endif } } - if (tmp_buf) { - free_page((unsigned long) tmp_buf); - tmp_buf = NULL; - } } /* cy_cleanup_module */ module_init(cy_init); diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 3baa2ab8cbd..c3f95583a12 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1113,11 +1113,8 @@ static void __exit epca_module_exit(void) ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { /* Begin for each port */ - if (ch) { - if (ch->tty) - tty_hangup(ch->tty); - kfree(ch->tmp_buf); - } + if (ch && ch->tty) + tty_hangup(ch->tty); } /* End for each port */ } /* End for each card */ pci_unregister_driver (&epca_driver); @@ -1635,16 +1632,6 @@ static void post_fep_init(unsigned int crd) init_waitqueue_head(&ch->close_wait); spin_unlock_irqrestore(&epca_lock, flags); - - ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); - if (!ch->tmp_buf) { - printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i); - release_region((int)bd->port, 4); - while(i-- > 0) - kfree((ch--)->tmp_buf); - return; - } else - memset((void *)ch->tmp_buf,0,ch->txbufsize); } /* End for each port */ printk(KERN_INFO diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 456d6c8f94a..a297238cd3b 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -130,7 +130,6 @@ struct channel unsigned long c_oflag; unsigned char __iomem *txptr; unsigned char __iomem *rxptr; - unsigned char *tmp_buf; struct board_info *board; struct board_chan __iomem *brdchan; struct digi_struct digiext; diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 4711d9b3a59..87127e49c0d 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -33,8 +33,6 @@ #define DEBUG -static char * tmp_buf; - static int gs_debug; #ifdef DEBUG @@ -205,7 +203,7 @@ int gs_write(struct tty_struct * tty, if (!tty) return -EIO; port = tty->driver_data; - if (!port || !port->xmit_buf || !tmp_buf) + if (!port || !port->xmit_buf) return -EIO; local_save_flags(flags); @@ -837,24 +835,9 @@ void gs_set_termios (struct tty_struct * tty, int gs_init_port(struct gs_port *port) { unsigned long flags; - unsigned long page; func_enter (); - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */ - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - spin_unlock_irqrestore (&port->driver_lock, flags); - if (!tmp_buf) { - func_exit (); - return -ENOMEM; - } - } - if (port->flags & ASYNC_INITIALIZED) { func_exit (); return 0; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 214d850112f..b0ab3f28cc6 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -81,7 +81,6 @@ static struct riscom_board * IRQ_to_board[16]; static struct tty_driver *riscom_driver; -static unsigned char * tmp_buf; static unsigned long baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, @@ -1124,7 +1123,7 @@ static int rc_write(struct tty_struct * tty, bp = port_Board(port); - if (!tty || !port->xmit_buf || !tmp_buf) + if (!tty || !port->xmit_buf) return 0; save_flags(flags); @@ -1612,11 +1611,6 @@ static inline int rc_init_drivers(void) if (!riscom_driver) return -ENOMEM; - if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) { - printk(KERN_ERR "rc: Couldn't get free page.\n"); - put_tty_driver(riscom_driver); - return 1; - } memset(IRQ_to_board, 0, sizeof(IRQ_to_board)); riscom_driver->owner = THIS_MODULE; riscom_driver->name = "ttyL"; @@ -1629,7 +1623,6 @@ static inline int rc_init_drivers(void) riscom_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(riscom_driver, &riscom_ops); if ((error = tty_register_driver(riscom_driver))) { - free_page((unsigned long)tmp_buf); put_tty_driver(riscom_driver); printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, " "error = %d\n", @@ -1657,7 +1650,6 @@ static void rc_release_drivers(void) save_flags(flags); cli(); - free_page((unsigned long)tmp_buf); tty_unregister_driver(riscom_driver); put_tty_driver(riscom_driver); restore_flags(flags); diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index b4ea1266b66..48dae5d68da 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -118,17 +118,6 @@ struct cyclades_port cy_port[] = { }; #define NR_PORTS ARRAY_SIZE(cy_port) -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf = 0; - /* * This is used to look up the divisor speeds and the timeouts * We're normally limited to 15 distinct baud rates. The extra @@ -1198,7 +1187,7 @@ cy_write(struct tty_struct * tty, return 0; } - if (!tty || !info->xmit_buf || !tmp_buf){ + if (!tty || !info->xmit_buf){ return 0; } @@ -1983,13 +1972,6 @@ cy_open(struct tty_struct *tty, struct file * filp) tty->driver_data = info; info->tty = tty; - if (!tmp_buf) { - tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL); - if (!tmp_buf){ - return -ENOMEM; - } - } - /* * Start up serial port */ -- GitLab From d321765f7cbc2dc0683374c91bb3720d57331d37 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 4 Oct 2006 02:15:28 -0700 Subject: [PATCH 0468/1619] [PATCH] Char: serial167, remove useless tty check serial167, remove useless tty check tty is dereferenced before it is checked to be non-NULL. Remove such check. Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/serial167.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 48dae5d68da..f4809c8183c 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -1121,7 +1121,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch) if (serial_paranoia_check(info, tty->name, "cy_put_char")) return; - if (!tty || !info->xmit_buf) + if (!info->xmit_buf) return; local_irq_save(flags); @@ -1187,7 +1187,7 @@ cy_write(struct tty_struct * tty, return 0; } - if (!tty || !info->xmit_buf){ + if (!info->xmit_buf){ return 0; } -- GitLab From 7822082d4e054fbdec8cf26590a350e3496c5cc9 Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Wed, 4 Oct 2006 02:15:28 -0700 Subject: [PATCH 0469/1619] [PATCH] pktcdvd: Replace pktcdvd strings with macro DRIVER_NAME. pktcdvd: Replace pktcdvd strings with macro DRIVER_NAME. Signed-off-by: Thomas Maier Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 124 ++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index a6b2aa67c9b..8a73a054a15 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -62,6 +62,8 @@ #include +#define DRIVER_NAME "pktcdvd" + #if PACKET_DEBUG #define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) #else @@ -89,7 +91,7 @@ static void pkt_bio_finished(struct pktcdvd_device *pd) { BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0); if (atomic_dec_and_test(&pd->cdrw.pending_bios)) { - VPRINTK("pktcdvd: queue empty\n"); + VPRINTK(DRIVER_NAME": queue empty\n"); atomic_set(&pd->iosched.attention, 1); wake_up(&pd->wqueue); } @@ -400,7 +402,7 @@ static void pkt_dump_sense(struct packet_command *cgc) int i; struct request_sense *sense = cgc->sense; - printk("pktcdvd:"); + printk(DRIVER_NAME":"); for (i = 0; i < CDROM_PACKET_SIZE; i++) printk(" %02x", cgc->cmd[i]); printk(" - "); @@ -528,7 +530,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) need_write_seek = 0; if (need_write_seek && reads_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { - VPRINTK("pktcdvd: write, waiting\n"); + VPRINTK(DRIVER_NAME": write, waiting\n"); break; } pkt_flush_cache(pd); @@ -537,7 +539,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) } else { if (!reads_queued && writes_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { - VPRINTK("pktcdvd: read, waiting\n"); + VPRINTK(DRIVER_NAME": read, waiting\n"); break; } pd->iosched.writing = 1; @@ -600,7 +602,7 @@ static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q set_bit(PACKET_MERGE_SEGS, &pd->flags); return 0; } else { - printk("pktcdvd: cdrom max_phys_segments too small\n"); + printk(DRIVER_NAME": cdrom max_phys_segments too small\n"); return -EIO; } } @@ -1049,7 +1051,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) for (f = 0; f < pkt->frames; f++) if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset)) BUG(); - VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt); + VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt); atomic_set(&pkt->io_wait, 1); pkt->w_bio->bi_rw = WRITE; @@ -1286,7 +1288,7 @@ work_to_do: static void pkt_print_settings(struct pktcdvd_device *pd) { - printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable"); + printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable"); printk("%u blocks, ", pd->settings.size >> 2); printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2'); } @@ -1471,7 +1473,7 @@ static int pkt_set_write_settings(struct pktcdvd_device *pd) /* * paranoia */ - printk("pktcdvd: write mode wrong %d\n", wp->data_block_type); + printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type); return 1; } wp->packet_size = cpu_to_be32(pd->settings.size >> 2); @@ -1515,7 +1517,7 @@ static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti) if (ti->rt == 1 && ti->blank == 0) return 1; - printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); return 0; } @@ -1533,7 +1535,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) case 0x12: /* DVD-RAM */ return 1; default: - VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile); + VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile); return 0; } @@ -1542,22 +1544,22 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) * but i'm not sure, should we leave this to user apps? probably. */ if (di->disc_type == 0xff) { - printk("pktcdvd: Unknown disc. No track?\n"); + printk(DRIVER_NAME": Unknown disc. No track?\n"); return 0; } if (di->disc_type != 0x20 && di->disc_type != 0) { - printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type); + printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type); return 0; } if (di->erasable == 0) { - printk("pktcdvd: Disc not erasable\n"); + printk(DRIVER_NAME": Disc not erasable\n"); return 0; } if (di->border_status == PACKET_SESSION_RESERVED) { - printk("pktcdvd: Can't write to last track (reserved)\n"); + printk(DRIVER_NAME": Can't write to last track (reserved)\n"); return 0; } @@ -1593,12 +1595,12 @@ static int pkt_probe_settings(struct pktcdvd_device *pd) track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ if ((ret = pkt_get_track_info(pd, track, 1, &ti))) { - printk("pktcdvd: failed get_track\n"); + printk(DRIVER_NAME": failed get_track\n"); return ret; } if (!pkt_writable_track(pd, &ti)) { - printk("pktcdvd: can't write to this track\n"); + printk(DRIVER_NAME": can't write to this track\n"); return -EROFS; } @@ -1608,11 +1610,11 @@ static int pkt_probe_settings(struct pktcdvd_device *pd) */ pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; if (pd->settings.size == 0) { - printk("pktcdvd: detected zero packet size!\n"); + printk(DRIVER_NAME": detected zero packet size!\n"); return -ENXIO; } if (pd->settings.size > PACKET_MAX_SECTORS) { - printk("pktcdvd: packet size is too big\n"); + printk(DRIVER_NAME": packet size is too big\n"); return -EROFS; } pd->settings.fp = ti.fp; @@ -1654,7 +1656,7 @@ static int pkt_probe_settings(struct pktcdvd_device *pd) pd->settings.block_mode = PACKET_BLOCK_MODE2; break; default: - printk("pktcdvd: unknown data mode\n"); + printk(DRIVER_NAME": unknown data mode\n"); return -EROFS; } return 0; @@ -1688,10 +1690,10 @@ static int pkt_write_caching(struct pktcdvd_device *pd, int set) cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); ret = pkt_mode_select(pd, &cgc); if (ret) { - printk("pktcdvd: write caching control failed\n"); + printk(DRIVER_NAME": write caching control failed\n"); pkt_dump_sense(&cgc); } else if (!ret && set) - printk("pktcdvd: enabled write caching on %s\n", pd->name); + printk(DRIVER_NAME": enabled write caching on %s\n", pd->name); return ret; } @@ -1805,11 +1807,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) } if (!buf[6] & 0x40) { - printk("pktcdvd: Disc type is not CD-RW\n"); + printk(DRIVER_NAME": Disc type is not CD-RW\n"); return 1; } if (!buf[6] & 0x4) { - printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n"); + printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n"); return 1; } @@ -1829,14 +1831,14 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) *speed = us_clv_to_speed[sp]; break; default: - printk("pktcdvd: Unknown disc sub-type %d\n",st); + printk(DRIVER_NAME": Unknown disc sub-type %d\n",st); return 1; } if (*speed) { - printk("pktcdvd: Max. media speed: %d\n",*speed); + printk(DRIVER_NAME": Max. media speed: %d\n",*speed); return 0; } else { - printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st); + printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st); return 1; } } @@ -1847,7 +1849,7 @@ static int pkt_perform_opc(struct pktcdvd_device *pd) struct request_sense sense; int ret; - VPRINTK("pktcdvd: Performing OPC\n"); + VPRINTK(DRIVER_NAME": Performing OPC\n"); init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.sense = &sense; @@ -1865,12 +1867,12 @@ static int pkt_open_write(struct pktcdvd_device *pd) unsigned int write_speed, media_write_speed, read_speed; if ((ret = pkt_probe_settings(pd))) { - VPRINTK("pktcdvd: %s failed probe\n", pd->name); + VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name); return ret; } if ((ret = pkt_set_write_settings(pd))) { - DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name); + DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name); return -EIO; } @@ -1882,26 +1884,26 @@ static int pkt_open_write(struct pktcdvd_device *pd) case 0x13: /* DVD-RW */ case 0x1a: /* DVD+RW */ case 0x12: /* DVD-RAM */ - DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed); + DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed); break; default: if ((ret = pkt_media_speed(pd, &media_write_speed))) media_write_speed = 16; write_speed = min(write_speed, media_write_speed * 177); - DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176); + DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176); break; } read_speed = write_speed; if ((ret = pkt_set_speed(pd, write_speed, read_speed))) { - DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name); + DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name); return -EIO; } pd->write_speed = write_speed; pd->read_speed = read_speed; if ((ret = pkt_perform_opc(pd))) { - DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name); + DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name); } return 0; @@ -1929,7 +1931,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) goto out_putdev; if ((ret = pkt_get_last_written(pd, &lba))) { - printk("pktcdvd: pkt_get_last_written failed\n"); + printk(DRIVER_NAME": pkt_get_last_written failed\n"); goto out_unclaim; } @@ -1959,11 +1961,11 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) if (write) { if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { - printk("pktcdvd: not enough memory for buffers\n"); + printk(DRIVER_NAME": not enough memory for buffers\n"); ret = -ENOMEM; goto out_unclaim; } - printk("pktcdvd: %lukB available on disc\n", lba << 1); + printk(DRIVER_NAME": %lukB available on disc\n", lba << 1); } return 0; @@ -1983,7 +1985,7 @@ out: static void pkt_release_dev(struct pktcdvd_device *pd, int flush) { if (flush && pkt_flush_cache(pd)) - DPRINTK("pktcdvd: %s not flushing cache\n", pd->name); + DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name); pkt_lock_door(pd, 0); @@ -2006,7 +2008,7 @@ static int pkt_open(struct inode *inode, struct file *file) struct pktcdvd_device *pd = NULL; int ret; - VPRINTK("pktcdvd: entering open\n"); + VPRINTK(DRIVER_NAME": entering open\n"); mutex_lock(&ctl_mutex); pd = pkt_find_dev_from_minor(iminor(inode)); @@ -2040,7 +2042,7 @@ static int pkt_open(struct inode *inode, struct file *file) out_dec: pd->refcnt--; out: - VPRINTK("pktcdvd: failed open (%d)\n", ret); + VPRINTK(DRIVER_NAME": failed open (%d)\n", ret); mutex_unlock(&ctl_mutex); return ret; } @@ -2088,7 +2090,7 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio) pd = q->queuedata; if (!pd) { - printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b)); + printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b)); goto end_io; } @@ -2110,13 +2112,13 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio) } if (!test_bit(PACKET_WRITABLE, &pd->flags)) { - printk("pktcdvd: WRITE for ro device %s (%llu)\n", + printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n", pd->name, (unsigned long long)bio->bi_sector); goto end_io; } if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { - printk("pktcdvd: wrong bio size\n"); + printk(DRIVER_NAME": wrong bio size\n"); goto end_io; } @@ -2319,7 +2321,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) struct block_device *bdev; if (pd->pkt_dev == dev) { - printk("pktcdvd: Recursive setup not allowed\n"); + printk(DRIVER_NAME": Recursive setup not allowed\n"); return -EBUSY; } for (i = 0; i < MAX_WRITERS; i++) { @@ -2327,11 +2329,11 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) if (!pd2) continue; if (pd2->bdev->bd_dev == dev) { - printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b)); + printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b)); return -EBUSY; } if (pd2->pkt_dev == dev) { - printk("pktcdvd: Can't chain pktcdvd devices\n"); + printk(DRIVER_NAME": Can't chain pktcdvd devices\n"); return -EBUSY; } } @@ -2354,7 +2356,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) atomic_set(&pd->cdrw.pending_bios, 0); pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name); if (IS_ERR(pd->cdrw.thread)) { - printk("pktcdvd: can't start kernel thread\n"); + printk(DRIVER_NAME": can't start kernel thread\n"); ret = -ENOMEM; goto out_mem; } @@ -2364,7 +2366,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) proc->data = pd; proc->proc_fops = &pkt_proc_fops; } - DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); + DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); return 0; out_mem: @@ -2401,7 +2403,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); default: - VPRINTK("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); + VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd); return -ENOTTY; } @@ -2446,7 +2448,7 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) if (!pkt_devs[idx]) break; if (idx == MAX_WRITERS) { - printk("pktcdvd: max %d writers supported\n", MAX_WRITERS); + printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS); return -EBUSY; } @@ -2470,7 +2472,7 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) spin_lock_init(&pd->lock); spin_lock_init(&pd->iosched.lock); - sprintf(pd->name, "pktcdvd%d", idx); + sprintf(pd->name, DRIVER_NAME"%d", idx); init_waitqueue_head(&pd->wqueue); pd->bio_queue = RB_ROOT; @@ -2478,7 +2480,7 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) disk->first_minor = idx; disk->fops = &pktcdvd_ops; disk->flags = GENHD_FL_REMOVABLE; - sprintf(disk->disk_name, "pktcdvd%d", idx); + sprintf(disk->disk_name, DRIVER_NAME"%d", idx); disk->private_data = pd; disk->queue = blk_alloc_queue(GFP_KERNEL); if (!disk->queue) @@ -2520,7 +2522,7 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd) break; } if (idx == MAX_WRITERS) { - DPRINTK("pktcdvd: dev not setup\n"); + DPRINTK(DRIVER_NAME": dev not setup\n"); return -ENXIO; } @@ -2533,7 +2535,7 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd) blkdev_put(pd->bdev); remove_proc_entry(pd->name, pkt_proc); - DPRINTK("pktcdvd: writer %s unmapped\n", pd->name); + DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name); del_gendisk(pd->disk); blk_cleanup_queue(pd->disk->queue); @@ -2610,7 +2612,7 @@ static struct file_operations pkt_ctl_fops = { static struct miscdevice pkt_misc = { .minor = MISC_DYNAMIC_MINOR, - .name = "pktcdvd", + .name = DRIVER_NAME, .fops = &pkt_ctl_fops }; @@ -2623,9 +2625,9 @@ static int __init pkt_init(void) if (!psd_pool) return -ENOMEM; - ret = register_blkdev(pkt_major, "pktcdvd"); + ret = register_blkdev(pkt_major, DRIVER_NAME); if (ret < 0) { - printk("pktcdvd: Unable to register block device\n"); + printk(DRIVER_NAME": Unable to register block device\n"); goto out2; } if (!pkt_major) @@ -2633,18 +2635,18 @@ static int __init pkt_init(void) ret = misc_register(&pkt_misc); if (ret) { - printk("pktcdvd: Unable to register misc device\n"); + printk(DRIVER_NAME": Unable to register misc device\n"); goto out; } mutex_init(&ctl_mutex); - pkt_proc = proc_mkdir("pktcdvd", proc_root_driver); + pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); return 0; out: - unregister_blkdev(pkt_major, "pktcdvd"); + unregister_blkdev(pkt_major, DRIVER_NAME); out2: mempool_destroy(psd_pool); return ret; @@ -2652,9 +2654,9 @@ out2: static void __exit pkt_exit(void) { - remove_proc_entry("pktcdvd", proc_root_driver); + remove_proc_entry(DRIVER_NAME, proc_root_driver); misc_deregister(&pkt_misc); - unregister_blkdev(pkt_major, "pktcdvd"); + unregister_blkdev(pkt_major, DRIVER_NAME); mempool_destroy(psd_pool); } -- GitLab From add216608a63713b8a2c4545698d5ae02e27ac3b Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Wed, 4 Oct 2006 02:15:30 -0700 Subject: [PATCH 0470/1619] [PATCH] pktcdvd: rename a variable for better readability pktcdvd: Rename a variable for better readability. Signed-off-by: Thomas Maier Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 8a73a054a15..f2904f67af4 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -82,7 +82,7 @@ static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; static struct proc_dir_entry *pkt_proc; -static int pkt_major; +static int pktdev_major; static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ static mempool_t *psd_pool; @@ -2476,7 +2476,7 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) init_waitqueue_head(&pd->wqueue); pd->bio_queue = RB_ROOT; - disk->major = pkt_major; + disk->major = pktdev_major; disk->first_minor = idx; disk->fops = &pktcdvd_ops; disk->flags = GENHD_FL_REMOVABLE; @@ -2625,13 +2625,13 @@ static int __init pkt_init(void) if (!psd_pool) return -ENOMEM; - ret = register_blkdev(pkt_major, DRIVER_NAME); + ret = register_blkdev(pktdev_major, DRIVER_NAME); if (ret < 0) { printk(DRIVER_NAME": Unable to register block device\n"); goto out2; } - if (!pkt_major) - pkt_major = ret; + if (!pktdev_major) + pktdev_major = ret; ret = misc_register(&pkt_misc); if (ret) { @@ -2646,7 +2646,7 @@ static int __init pkt_init(void) return 0; out: - unregister_blkdev(pkt_major, DRIVER_NAME); + unregister_blkdev(pktdev_major, DRIVER_NAME); out2: mempool_destroy(psd_pool); return ret; @@ -2656,7 +2656,7 @@ static void __exit pkt_exit(void) { remove_proc_entry(DRIVER_NAME, proc_root_driver); misc_deregister(&pkt_misc); - unregister_blkdev(pkt_major, DRIVER_NAME); + unregister_blkdev(pktdev_major, DRIVER_NAME); mempool_destroy(psd_pool); } -- GitLab From 585b7747d63e3a5f65628d21c1745edd926d7897 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Wed, 4 Oct 2006 02:15:30 -0700 Subject: [PATCH 0471/1619] [PATCH] Remove unnecessary check in fs/reiserfs/inode.c Since all callers dereference dir, we dont need this check. Coverity id #337. Signed-off-by: Eric Sesterhenn Cc: Jeff Mahoney Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 7e5a2f5ebeb..9c69bcacad2 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1780,7 +1780,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, err = -EDQUOT; goto out_end_trans; } - if (!dir || !dir->i_nlink) { + if (!dir->i_nlink) { err = -EPERM; goto out_bad_inode; } -- GitLab From 18e39913d41ca4d63e9e94a2ad25b5ea31caaa7f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 4 Oct 2006 02:15:32 -0700 Subject: [PATCH 0472/1619] [PATCH] Fix spurious error on TAGS target when missing defconfig Not all architectures have a file named 'defconfig' (e.g. powerpc). However the make TAGS and make tags targets search such files for tags, causing an error message when they don't exist. This patch addresses the problem by instructing xargs not to run the tags program if there are no matching files. Signed-off-by: David Gibson Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4c6c5e32ef9..adb2c748e10 100644 --- a/Makefile +++ b/Makefile @@ -1321,7 +1321,7 @@ define xtags --langdef=kconfig \ --language-force=kconfig \ --regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \ - $(all-defconfigs) | xargs $1 -a \ + $(all-defconfigs) | xargs -r $1 -a \ --langdef=dotconfig \ --language-force=dotconfig \ --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \ @@ -1329,7 +1329,7 @@ define xtags $(all-sources) | xargs $1 -a; \ $(all-kconfigs) | xargs $1 -a \ --regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \ - $(all-defconfigs) | xargs $1 -a \ + $(all-defconfigs) | xargs -r $1 -a \ --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \ else \ $(all-sources) | xargs $1 -a; \ -- GitLab From 9bded00bf62090ebc9d6e8be640cdb69e8497db6 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 4 Oct 2006 02:15:34 -0700 Subject: [PATCH 0473/1619] [PATCH] fix "PCI: assign ioapic resource at hotplug" Roland Dreier wrote: > The change "PCI: assign ioapic resource at hotplug" (commit > 23186279658cea6d42a050400d3e79c56cb459b4 in Linus's tree) makes > networking stop working on my system (SuperMicro H8QC8 with four > dual-core Opteron 885 CPUs). In particular, the on-board NIC stops > working, probably because it gets assigned the wrong IRQ (225 in the > non-working case, 217 in the working case) > > With that patch applied, e1000 doesn't work. Reverting just that > patch (shown below) from Linus's latest tree fixes things for me. > The cause of this problem might be an wrong assumption that the 'start' member of resource structure for ioapic device has non-zero value if the resources are assigned by firmware. The 'start' member of ioapic device seems not to be set even though the resources were actually assigned to ioapic devices by firmware. Cc: Kenji Kaneshige Cc: MUNEDA Takahiro Cc: Satoru Takeuchi Cc: Kristen Carlson Accardi Cc: Greg Kroah-Hartman Cc: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/setup-bus.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 54404917be9..8f7bcf56f14 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -55,16 +55,16 @@ pbus_assign_resources_sorted(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { u16 class = dev->class >> 8; - /* Don't touch classless devices or host bridges. */ + /* Don't touch classless devices or host bridges or ioapics. */ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) continue; - /* Don't touch ioapics if it has the assigned resources. */ + /* Don't touch ioapic devices already enabled by firmware */ if (class == PCI_CLASS_SYSTEM_PIC) { - res = &dev->resource[0]; - if (res[0].start || res[1].start || res[2].start || - res[3].start || res[4].start || res[5].start) + u16 command; + pci_read_config_word(dev, PCI_COMMAND, &command); + if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) continue; } -- GitLab From 856fe98f168e5b80b053979769af2514aab96d6b Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Wed, 4 Oct 2006 02:15:35 -0700 Subject: [PATCH 0474/1619] [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(-) diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c index d418b829721..22915cc46ba 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 693c0557e70..de466e11e27 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 -- GitLab From 4020f2d7f0b0e68b92bec9a3e1f4a54a7a9dc672 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 4 Oct 2006 02:15:37 -0700 Subject: [PATCH 0475/1619] [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 diff --git a/MAINTAINERS b/MAINTAINERS index 1c6223d3ce7..77e58585ce5 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 00000000000..a7ed3044618 --- /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 00000000000..cca5f852246 --- /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 00000000000..6d23dc08d16 --- /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 00000000000..203dd5e11ec --- /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 -- GitLab From f9565129993446e16678cfc4d9c7f3b7e75eecbd Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 4 Oct 2006 02:15:38 -0700 Subject: [PATCH 0476/1619] [PATCH] mmc: driver for TI FlashMedia card reader - Kconfig/Makefile 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 --- drivers/misc/Kconfig | 32 ++++++++++++++++++++++++++++++-- drivers/misc/Makefile | 2 ++ drivers/mmc/Kconfig | 16 ++++++++++++++++ drivers/mmc/Makefile | 1 + 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7fc692a8f5b..3df0e7a07c4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -18,7 +18,7 @@ config IBM_ASM service processor board as a regular serial port. To make use of this feature serial driver support (CONFIG_SERIAL_8250) must be enabled. - + WARNING: This software may not be supported or function correctly on your IBM server. Please consult the IBM ServerProven website for @@ -28,5 +28,33 @@ config IBM_ASM If unsure, say N. -endmenu +config TIFM_CORE + tristate "TI Flash Media interface support (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + If you want support for Texas Instruments(R) Flash Media adapters + you should select this option and then also choose an appropriate + host adapter, such as 'TI Flash Media PCI74xx/PCI76xx host adapter + support', if you have a TI PCI74xx compatible card reader, for + example. + You will also have to select some flash card format drivers. MMC/SD + cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD + Interface support (MMC_TIFM_SD)'. + + To compile this driver as a module, choose M here: the module will + be called tifm_core. +config TIFM_7XX1 + tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)" + depends on PCI && TIFM_CORE && EXPERIMENTAL + default TIFM_CORE + help + This option enables support for Texas Instruments(R) PCI74xx and + PCI76xx families of Flash Media adapters, found in many laptops. + To make actual use of the device, you will have to select some + flash card format drivers, as outlined in the TIFM_CORE Help. + + To compile this driver as a module, choose M here: the module will + be called tifm_7xx1. + +endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c1bf1fb04c5..d65ece76095 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -6,3 +6,5 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_LKDTM) += lkdtm.o +obj-$(CONFIG_TIFM_CORE) += tifm_core.o +obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index f540bd88dc5..ea41852ec8c 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -109,4 +109,20 @@ config MMC_IMX If unsure, say N. +config MMC_TIFM_SD + tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" + depends on MMC && EXPERIMENTAL + select TIFM_CORE + help + Say Y here if you want to be able to access MMC/SD cards with + the Texas Instruments(R) Flash Media card reader, found in many + laptops. + This option 'selects' (turns on, enables) 'TIFM_CORE', but you + probably also need appropriate card reader host adapter, such as + 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support + (TIFM_7XX1)'. + + To compile this driver as a module, choose M here: the + module will be called tifm_sd. + endmenu diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index b1f6e03e7aa..acfd4de0aba 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o +obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o mmc_core-y := mmc.o mmc_sysfs.o mmc_core-$(CONFIG_BLOCK) += mmc_queue.o -- GitLab From 5f25a66f6bbac563c94af94f03491b3ae43c40af Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 4 Oct 2006 02:15:39 -0700 Subject: [PATCH 0477/1619] [PATCH] mmc: fix MMIO vs memory races in sdhci Sprinkle some mmiowb() where needed (writeX() before unlock()). Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/sdhci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 4dab5ec392e..9ff9231116a 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -717,6 +717,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) } else sdhci_send_command(host, mrq->cmd); + mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -753,6 +754,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ctrl &= ~SDHCI_CTRL_4BITBUS; writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); + mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -860,6 +862,7 @@ static void sdhci_tasklet_finish(unsigned long param) sdhci_deactivate_led(host); + mmiowb(); spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); @@ -893,6 +896,7 @@ static void sdhci_timeout_timer(unsigned long data) } } + mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -1030,6 +1034,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs) result = IRQ_HANDLED; + mmiowb(); out: spin_unlock(&host->lock); @@ -1095,6 +1100,7 @@ static int sdhci_resume (struct pci_dev *pdev) if (chip->hosts[i]->flags & SDHCI_USE_DMA) pci_set_master(pdev); sdhci_init(chip->hosts[i]); + mmiowb(); ret = mmc_resume_host(chip->hosts[i]->mmc); if (ret) return ret; @@ -1327,6 +1333,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) host->chip = chip; chip->hosts[slot] = host; + mmiowb(); + mmc_add_host(mmc); printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc), -- GitLab From 8a4da1430f7f2a16df3be9c7b5d55ba4e75b708c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 4 Oct 2006 02:15:40 -0700 Subject: [PATCH 0478/1619] [PATCH] mmc: avoid some resets without card Some Ricoh controllers only respect a full reset when there is no card in the slot. As we wait for the reset to complete, we must avoid even requesting those resets on the buggy controllers. Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/sdhci.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 9ff9231116a..20711acb012 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -35,6 +35,8 @@ static unsigned int debug_quirks = 0; #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) #define SDHCI_QUIRK_FORCE_DMA (1<<1) +/* Controller doesn't like some resets when there is no card inserted. */ +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) static const struct pci_device_id pci_ids[] __devinitdata = { { @@ -51,7 +53,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_RICOH_R5C822, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = SDHCI_QUIRK_FORCE_DMA, + .driver_data = SDHCI_QUIRK_FORCE_DMA | + SDHCI_QUIRK_NO_CARD_NO_RESET, }, { @@ -125,6 +128,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) { unsigned long timeout; + if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { + if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT)) + return; + } + writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET); if (mask & SDHCI_RESET_ALL) @@ -1174,6 +1183,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) host = mmc_priv(mmc); host->mmc = mmc; + host->chip = chip; + chip->hosts[slot] = host; + host->bar = first_bar + slot; host->addr = pci_resource_start(pdev, host->bar); @@ -1330,9 +1342,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) sdhci_dumpregs(host); #endif - host->chip = chip; - chip->hosts[slot] = host; - mmiowb(); mmc_add_host(mmc); -- GitLab From 7104e2d5a85b4b786d6a63568beffe1e185547bb Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 4 Oct 2006 02:15:41 -0700 Subject: [PATCH 0479/1619] [PATCH] mmc: use own work queue The MMC layer uses the standard work queue for doing card detection. As this queue is shared with other crucial subsystems, the effects of a long (and perhaps buggy) detection can cause the system to be unusable. E.g. the keyboard stops working while the detection routine is running. The solution is to add a specific mmc work queue to run the detection code in. This is similar to how other subsystems handle detection (a full kernel thread is the most common theme). Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/mmc.c | 6 +++--- drivers/mmc/mmc.h | 4 ++++ drivers/mmc/mmc_sysfs.c | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 5b9caa7978d..ee8863c123e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1166,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host) void mmc_detect_change(struct mmc_host *host, unsigned long delay) { if (delay) - schedule_delayed_work(&host->detect, delay); + mmc_schedule_delayed_work(&host->detect, delay); else - schedule_work(&host->detect); + mmc_schedule_work(&host->detect); } EXPORT_SYMBOL(mmc_detect_change); @@ -1311,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host); */ void mmc_free_host(struct mmc_host *host) { - flush_scheduled_work(); + mmc_flush_scheduled_work(); mmc_free_host_sysfs(host); } diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h index 97bae00292f..cd5e0ab3d84 100644 --- a/drivers/mmc/mmc.h +++ b/drivers/mmc/mmc.h @@ -18,4 +18,8 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); int mmc_add_host_sysfs(struct mmc_host *host); 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); +void mmc_flush_scheduled_work(void); #endif diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index a2a35fd946e..10cc9734eaa 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host *host) class_device_put(&host->class_dev); } +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) +{ + return queue_delayed_work(workqueue, work, delay); +} + +/* + * Internal function. Flush all scheduled work from the MMC work queue. + */ +void mmc_flush_scheduled_work(void) +{ + flush_workqueue(workqueue); +} static int __init mmc_init(void) { - int ret = bus_register(&mmc_bus_type); + int ret; + + workqueue = create_singlethread_workqueue("kmmcd"); + if (!workqueue) + return -ENOMEM; + + ret = bus_register(&mmc_bus_type); if (ret == 0) { ret = class_register(&mmc_host_class); if (ret) @@ -333,6 +365,7 @@ static void __exit mmc_exit(void) { class_unregister(&mmc_host_class); bus_unregister(&mmc_bus_type); + destroy_workqueue(workqueue); } module_init(mmc_init); -- GitLab From 176f00ffed3ef94a198326fbf6a5db64f1cf73ad Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 4 Oct 2006 02:15:41 -0700 Subject: [PATCH 0480/1619] [PATCH] mmc: properly use the new multi block-write error handling Use the new multi block-write error reporting flag and properly tell the block layer how much data was transferred before the error. Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/mmc_block.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index db0e8ad439a..c1293f1bda8 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -158,13 +158,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; + struct mmc_blk_request brq; int ret; if (mmc_card_claim_host(card)) goto cmd_err; do { - struct mmc_blk_request brq; struct mmc_command cmd; u32 readcmd, writecmd; @@ -278,17 +278,27 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) cmd_err: mmc_card_release_host(card); + ret = 1; + /* - * This is a little draconian, but until we get proper - * error handling sorted out here, its the best we can - * do - especially as some hosts have no idea how much - * data was transferred before the error occurred. + * For writes and where the host claims to support proper + * error reporting, we first ok the successful blocks. + * + * 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)) { + spin_lock_irq(&md->lock); + ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); + spin_unlock_irq(&md->lock); + } + spin_lock_irq(&md->lock); - do { + while (ret) { ret = end_that_request_chunk(req, 0, req->current_nr_sectors << 9); - } while (ret); + } add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req); -- GitLab From 1d02a030b01443f1cb81f22750113fe9a98109d9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 4 Oct 2006 02:15:42 -0700 Subject: [PATCH 0481/1619] [PATCH] hisax niccy cleanup Whitespace cleanup, delete unnecesasry parenthesis and braces. Signed-off-by: Jiri Slaby Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hisax/niccy.c | 223 ++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 114 deletions(-) diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 489022bdef7..0945336c28d 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -13,7 +13,6 @@ * */ - #include #include "hisax.h" #include "isac.h" @@ -45,33 +44,31 @@ static const char *niccy_revision = "$Revision: 1.21.2.4 $"; #define PCI_IRQ_DISABLE 0xff0000 #define PCI_IRQ_ASSERT 0x800000 -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) +static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) { register u_char ret; byteout(ale, off); ret = bytein(adr); - return (ret); + return ret; } -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +static inline void readfifo(unsigned int ale, unsigned int adr, u_char off, + u_char *data, int size) { byteout(ale, off); insb(adr, data, size); } - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) +static inline void writereg(unsigned int ale, unsigned int adr, u_char off, + u_char data) { byteout(ale, off); byteout(adr, data); } -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +static inline void writefifo(unsigned int ale, unsigned int adr, u_char off, + u_char *data, int size) { byteout(ale, off); outsb(adr, data, size); @@ -79,39 +76,34 @@ writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int siz /* Interface functions */ -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) +static u_char ReadISAC(struct IsdnCardState *cs, u_char offset) { - return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset)); + return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset); } -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) { writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value); } -static void -ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +static void ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) { readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); } -static void -WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +static void WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) { writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); } -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { - return (readreg(cs->hw.niccy.hscx_ale, - cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0))); + return readreg(cs->hw.niccy.hscx_ale, + cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)); } -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, + u_char value) { writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value); @@ -130,8 +122,8 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #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 pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char val; @@ -141,21 +133,23 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (cs->subtyp == NICCY_PCI) { int ival; ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */ + if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */ spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; } outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); } - val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); - Start_HSCX: + val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, + HSCX_ISTA + 0x40); +Start_HSCX: if (val) hscx_int_main(cs, val); val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); - Start_ISAC: +Start_ISAC: if (val) isac_interrupt(cs, val); - val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); + val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, + HSCX_ISTA + 0x40); if (val) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX IntStat after IntRoutine"); @@ -168,21 +162,21 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) goto Start_ISAC; } writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, + 0xFF); writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF); writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0); writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,0); spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -static void -release_io_niccy(struct IsdnCardState *cs) +static void release_io_niccy(struct IsdnCardState *cs) { if (cs->subtyp == NICCY_PCI) { int val; - + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); val &= PCI_IRQ_DISABLE; outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); @@ -194,8 +188,7 @@ release_io_niccy(struct IsdnCardState *cs) } } -static void -niccy_reset(struct IsdnCardState *cs) +static void niccy_reset(struct IsdnCardState *cs) { if (cs->subtyp == NICCY_PCI) { int val; @@ -207,29 +200,28 @@ niccy_reset(struct IsdnCardState *cs) inithscxisac(cs, 3); } -static int -niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) +static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) { u_long flags; switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - niccy_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return(0); - case CARD_RELEASE: - release_io_niccy(cs); - return(0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - niccy_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return(0); - case CARD_TEST: - return(0); + case CARD_RESET: + spin_lock_irqsave(&cs->lock, flags); + niccy_reset(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return 0; + case CARD_RELEASE: + release_io_niccy(cs); + return 0; + case CARD_INIT: + spin_lock_irqsave(&cs->lock, flags); + niccy_reset(cs); + spin_unlock_irqrestore(&cs->lock, flags); + return 0; + case CARD_TEST: + return 0; } - return(0); + return 0; } static struct pci_dev *niccy_dev __devinitdata = NULL; @@ -237,8 +229,7 @@ static struct pci_dev *niccy_dev __devinitdata = NULL; static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __devinit -setup_niccy(struct IsdnCard *card) +int __devinit setup_niccy(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -246,40 +237,44 @@ setup_niccy(struct IsdnCard *card) strcpy(tmp, niccy_revision); printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_NICCY) - return (0); + return 0; #ifdef __ISAPNP__ if (!card->para[1] && isapnp_present()) { struct pnp_dev *pnp_d = NULL; int err; - if ((pnp_c = pnp_find_card( - ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pnp_c))) { - if (!(pnp_d = pnp_find_dev(pnp_c, - ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pnp_d))) { - printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n"); - return (0); + pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'), + ISAPNP_FUNCTION(0x0150), pnp_c); + if (pnp_c) { + pnp_d = pnp_find_dev(pnp_c, + ISAPNP_VENDOR('S', 'D', 'A'), + ISAPNP_FUNCTION(0x0150), pnp_d); + if (!pnp_d) { + printk(KERN_ERR "NiccyPnP: PnP error card " + "found, no device\n"); + return 0; } pnp_disable_dev(pnp_d); err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); + if (err < 0) { + printk(KERN_WARNING "%s: pnp_activate_dev " + "ret(%d)\n", __FUNCTION__, err); + return 0; } card->para[1] = pnp_port_start(pnp_d, 0); card->para[2] = pnp_port_start(pnp_d, 1); card->para[0] = pnp_irq(pnp_d, 0); - if (!card->para[0] || !card->para[1] || !card->para[2]) { - printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n", - card->para[0], card->para[1], card->para[2]); + if (!card->para[0] || !card->para[1] || + !card->para[2]) { + printk(KERN_ERR "NiccyPnP:some resources are " + "missing %ld/%lx/%lx\n", + card->para[0], card->para[1], + card->para[2]); pnp_disable_dev(pnp_d); - return(0); + return 0; } - } else { + } else printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n"); - } } #endif if (card->para[1]) { @@ -291,50 +286,51 @@ setup_niccy(struct IsdnCard *card) cs->subtyp = NICCY_PNP; cs->irq = card->para[0]; if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) { - printk(KERN_WARNING - "HiSax: %s data port %x-%x already in use\n", - CardType[card->typ], - cs->hw.niccy.isac, - cs->hw.niccy.isac + 1); - return (0); + printk(KERN_WARNING "HiSax: %s data port %x-%x " + "already in use\n", CardType[card->typ], + cs->hw.niccy.isac, cs->hw.niccy.isac + 1); + return 0; } if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) { - printk(KERN_WARNING - "HiSax: %s address port %x-%x already in use\n", - CardType[card->typ], + printk(KERN_WARNING "HiSax: %s address port %x-%x " + "already in use\n", CardType[card->typ], cs->hw.niccy.isac_ale, cs->hw.niccy.isac_ale + 1); release_region(cs->hw.niccy.isac, 2); - return (0); + return 0; } } else { #ifdef CONFIG_PCI u_int pci_ioaddr; cs->subtyp = 0; if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, - PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { + PCI_DEVICE_ID_SATSAGEM_NICCY, + niccy_dev))) { if (pci_enable_device(niccy_dev)) - return(0); + return 0; /* get IRQ */ if (!niccy_dev->irq) { - printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); - return(0); + printk(KERN_WARNING + "Niccy: No IRQ for PCI card found\n"); + return 0; } cs->irq = niccy_dev->irq; cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); if (!cs->hw.niccy.cfg_reg) { - printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); - return(0); + printk(KERN_WARNING + "Niccy: No IO-Adr for PCI cfg found\n"); + return 0; } pci_ioaddr = pci_resource_start(niccy_dev, 1); if (!pci_ioaddr) { - printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); - return(0); + printk(KERN_WARNING + "Niccy: No IO-Adr for PCI card found\n"); + return 0; } cs->subtyp = NICCY_PCI; } else { printk(KERN_WARNING "Niccy: No PCI card found\n"); - return(0); + return 0; } cs->irq_flags |= IRQF_SHARED; cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; @@ -343,29 +339,28 @@ setup_niccy(struct IsdnCard *card) cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; if (!request_region(cs->hw.niccy.isac, 4, "niccy")) { printk(KERN_WARNING - "HiSax: %s data port %x-%x already in use\n", - CardType[card->typ], - cs->hw.niccy.isac, - cs->hw.niccy.isac + 4); - return (0); + "HiSax: %s data port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.isac, cs->hw.niccy.isac + 4); + return 0; } if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) { printk(KERN_WARNING "HiSax: %s pci port %x-%x already in use\n", - CardType[card->typ], - cs->hw.niccy.cfg_reg, - cs->hw.niccy.cfg_reg + 0x40); + CardType[card->typ], + cs->hw.niccy.cfg_reg, + cs->hw.niccy.cfg_reg + 0x40); release_region(cs->hw.niccy.isac, 4); - return (0); + return 0; } #else printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n"); printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n"); - return (0); -#endif /* CONFIG_PCI */ + return 0; +#endif /* CONFIG_PCI */ } printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n", - CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI", + CardType[cs->typ], (cs->subtyp == 1) ? "PnP" : "PCI", cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); setup_isac(cs); cs->readisac = &ReadISAC; @@ -379,10 +374,10 @@ setup_niccy(struct IsdnCard *card) cs->irq_func = &niccy_interrupt; ISACVersion(cs, "Niccy:"); if (HscxVersion(cs, "Niccy:")) { - printk(KERN_WARNING - "Niccy: wrong HSCX versions check IO address\n"); + printk(KERN_WARNING "Niccy: wrong HSCX versions check IO " + "address\n"); release_io_niccy(cs); - return (0); + return 0; } - return (1); + return 1; } -- GitLab From 7ed94296a660a61989b5d54f0c4bb804f30567d3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:43 -0700 Subject: [PATCH 0482/1619] [PATCH] knfsd: nfsd: lockdep annotation fix nfsv2 needs the I_MUTEX_PARENT on the directory when creating a file too. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 06cd0db0f32..4e06810b610 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -225,7 +225,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, nfserr = nfserr_exist; if (isdotent(argp->name, argp->len)) goto done; - fh_lock(dirfhp); + fh_lock_nested(dirfhp, I_MUTEX_PARENT); dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); if (IS_ERR(dchild)) { nfserr = nfserrno(PTR_ERR(dchild)); -- GitLab From 37a034729ae611295bbb8e925333d4d54d7c1ebc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:44 -0700 Subject: [PATCH 0483/1619] [PATCH] knfsd: call lockd_down when closing a socket via a write to nfsd/portlist The refcount that nfsd holds on lockd is based on the number of open sockets. So when we close a socket, we should decrement the ref (with lockd_down). Currently when a socket is closed via writing to the portlist file, that doesn't happen. So: make sure we get an error return if the socket that was requested does is not found, and call lockd_down if it was. Cc: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 2 ++ net/sunrpc/svcsock.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 5c6a477c20e..83997282fc1 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -545,6 +545,8 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) if (nfsd_serv) len = svc_sock_names(buf, nfsd_serv, toclose); unlock_kernel(); + if (len >= 0) + lockd_down(); kfree(toclose); return len; } diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index cba85d19522..4e0813b12cc 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -493,6 +493,8 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) spin_unlock(&serv->sv_lock); if (closesk) svc_delete_socket(closesk); + else if (toclose) + return -ENOENT; return len; } EXPORT_SYMBOL(svc_sock_names); -- GitLab From cda9e0cd8a6b30ccc32edced066c378fbd87003d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:44 -0700 Subject: [PATCH 0484/1619] [PATCH] knfsd: Protect update to sn_nrthreads with lock_kernel Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 83997282fc1..f85472dda46 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -532,7 +532,9 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) /* Decrease the count, but don't shutdown the * the service */ + lock_kernel(); nfsd_serv->sv_nrthreads--; + unlock_kernel(); } return err; } -- GitLab From 5680c44632053a6c9464bca43083f01776d318da Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:45 -0700 Subject: [PATCH 0485/1619] [PATCH] knfsd: Fixed handling of lockd fail when adding nfsd socket Arrgg.. We cannot 'lockd_up' before 'svc_addsock' as we don't know the protocol yet.... So switch it around again and save the name of the created sockets so that it can be closed if lock_up fails. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 12 ++++++------ net/sunrpc/svcsock.c | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index f85472dda46..6c2ddfed2cf 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -523,11 +523,11 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) err = nfsd_create_serv(); if (!err) { int proto = 0; - err = lockd_up(proto); - if (!err) { - err = svc_addsock(nfsd_serv, fd, buf, &proto); - if (err) - lockd_down(); + err = svc_addsock(nfsd_serv, fd, buf, &proto); + if (err >= 0) { + err = lockd_up(proto); + if (err < 0) + svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); } /* Decrease the count, but don't shutdown the * the service @@ -536,7 +536,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) nfsd_serv->sv_nrthreads--; unlock_kernel(); } - return err; + return err < 0 ? err : 0; } if (buf[0] == '-') { char *toclose = kstrdup(buf+1, GFP_KERNEL); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 4e0813b12cc..4de8626e4f5 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -492,6 +492,9 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) } spin_unlock(&serv->sv_lock); if (closesk) + /* Should unregister with portmap, but you cannot + * unregister just one protocol... + */ svc_delete_socket(closesk); else if (toclose) return -ENOENT; -- GitLab From 4452435948424e5322c2a2fefbdc2cf3732cc45d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:46 -0700 Subject: [PATCH 0486/1619] [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(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index fe56b38364c..71108da2e54 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 16e10c170ae..f813b054f4a 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 243d94b9653..20ba728a464 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 5be00436b5b..9f30c53ac0e 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 3f14a17eaa6..ad2fba3c54f 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 443ebc52e38..bfd36e587ec 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 4ebcdf91f3b..3669e91c43b 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 638c0b57620..558692d7e46 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 a99e67b164c..f4a509a925b 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 4de8626e4f5..25096d53667 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; } -- GitLab From 3cc03b164cf01c6f36e64720b58610d292fb26f7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:47 -0700 Subject: [PATCH 0487/1619] [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(-) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index f61142afea4..0c4fab01879 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 20ba728a464..4b9aefbcc93 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 15ded7a30a7..38b0f91175d 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 9f30c53ac0e..df341956254 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 4e06810b610..ca497315021 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 ad2fba3c54f..ab6745e78d1 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 a38f9d776de..0e53de87d88 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 a4322741f8b..474d882dc2f 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 77adba7d228..66e642762a0 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 3669e91c43b..cb0ed9beb22 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 25096d53667..1d512337ccd 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; -- GitLab From 7adae489fe794e3e203ff168595f635d0b845e59 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Wed, 4 Oct 2006 02:15:47 -0700 Subject: [PATCH 0488/1619] [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(-) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 0c4fab01879..a5ebc7dbb38 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 4b9aefbcc93..247d518248b 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 df341956254..4cfacc557b4 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 ca497315021..9ee1dab5d44 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 ab6745e78d1..1135c0d1455 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 b75bb1b38d0..adbddf00789 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 862c0d8c838..534cdc7be58 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 8d10d148834..1e65f2dd80e 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 cb0ed9beb22..74e52c245da 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 6cf62658075..60394fbc4c7 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 f4a509a925b..b252401c860 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); -- GitLab From 596bbe53eb3abfe7326b2f5e8afd614265c319c8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:48 -0700 Subject: [PATCH 0489/1619] [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(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 6c2ddfed2cf..39aed901514 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 19443056ec3..0603baad542 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 adbddf00789..f478066f9cd 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 e1dbc86c270..259841bb2f6 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 -- GitLab From fce1456a19f5c08b688c29f00ef90fdfa074c79b Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Wed, 4 Oct 2006 02:15:49 -0700 Subject: [PATCH 0490/1619] [PATCH] knfsd: make nfsd readahead params cache SMP-friendly Make the nfsd read-ahead params cache more SMP-friendly by changing the single global list and lock into a fixed 16-bucket hashtable with per-bucket locks. This reduces spinlock contention in nfsd_read() on read-heavy workloads on multiprocessor servers. Testing was on a 4 CPU 4 NIC Altix using 4 IRIX clients each doing 1K streaming reads at full line rate. The server had 128 nfsd threads, which sizes the RA cache at 256 entries, of which only a handful were used. Flat profiling shows nfsd_read(), including the inlined nfsd_get_raparms(), taking 10.4% of each CPU. This patch drops the contribution from nfsd() to 1.71% for each CPU. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/vfs.c | 60 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index bfd36e587ec..137565a136d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -54,6 +54,7 @@ #include #include #endif /* CONFIG_NFSD_V4 */ +#include #include @@ -81,10 +82,19 @@ struct raparms { dev_t p_dev; int p_set; struct file_ra_state p_ra; + unsigned int p_hindex; }; +struct raparm_hbucket { + struct raparms *pb_head; + spinlock_t pb_lock; +} ____cacheline_aligned_in_smp; + static struct raparms * raparml; -static struct raparms * raparm_cache; +#define RAPARM_HASH_BITS 4 +#define RAPARM_HASH_SIZE (1<p_next) { + spin_lock(&rab->pb_lock); + for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) { if (ra->p_ino == ino && ra->p_dev == dev) goto found; depth++; @@ -761,7 +775,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino) } depth = nfsdstats.ra_size*11/10; if (!frap) { - spin_unlock(&ra_lock); + spin_unlock(&rab->pb_lock); return NULL; } rap = frap; @@ -769,15 +783,16 @@ nfsd_get_raparms(dev_t dev, ino_t ino) ra->p_dev = dev; ra->p_ino = ino; ra->p_set = 0; + ra->p_hindex = hash; found: - if (rap != &raparm_cache) { + if (rap != &rab->pb_head) { *rap = ra->p_next; - ra->p_next = raparm_cache; - raparm_cache = ra; + ra->p_next = rab->pb_head; + rab->pb_head = ra; } ra->p_count++; nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; - spin_unlock(&ra_lock); + spin_unlock(&rab->pb_lock); return ra; } @@ -853,11 +868,12 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, /* Write back readahead params */ if (ra) { - spin_lock(&ra_lock); + struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; + spin_lock(&rab->pb_lock); ra->p_ra = file->f_ra; ra->p_set = 1; ra->p_count--; - spin_unlock(&ra_lock); + spin_unlock(&rab->pb_lock); } if (err >= 0) { @@ -1833,11 +1849,11 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) void nfsd_racache_shutdown(void) { - if (!raparm_cache) + if (!raparml) return; dprintk("nfsd: freeing readahead buffers.\n"); kfree(raparml); - raparm_cache = raparml = NULL; + raparml = NULL; } /* * Initialize readahead param cache @@ -1846,19 +1862,31 @@ int nfsd_racache_init(int cache_size) { int i; + int j = 0; + int nperbucket; - if (raparm_cache) + + if (raparml) return 0; + if (cache_size < 2*RAPARM_HASH_SIZE) + cache_size = 2*RAPARM_HASH_SIZE; raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL); if (raparml != NULL) { dprintk("nfsd: allocating %d readahead buffers.\n", cache_size); + for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) { + raparm_hash[i].pb_head = NULL; + spin_lock_init(&raparm_hash[i].pb_lock); + } + nperbucket = cache_size >> RAPARM_HASH_BITS; memset(raparml, 0, sizeof(struct raparms) * cache_size); for (i = 0; i < cache_size - 1; i++) { - raparml[i].p_next = raparml + i + 1; + if (i % nperbucket == 0) + raparm_hash[j++].pb_head = raparml + i; + if (i % nperbucket < nperbucket-1) + raparml[i].p_next = raparml + i + 1; } - raparm_cache = raparml; } else { printk(KERN_WARNING "nfsd: Could not allocate memory read-ahead cache.\n"); -- GitLab From 7b2b1fee30df7e2165525cd03f7d1d01a3a56794 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Wed, 4 Oct 2006 02:15:50 -0700 Subject: [PATCH 0491/1619] [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(-) diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index b5612c958cc..3699dff7db8 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 a6601650dee..de92619b082 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 4c296152cbf..98b21ad370f 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 40d41a2831d..e1bd933629f 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 1d512337ccd..b39e7e2b648 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); -- GitLab From 977faf392fc898407554bbe7338d57b29e3660cf Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:51 -0700 Subject: [PATCH 0492/1619] [PATCH] knfsd: hide use of lockd's h_monitored flag This patch moves all checks of the h_monitored flag into the nsm_monitor/unmonitor functions. A subsequent patch will replace the mechanism by which we mark a host as being monitored. There is still one occurence of h_monitored outside of mon.c and that is in clntlock.c where we respond to a reboot. The subsequent patch will modify this too. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntproc.c | 2 +- fs/lockd/host.c | 9 ++++++--- fs/lockd/mon.c | 19 ++++++++++++------- fs/lockd/svc4proc.c | 2 +- fs/lockd/svcproc.c | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 0116729cec5..5436be623e3 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -499,7 +499,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) unsigned char fl_flags = fl->fl_flags; int status = -ENOLCK; - if (!host->h_monitored && nsm_monitor(host) < 0) { + if (nsm_monitor(host) < 0) { printk(KERN_NOTICE "lockd: failed to monitor %s\n", host->h_name); goto out; diff --git a/fs/lockd/host.c b/fs/lockd/host.c index a0d0b58ce7a..637ec956706 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -331,9 +331,12 @@ nlm_gc_hosts(void) } dprintk("lockd: delete host %s\n", host->h_name); *q = host->h_next; - /* Don't unmonitor hosts that have been invalidated */ - if (host->h_monitored && !host->h_killed) - nsm_unmonitor(host); + + /* + * Unmonitor unless host was invalidated (i.e. lockd restarted) + */ + nsm_unmonitor(host); + if ((clnt = host->h_rpcclnt) != NULL) { if (atomic_read(&clnt->cl_users)) { printk(KERN_WARNING diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index a816b920d43..e02a1a4dfce 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -74,6 +74,8 @@ nsm_monitor(struct nlm_host *host) int status; dprintk("lockd: nsm_monitor(%s)\n", host->h_name); + if (host->h_monitored) + return 0; status = nsm_mon_unmon(host, SM_MON, &res); @@ -91,15 +93,18 @@ int nsm_unmonitor(struct nlm_host *host) { struct nsm_res res; - int status; + int status = 0; dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); - - status = nsm_mon_unmon(host, SM_UNMON, &res); - if (status < 0) - printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name); - else - host->h_monitored = 0; + if (!host->h_monitored) + return 0; + host->h_monitored = 0; + + 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); + } return status; } diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index a2dd9ccb9b3..b5aceb83f8c 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -39,7 +39,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain host handle */ if (!(host = nlmsvc_lookup_host(rqstp)) - || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0)) + || (argp->monitor && nsm_monitor(host) < 0)) goto no_locks; *hostp = host; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index dbb66a3b5cd..dbc4ea2638c 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -67,7 +67,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain host handle */ if (!(host = nlmsvc_lookup_host(rqstp)) - || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0)) + || (argp->monitor && nsm_monitor(host) < 0)) goto no_locks; *hostp = host; -- GitLab From cf712c24d72341effcfd28330b83b49f77cb627b Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:52 -0700 Subject: [PATCH 0493/1619] [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(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 637ec956706..bcc21b05808 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 b5aceb83f8c..97bd36c09a5 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 dbc4ea2638c..452eb5e5ea4 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 47b7dbd647a..5f886695ac9 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 *); /* -- GitLab From db4e4c9a9e741ee812e1febf5e386d6a24218a71 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:52 -0700 Subject: [PATCH 0494/1619] [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(-) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 5436be623e3..7e6f22e2a3b 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 bcc21b05808..481ce7ee100 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 97bd36c09a5..7d835ad8107 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 93c00ee7189..3127ae9e435 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 452eb5e5ea4..12291ab1e72 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 5f886695ac9..0f9b236bca7 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 *); -- GitLab From 8dead0dbd478f35fd943f3719591e5af1ac0950d Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:53 -0700 Subject: [PATCH 0495/1619] [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(-) diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 87e1d03e826..54e63ddef04 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 481ce7ee100..0bf4afb71d2 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 e02a1a4dfce..e27981403fb 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 0f9b236bca7..ab2ffc8a0b4 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 *); /* -- GitLab From f0737a39a64a9df32bb045c54e1cdf6cecdcbdd7 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:54 -0700 Subject: [PATCH 0496/1619] [PATCH] knfsd: misc minor fixes, indentation changes cleans up some code in lockd/host.c, fixes an error printk and makes it a fatal BUG if nlmsvc_free_host_resources fails. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 15 ++++++--------- fs/lockd/svcsubs.c | 8 +++++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 0bf4afb71d2..4990223a3e1 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -110,16 +110,13 @@ 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; - } - nlm_get_host(host); - mutex_unlock(&nlm_host_mutex); - return host; + if (hp != nlm_hosts + hash) { + *hp = host->h_next; + host->h_next = nlm_hosts[hash]; + nlm_hosts[hash] = host; } + nlm_get_host(host); + goto out; } /* Sadly, the host isn't in our hash table yet. See if diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index a92dd98f840..c8308bccd31 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -115,7 +115,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, * the file. */ if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) { - dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr)); + dprintk("lockd: open failed (error %d)\n", nfserr); goto out_free; } @@ -313,10 +313,12 @@ 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, NLM_ACT_UNLOCK)) { printk(KERN_WARNING - "lockd: couldn't remove all locks held by %s", + "lockd: couldn't remove all locks held by %s\n", host->h_name); + BUG(); + } } /* -- GitLab From 5c8dd29ca7fc7483690cef4306549742d534f2a2 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:55 -0700 Subject: [PATCH 0497/1619] [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(-) diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 54e63ddef04..a4ab6dd7661 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 4990223a3e1..3cd96e2e125 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 7d835ad8107..b8525fb6293 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 12291ab1e72..66e7b0b3430 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 ab2ffc8a0b4..a41eb841428 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 *); -- GitLab From 9502c52259f7038b6c1e31532e22884716a56b1a Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:56 -0700 Subject: [PATCH 0498/1619] [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(-) diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e27981403fb..626b6c116a6 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 1080bb6ae31..d93b074668c 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 */ }; /* -- GitLab From 0cea32761a2f954c6d42ca79d7d1e6b9663b1e4a Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:56 -0700 Subject: [PATCH 0499/1619] [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(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 3cd96e2e125..4449ef0b783 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 a41eb841428..c8635d84d5d 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 */ -- GitLab From 68a2d76cea4234bc027df23085d9df4f2171f7fc Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:57 -0700 Subject: [PATCH 0500/1619] [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(-) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 3127ae9e435..7209712f383 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 c8308bccd31..a92fc581314 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 c8635d84d5d..2e740f6a2f7 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 */ }; -- GitLab From 07ba80635117c136714084e019375aa508365375 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:58 -0700 Subject: [PATCH 0501/1619] [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(-) diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index a92fc581314..91731353dfa 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 2e740f6a2f7..777a91e1ac8 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 */ }; /* -- GitLab From f2af793db02d2c2f677bdb5bf8e0efdcbf9c0256 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:59 -0700 Subject: [PATCH 0502/1619] [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(-) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 7209712f383..1f91567a1b8 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 27288c83da9..b9926ce8782 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 91731353dfa..bb13a48210f 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 777a91e1ac8..8c1145669d0 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 c75a424ebe4..cd7816e74c0 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 */ -- GitLab From c53c1bb94f30cecee79ca0a8e9977640338283be Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:00 -0700 Subject: [PATCH 0503/1619] [PATCH] knfsd: lockd: Add nlm_destroy_host This patch moves the host destruction code out of nlm_host_gc into a function of its own. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 4449ef0b783..3b55fe5e94a 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -164,6 +164,34 @@ out: return host; } +/* + * Destroy a host + */ +static void +nlm_destroy_host(struct nlm_host *host) +{ + struct rpc_clnt *clnt; + + BUG_ON(!list_empty(&host->h_lockowners)); + BUG_ON(atomic_read(&host->h_count)); + + /* + * Release NSM handle and unmonitor host. + */ + nsm_unmonitor(host); + + if ((clnt = host->h_rpcclnt) != NULL) { + if (atomic_read(&clnt->cl_users)) { + printk(KERN_WARNING + "lockd: active RPC handle\n"); + clnt->cl_dead = 1; + } else { + rpc_destroy_client(host->h_rpcclnt); + } + } + kfree(host); +} + struct nlm_host * nlm_find_client(void) { @@ -400,7 +428,6 @@ nlm_gc_hosts(void) struct hlist_head *chain; struct hlist_node *pos, *next; struct nlm_host *host; - struct rpc_clnt *clnt; dprintk("lockd: host garbage collection\n"); for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { @@ -423,21 +450,7 @@ nlm_gc_hosts(void) dprintk("lockd: delete host %s\n", host->h_name); hlist_del_init(&host->h_hash); - /* - * Unmonitor unless host was invalidated (i.e. lockd restarted) - */ - nsm_unmonitor(host); - - if ((clnt = host->h_rpcclnt) != NULL) { - if (atomic_read(&clnt->cl_users)) { - printk(KERN_WARNING - "lockd: active RPC handle\n"); - clnt->cl_dead = 1; - } else { - rpc_destroy_client(host->h_rpcclnt); - } - } - kfree(host); + nlm_destroy_host(host); nrhosts--; } } -- GitLab From 350fce8dbf43f7d441b77366851c9ce3cd28d6dc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:16:00 -0700 Subject: [PATCH 0504/1619] [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(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 3b55fe5e94a..1bf384307d1 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 bb13a48210f..a1c7c084841 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 8c1145669d0..1fcf936d75b 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 *); -- GitLab From abd1f50094cad9dff6d68ada98b495549f52fc30 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:01 -0700 Subject: [PATCH 0505/1619] [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(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 1bf384307d1..a1423c66df0 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 626b6c116a6..709cf7c8054 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 3cc369e5693..a3b7602cd38 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 1fcf936d75b..7be7aeaeee5 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 d93b074668c..daef509bb9b 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; }; /* -- GitLab From 031d869d0e0be18cfe35526be5608225b8f0a7be Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:02 -0700 Subject: [PATCH 0506/1619] [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(-) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 7e6f22e2a3b..3d84f600b63 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 7be7aeaeee5..a345650e562 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 -- GitLab From 39be4502cb75dc26007fe1659735b26c8e63fcc6 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:03 -0700 Subject: [PATCH 0507/1619] [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(-) diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index b8525fb6293..fa370f6eb07 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 1f91567a1b8..3d2b8a831be 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 66e7b0b3430..75b2c81bcb9 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 a345650e562..5920ecaeed6 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 -- GitLab From 460f5cac1e24e947509b6112c99c5bc9ff687b45 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:03 -0700 Subject: [PATCH 0508/1619] [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(-) diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 709cf7c8054..e0179f8c327 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 a3b7602cd38..634139232aa 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 daef509bb9b..fc61d40964d 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 */ -- GitLab From 0ade060ee51b9b6cf18d580405dc9ab90067f69f Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:04 -0700 Subject: [PATCH 0509/1619] [PATCH] knfsd: lockd: fix use of h_nextrebind nlmclnt_recovery would try to force a portmap rebind by setting host->h_nextrebind to 0. The right thing to do here is to set it to the current time. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index a4ab6dd7661..e8c7765419e 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -184,7 +184,7 @@ restart: /* Force a portmap getport - the peer's lockd will * most likely end up on a different port. */ - host->h_nextrebind = 0; + host->h_nextrebind = jiffies; nlm_rebind_host(host); /* First, reclaim all locks that have been granted. */ -- GitLab From bc5fea4299b8bda5f73c6f79dc35d388caf8bced Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:05 -0700 Subject: [PATCH 0510/1619] [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(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 71108da2e54..9187755661d 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 f813b054f4a..d4bdc00c116 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 74e52c245da..d6288e89fd9 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 b252401c860..550441d13a0 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; + } } } -- GitLab From 89e63ef609fb0064a47281e31e38010159c32d57 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Wed, 4 Oct 2006 02:16:06 -0700 Subject: [PATCH 0511/1619] [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(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index a1423c66df0..0257a559452 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 3d2b8a831be..814c6064c9e 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 a1c7c084841..514f5f20701 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 5920ecaeed6..2909619c029 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 */ }; /* -- GitLab From 3c15a486643a103eaf068e5fb3b7f9d720d579a7 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:06 -0700 Subject: [PATCH 0512/1619] [PATCH] knfsd: svcrpc: gss: factor out some common wrapping code Factor out some common code from the integrity and privacy cases. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/auth_gss/svcauth_gss.c | 43 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 558692d7e46..eeb1cce9664 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1147,6 +1147,25 @@ out: return ret; } +u32 * +svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd) +{ + u32 *p; + + p = gsd->body_start; + gsd->body_start = NULL; + /* move accept_stat to right place: */ + memcpy(p, p + 2, 4); + /* Don't wrap in failure case: */ + /* Counting on not getting here if call was not even accepted! */ + if (*p != rpc_success) { + resbuf->head[0].iov_len -= 2 * 4; + return NULL; + } + p++; + return p; +} + static inline int svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) { @@ -1160,17 +1179,9 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) int integ_offset, integ_len; int stat = -EINVAL; - p = gsd->body_start; - gsd->body_start = NULL; - /* move accept_stat to right place: */ - memcpy(p, p + 2, 4); - /* Don't wrap in failure case: */ - /* Counting on not getting here if call was not even accepted! */ - if (*p != rpc_success) { - resbuf->head[0].iov_len -= 2 * 4; + p = svcauth_gss_prepare_to_wrap(resbuf, gsd); + if (p == NULL) goto out; - } - p++; integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base; integ_len = resbuf->len - integ_offset; BUG_ON(integ_len % 4); @@ -1222,17 +1233,9 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) int offset; int pad; - p = gsd->body_start; - gsd->body_start = NULL; - /* move accept_stat to right place: */ - memcpy(p, p + 2, 4); - /* Don't wrap in failure case: */ - /* Counting on not getting here if call was not even accepted! */ - if (*p != rpc_success) { - resbuf->head[0].iov_len -= 2 * 4; + p = svcauth_gss_prepare_to_wrap(resbuf, gsd); + if (p == NULL) return 0; - } - p++; len = p++; offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base; *p++ = htonl(gc->gc_seq); -- GitLab From 5b304bc5bfccc82b856e876e829c260df8e67ff2 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:07 -0700 Subject: [PATCH 0513/1619] [PATCH] knfsd: svcrpc: gss: fix failure on SVC_DENIED in integrity case If the request is denied after gss_accept was called, we shouldn't try to wrap the reply. We were checking the accept_stat but not the reply_stat. To check the reply_stat in _release, we need a pointer to before (rather than after) the verifier, so modify body_start appropriately. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/auth_gss/svcauth_gss.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index eeb1cce9664..447d9aef460 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -903,9 +903,9 @@ out_seq: struct gss_svc_data { /* decoded gss client cred: */ struct rpc_gss_wire_cred clcred; - /* pointer to the beginning of the procedure-specific results, - * which may be encrypted/checksummed in svcauth_gss_release: */ - __be32 *body_start; + /* save a pointer to the beginning of the encoded verifier, + * for use in encryption/checksumming in svcauth_gss_release: */ + __be32 *verf_start; struct rsc *rsci; }; @@ -968,7 +968,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) if (!svcdata) goto auth_err; rqstp->rq_auth_data = svcdata; - svcdata->body_start = NULL; + svcdata->verf_start = NULL; svcdata->rsci = NULL; gc = &svcdata->clcred; @@ -1097,6 +1097,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) goto complete; case RPC_GSS_PROC_DATA: *authp = rpcsec_gsserr_ctxproblem; + svcdata->verf_start = resv->iov_base + resv->iov_len; if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq)) goto auth_err; rqstp->rq_cred = rsci->cred; @@ -1110,7 +1111,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) gc->gc_seq, rsci->mechctx)) goto auth_err; /* placeholders for length and seq. number: */ - svcdata->body_start = resv->iov_base + resv->iov_len; svc_putnl(resv, 0); svc_putnl(resv, 0); break; @@ -1119,7 +1119,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) gc->gc_seq, rsci->mechctx)) goto auth_err; /* placeholders for length and seq. number: */ - svcdata->body_start = resv->iov_base + resv->iov_len; svc_putnl(resv, 0); svc_putnl(resv, 0); break; @@ -1150,14 +1149,21 @@ out: u32 * svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd) { - u32 *p; + u32 *p, verf_len; - p = gsd->body_start; - gsd->body_start = NULL; + p = gsd->verf_start; + gsd->verf_start = NULL; + + /* If the reply stat is nonzero, don't wrap: */ + if (*(p-1) != rpc_success) + return NULL; + /* Skip the verifier: */ + p += 1; + verf_len = ntohl(*p++); + p += XDR_QUADLEN(verf_len); /* move accept_stat to right place: */ memcpy(p, p + 2, 4); - /* Don't wrap in failure case: */ - /* Counting on not getting here if call was not even accepted! */ + /* Also don't wrap if the accept stat is nonzero: */ if (*p != rpc_success) { resbuf->head[0].iov_len -= 2 * 4; return NULL; @@ -1283,7 +1289,7 @@ svcauth_gss_release(struct svc_rqst *rqstp) if (gc->gc_proc != RPC_GSS_PROC_DATA) goto out; /* Release can be called twice, but we only wrap once. */ - if (gsd->body_start == NULL) + if (gsd->verf_start == NULL) goto out; /* normally not set till svc_send, but we need it here: */ /* XXX: what for? Do we mess it up the moment we call svc_putu32 -- GitLab From 8f8e05c5708d7e9017c47f395f8b1498f7f52922 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:08 -0700 Subject: [PATCH 0514/1619] [PATCH] knfsd: svcrpc: use consistent variable name for the reply state The rpc reply has multiple levels of error returns. The code here contributes to the confusion by using "accept_statp" for a pointer to what the rfc (and wireshark, etc.) refer to as the "reply_stat". (The confusion is compounded by the fact that the rfc also has an "accept_stat" which follows the reply_stat in the succesful case.) Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/svc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 550441d13a0..c2c8bb20d07 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -699,7 +699,7 @@ svc_process(struct svc_rqst *rqstp) u32 dir, prog, vers, proc; __be32 auth_stat, rpc_stat; int auth_res; - __be32 *accept_statp; + __be32 *reply_statp; rpc_stat = rpc_success; @@ -740,7 +740,7 @@ svc_process(struct svc_rqst *rqstp) goto err_bad_rpc; /* Save position in case we later decide to reject: */ - accept_statp = resv->iov_base + resv->iov_len; + reply_statp = resv->iov_base + resv->iov_len; svc_putnl(resv, 0); /* ACCEPT */ @@ -888,7 +888,7 @@ err_bad_auth: dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); serv->sv_stats->rpcbadauth++; /* Restore write pointer to location of accept status: */ - xdr_ressize_check(rqstp, accept_statp); + xdr_ressize_check(rqstp, reply_statp); svc_putnl(resv, 1); /* REJECT */ svc_putnl(resv, 1); /* AUTH_ERROR */ svc_putnl(resv, ntohl(auth_stat)); /* status */ -- GitLab From f38b20c64519bb812a49b9ef4e10d90367a5af5c Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:09 -0700 Subject: [PATCH 0515/1619] [PATCH] knfsd: nfsd4: refactor exp_pseudoroot We could be using more common code in exp_pseudoroot(). This will also simplify some changes we need to make later. 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 | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index cfe141e5d75..ac5149d2537 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1048,30 +1048,24 @@ int exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, struct cache_req *creq) { - struct svc_expkey *fsid_key; struct svc_export *exp; int rv; u32 fsidv[2]; mk_fsid_v1(fsidv, 0); - fsid_key = exp_find_key(clp, 1, fsidv, creq); - if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN) + exp = exp_find(clp, 1, fsidv, creq); + if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) return nfserr_dropit; - if (!fsid_key || IS_ERR(fsid_key)) - return nfserr_perm; - - exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq); if (exp == NULL) rv = nfserr_perm; else if (IS_ERR(exp)) rv = nfserrno(PTR_ERR(exp)); else { rv = fh_compose(fhp, exp, - fsid_key->ek_dentry, NULL); + exp->ex_dentry, NULL); exp_put(exp); } - cache_put(&fsid_key->h, &svc_expkey_cache); return rv; } -- GitLab From d0ebd9c0e71d20ea8c2b4a071d2a2b4878ef07d6 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:10 -0700 Subject: [PATCH 0516/1619] [PATCH] knfsd: nfsd4: clean up exp_pseudoroot The previous patch enables some minor simplification here. 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 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index ac5149d2537..597b3cbf8b0 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1058,14 +1058,11 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) return nfserr_dropit; if (exp == NULL) - rv = nfserr_perm; + return nfserr_perm; else if (IS_ERR(exp)) - rv = nfserrno(PTR_ERR(exp)); - else { - rv = fh_compose(fhp, exp, - exp->ex_dentry, NULL); - exp_put(exp); - } + return nfserrno(PTR_ERR(exp)); + rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); + exp_put(exp); return rv; } -- GitLab From 09229edb68a3961db54174a2725055bd1589b4b8 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:11 -0700 Subject: [PATCH 0517/1619] [PATCH] knfsd: nfsd4: acls: relax the nfsv4->posix mapping Use a different nfsv4->(draft posix) acl mapping which is 1. completely backwards compatible, 2. accepts any nfsv4 acl, and 3. errs on the side of restricting permissions. In detail: 1. completely backwards compatible: The new mapping produces the same result on any acl produced by the existing (draft posix)->nfsv4 mapping; the one exception is that we no longer attempt to guess the value of the mask by assuming certain denies represent the mask. Since the server still keeps track of the mask locally, sequences of chmod's will still be handled fine; the only thing this will change is sequences of chmod's with intervening read-modify-writes of the acl. That last case just isn't worth the trouble and the possible misrepresentations of the user's intent (if we guess that a certain deny indicates masking is in effect when it really isn't). 2. accepts any nfsv4 acl: That's not quite true: we still reject acls that use combinations of inheritance flags that we don't support. We also reject acls that attempt to explicitly deny read_acl or read_attributes permissions, or that attempt to deny write_acl or write_attributes permissions to the owner of the file. 3. errs on the side of restricting permissions: one exception to this last rule: we totally ignore some bits (write_owner, synchronize, read_named_attributes, etc.) that are completely alien to our filesystem semantics, in some cases even if that would mean ignoring an explicit deny that we have no intention of enforcing. Excepting that, the posix acl produced should be the most permissive acl that is not more permissive than the given nfsv4 acl. And the new code's shorter, too. Neato. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4acl.c | 627 ++++++++++++++++++++-------------------------- 1 file changed, 273 insertions(+), 354 deletions(-) diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index edb107e61b9..f2f66b3da7a 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -96,24 +96,26 @@ deny_mask(u32 allow_mask, unsigned int flags) /* XXX: modify functions to return NFS errors; they're only ever * used by nfs code, after all.... */ -static int -mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) +/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the + * side of being more restrictive, so the mode bit mapping below is + * pessimistic. An optimistic version would be needed to handle DENY's, + * but we espect to coalesce all ALLOWs and DENYs before mapping to mode + * bits. */ + +static void +low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) { - u32 ignore = 0; + u32 write_mode = NFS4_WRITE_MODE; - if (!(flags & NFS4_ACL_DIR)) - ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */ - perm |= ignore; + if (flags & NFS4_ACL_DIR) + write_mode |= NFS4_ACE_DELETE_CHILD; *mode = 0; if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) *mode |= ACL_READ; - if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE) + if ((perm & write_mode) == write_mode) *mode |= ACL_WRITE; if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) *mode |= ACL_EXECUTE; - if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags))) - return -EINVAL; - return 0; } struct ace_container { @@ -338,38 +340,6 @@ sort_pacl(struct posix_acl *pacl) return; } -static int -write_pace(struct nfs4_ace *ace, struct posix_acl *pacl, - struct posix_acl_entry **pace, short tag, unsigned int flags) -{ - struct posix_acl_entry *this = *pace; - - if (*pace == pacl->a_entries + pacl->a_count) - return -EINVAL; /* fell off the end */ - (*pace)++; - this->e_tag = tag; - if (tag == ACL_USER_OBJ) - flags |= NFS4_ACL_OWNER; - if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags)) - return -EINVAL; - this->e_id = (tag == ACL_USER || tag == ACL_GROUP ? - ace->who : ACL_UNDEFINED_ID); - return 0; -} - -static struct nfs4_ace * -get_next_v4_ace(struct list_head **p, struct list_head *head) -{ - struct nfs4_ace *ace; - - *p = (*p)->next; - if (*p == head) - return NULL; - ace = list_entry(*p, struct nfs4_ace, l_ace); - - return ace; -} - int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, struct posix_acl **dpacl, unsigned int flags) @@ -429,349 +399,311 @@ out: return error; } +/* + * While processing the NFSv4 ACE, this maintains bitmasks representing + * which permission bits have been allowed and which denied to a given + * entity: */ +struct posix_ace_state { + u32 allow; + u32 deny; +}; + +struct posix_user_ace_state { + uid_t uid; + struct posix_ace_state perms; +}; + +struct posix_ace_state_array { + int n; + struct posix_user_ace_state aces[]; +}; + +/* + * While processing the NFSv4 ACE, this maintains the partial permissions + * calculated so far: */ + +struct posix_acl_state { + struct posix_ace_state owner; + struct posix_ace_state group; + struct posix_ace_state other; + struct posix_ace_state everyone; + struct posix_ace_state mask; /* Deny unused in this case */ + struct posix_ace_state_array *users; + struct posix_ace_state_array *groups; +}; + static int -same_who(struct nfs4_ace *a, struct nfs4_ace *b) +init_state(struct posix_acl_state *state, int cnt) { - return a->whotype == b->whotype && - (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who); + int alloc; + + memset(state, 0, sizeof(struct posix_acl_state)); + /* + * In the worst case, each individual acl could be for a distinct + * named user or group, but we don't no which, so we allocate + * enough space for either: + */ + alloc = sizeof(struct posix_ace_state_array) + + cnt*sizeof(struct posix_ace_state); + state->users = kzalloc(alloc, GFP_KERNEL); + if (!state->users) + return -ENOMEM; + state->groups = kzalloc(alloc, GFP_KERNEL); + if (!state->groups) { + kfree(state->users); + return -ENOMEM; + } + return 0; } -static int -complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny, - unsigned int flags) -{ - int ignore = 0; - if (!(flags & NFS4_ACL_DIR)) - ignore |= NFS4_ACE_DELETE_CHILD; - return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags), - ignore|deny->access_mask) && - allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && - deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE && - allow->flag == deny->flag && - same_who(allow, deny); +static void +free_state(struct posix_acl_state *state) { + kfree(state->users); + kfree(state->groups); } -static inline int -user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate) { - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; - - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace2type(ace) != ACL_USER_OBJ) - goto out; - error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace2 = get_next_v4_ace(p, &n4acl->ace_head); - if (ace2 == NULL) - goto out; - if (!complementary_ace_pair(ace, ace2, flags)) - goto out; - error = 0; -out: - return error; + state->mask.allow |= astate->allow; } -static inline int -users_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct nfs4_ace **mask_ace, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) -{ - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; +/* + * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS, + * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate + * to traditional read/write/execute permissions. + * + * It's problematic to reject acls that use certain mode bits, because it + * places the burden on users to learn the rules about which bits one + * particular server sets, without giving the user a lot of help--we return an + * error that could mean any number of different things. To make matters + * worse, the problematic bits might be introduced by some application that's + * automatically mapping from some other acl model. + * + * So wherever possible we accept anything, possibly erring on the side of + * denying more permissions than necessary. + * + * However we do reject *explicit* DENY's of a few bits representing + * permissions we could never deny: + */ - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - while (ace2type(ace) == ACL_USER) { - if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) - goto out; - if (*mask_ace && - !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) - goto out; - *mask_ace = ace; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) - goto out; - error = write_pace(ace, pacl, pace, ACL_USER, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace2 = get_next_v4_ace(p, &n4acl->ace_head); - if (ace2 == NULL) - goto out; - if (!complementary_ace_pair(ace, ace2, flags)) - goto out; - if ((*mask_ace)->flag != ace2->flag || - !same_who(*mask_ace, ace2)) - goto out; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - } - error = 0; -out: - return error; +static inline int check_deny(u32 mask, int isowner) +{ + if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL)) + return -EINVAL; + if (!isowner) + return 0; + if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)) + return -EINVAL; + return 0; } -static inline int -group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct nfs4_ace **mask_ace, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static struct posix_acl * +posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) { - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; - struct ace_container *ac; - struct list_head group_l; - - INIT_LIST_HEAD(&group_l); - ace = list_entry(*p, struct nfs4_ace, l_ace); - - /* group owner (mask and allow aces) */ + struct posix_acl_entry *pace; + struct posix_acl *pacl; + int nace; + int i, error = 0; - if (pacl->a_count != 3) { - /* then the group owner should be preceded by mask */ - if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) - goto out; - if (*mask_ace && - !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) - goto out; - *mask_ace = ace; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; + nace = 4 + state->users->n + state->groups->n; + pacl = posix_acl_alloc(nace, GFP_KERNEL); + if (!pacl) + return ERR_PTR(-ENOMEM); - if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace)) - goto out; + pace = pacl->a_entries; + pace->e_tag = ACL_USER_OBJ; + error = check_deny(state->owner.deny, 1); + if (error) + goto out_err; + low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; + + for (i=0; i < state->users->n; i++) { + pace++; + pace->e_tag = ACL_USER; + error = check_deny(state->users->aces[i].perms.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->users->aces[i].perms.allow, + &pace->e_perm, flags); + pace->e_id = state->users->aces[i].uid; + add_to_mask(state, &state->users->aces[i].perms); } - if (ace2type(ace) != ACL_GROUP_OBJ) - goto out; - - ac = kmalloc(sizeof(*ac), GFP_KERNEL); - error = -ENOMEM; - if (ac == NULL) - goto out; - ac->ace = ace; - list_add_tail(&ac->ace_l, &group_l); - - error = -EINVAL; - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) - goto out; - - error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags); - if (error < 0) - goto out; - - error = -EINVAL; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - - /* groups (mask and allow aces) */ - - while (ace2type(ace) == ACL_GROUP) { - if (*mask_ace == NULL) - goto out; - - if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE || - !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) - goto out; - *mask_ace = ace; + pace++; + pace->e_tag = ACL_GROUP_OBJ; + error = check_deny(state->group.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; + add_to_mask(state, &state->group); + + for (i=0; i < state->groups->n; i++) { + pace++; + pace->e_tag = ACL_GROUP; + error = check_deny(state->groups->aces[i].perms.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->groups->aces[i].perms.allow, + &pace->e_perm, flags); + pace->e_id = state->groups->aces[i].uid; + add_to_mask(state, &state->groups->aces[i].perms); + } - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - ac = kmalloc(sizeof(*ac), GFP_KERNEL); - error = -ENOMEM; - if (ac == NULL) - goto out; - error = -EINVAL; - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE || - !same_who(ace, *mask_ace)) - goto out; + pace++; + pace->e_tag = ACL_MASK; + low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; - ac->ace = ace; - list_add_tail(&ac->ace_l, &group_l); + pace++; + pace->e_tag = ACL_OTHER; + error = check_deny(state->other.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; - error = write_pace(ace, pacl, pace, ACL_GROUP, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - } + return pacl; +out_err: + posix_acl_release(pacl); + return ERR_PTR(error); +} - /* group owner (deny ace) */ +static inline void allow_bits(struct posix_ace_state *astate, u32 mask) +{ + /* Allow all bits in the mask not already denied: */ + astate->allow |= mask & ~astate->deny; +} - if (ace2type(ace) != ACL_GROUP_OBJ) - goto out; - ac = list_entry(group_l.next, struct ace_container, ace_l); - ace2 = ac->ace; - if (!complementary_ace_pair(ace2, ace, flags)) - goto out; - list_del(group_l.next); - kfree(ac); +static inline void deny_bits(struct posix_ace_state *astate, u32 mask) +{ + /* Deny all bits in the mask not already allowed: */ + astate->deny |= mask & ~astate->allow; +} - /* groups (deny aces) */ +static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid) +{ + int i; - while (!list_empty(&group_l)) { - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace2type(ace) != ACL_GROUP) - goto out; - ac = list_entry(group_l.next, struct ace_container, ace_l); - ace2 = ac->ace; - if (!complementary_ace_pair(ace2, ace, flags)) - goto out; - list_del(group_l.next); - kfree(ac); - } + for (i = 0; i < a->n; i++) + if (a->aces[i].uid == uid) + return i; + /* Not found: */ + a->n++; + a->aces[i].uid = uid; + a->aces[i].perms.allow = state->everyone.allow; + a->aces[i].perms.deny = state->everyone.deny; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace2type(ace) != ACL_OTHER) - goto out; - error = 0; -out: - while (!list_empty(&group_l)) { - ac = list_entry(group_l.next, struct ace_container, ace_l); - list_del(group_l.next); - kfree(ac); - } - return error; + return i; } -static inline int -mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct nfs4_ace **mask_ace, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static void deny_bits_array(struct posix_ace_state_array *a, u32 mask) { - int error = -EINVAL; - struct nfs4_ace *ace; + int i; - ace = list_entry(*p, struct nfs4_ace, l_ace); - if (pacl->a_count != 3) { - if (*mask_ace == NULL) - goto out; - (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags); - write_pace(*mask_ace, pacl, pace, ACL_MASK, flags); - } - error = 0; -out: - return error; + for (i=0; i < a->n; i++) + deny_bits(&a->aces[i].perms, mask); } -static inline int -other_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static void allow_bits_array(struct posix_ace_state_array *a, u32 mask) { - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; + int i; - ace = list_entry(*p, struct nfs4_ace, l_ace); - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) - goto out; - error = write_pace(ace, pacl, pace, ACL_OTHER, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace2 = get_next_v4_ace(p, &n4acl->ace_head); - if (ace2 == NULL) - goto out; - if (!complementary_ace_pair(ace, ace2, flags)) - goto out; - error = 0; -out: - return error; + for (i=0; i < a->n; i++) + allow_bits(&a->aces[i].perms, mask); } -static int -calculate_posix_ace_count(struct nfs4_acl *n4acl) +static void process_one_v4_ace(struct posix_acl_state *state, + struct nfs4_ace *ace) { - if (n4acl->naces == 6) /* owner, owner group, and other only */ - return 3; - else { /* Otherwise there must be a mask entry. */ - /* Also, the remaining entries are for named users and - * groups, and come in threes (mask, allow, deny): */ - if (n4acl->naces < 7) - return -EINVAL; - if ((n4acl->naces - 7) % 3) - return -EINVAL; - return 4 + (n4acl->naces - 7)/3; + u32 mask = ace->access_mask; + int i; + + switch (ace2type(ace)) { + case ACL_USER_OBJ: + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->owner, mask); + } else { + deny_bits(&state->owner, mask); + } + break; + case ACL_USER: + i = find_uid(state, state->users, ace->who); + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->users->aces[i].perms, mask); + } else { + deny_bits(&state->users->aces[i].perms, mask); + mask = state->users->aces[i].perms.deny; + deny_bits(&state->owner, mask); + } + break; + case ACL_GROUP_OBJ: + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->group, mask); + } else { + deny_bits(&state->group, mask); + mask = state->group.deny; + deny_bits(&state->owner, mask); + deny_bits(&state->everyone, mask); + deny_bits_array(state->users, mask); + deny_bits_array(state->groups, mask); + } + break; + case ACL_GROUP: + i = find_uid(state, state->groups, ace->who); + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->groups->aces[i].perms, mask); + } else { + deny_bits(&state->groups->aces[i].perms, mask); + mask = state->groups->aces[i].perms.deny; + deny_bits(&state->owner, mask); + deny_bits(&state->group, mask); + deny_bits(&state->everyone, mask); + deny_bits_array(state->users, mask); + deny_bits_array(state->groups, mask); + } + break; + case ACL_OTHER: + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->owner, mask); + allow_bits(&state->group, mask); + allow_bits(&state->other, mask); + allow_bits(&state->everyone, mask); + allow_bits_array(state->users, mask); + allow_bits_array(state->groups, mask); + } else { + deny_bits(&state->owner, mask); + deny_bits(&state->group, mask); + deny_bits(&state->other, mask); + deny_bits(&state->everyone, mask); + deny_bits_array(state->users, mask); + deny_bits_array(state->groups, mask); + } } } - static struct posix_acl * _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) { + struct posix_acl_state state; struct posix_acl *pacl; - int error = -EINVAL, nace = 0; - struct list_head *p; - struct nfs4_ace *mask_ace = NULL; - struct posix_acl_entry *pace; - - nace = calculate_posix_ace_count(n4acl); - if (nace < 0) - goto out_err; - - pacl = posix_acl_alloc(nace, GFP_KERNEL); - error = -ENOMEM; - if (pacl == NULL) - goto out_err; - - pace = &pacl->a_entries[0]; - p = &n4acl->ace_head; - - error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags); - if (error) - goto out_acl; - - error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); - if (error) - goto out_acl; + struct nfs4_ace *ace; + int ret; - error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace, - flags); - if (error) - goto out_acl; + ret = init_state(&state, n4acl->naces); + if (ret) + return ERR_PTR(ret); - error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); - if (error) - goto out_acl; - error = other_from_v4(n4acl, &p, pacl, &pace, flags); - if (error) - goto out_acl; + list_for_each_entry(ace, &n4acl->ace_head, l_ace) + process_one_v4_ace(&state, ace); - error = -EINVAL; - if (p->next != &n4acl->ace_head) - goto out_acl; - if (pace != pacl->a_entries + pacl->a_count) - goto out_acl; + pacl = posix_state_to_acl(&state, flags); - sort_pacl(pacl); + free_state(&state); - return pacl; -out_acl: - posix_acl_release(pacl); -out_err: - pacl = ERR_PTR(error); + if (!IS_ERR(pacl)) + sort_pacl(pacl); return pacl; } @@ -785,6 +717,10 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) list_for_each_safe(h, n, &acl->ace_head) { ace = list_entry(h, struct nfs4_ace, l_ace); + if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && + ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) + return -EINVAL; + if ((ace->flag & NFS4_INHERITANCE_FLAGS) != NFS4_INHERITANCE_FLAGS) continue; @@ -930,23 +866,6 @@ nfs4_acl_write_who(int who, char *p) return -1; } -static inline int -match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who) -{ - switch (ace->whotype) { - case NFS4_ACL_WHO_NAMED: - return who == ace->who; - case NFS4_ACL_WHO_OWNER: - return who == owner; - case NFS4_ACL_WHO_GROUP: - return who == group; - case NFS4_ACL_WHO_EVERYONE: - return 1; - default: - return 0; - } -} - EXPORT_SYMBOL(nfs4_acl_new); EXPORT_SYMBOL(nfs4_acl_free); EXPORT_SYMBOL(nfs4_acl_add_ace); -- GitLab From b548edc2dd9440c561f3302cb9f212ef2d06a8ef Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:12 -0700 Subject: [PATCH 0518/1619] [PATCH] knfsd: nfsd4: acls: fix inheritance We can be a little more flexible about the flags allowed for inheritance (in particular, we can deal with either the presence or the absence of INHERIT_ONLY), but we should probably reject other combinations that we don't understand. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4acl.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index f2f66b3da7a..59fdd9c1d3e 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -63,6 +63,8 @@ #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE) +#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP) + #define MASK_EQUAL(mask1, mask2) \ ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) ) @@ -721,22 +723,37 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) return -EINVAL; - if ((ace->flag & NFS4_INHERITANCE_FLAGS) - != NFS4_INHERITANCE_FLAGS) - continue; + if (ace->flag & ~NFS4_SUPPORTED_FLAGS) + return -EINVAL; - error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, + switch (ace->flag & NFS4_INHERITANCE_FLAGS) { + case 0: + /* Leave this ace in the effective acl: */ + continue; + case NFS4_INHERITANCE_FLAGS: + /* Add this ace to the default acl and remove it + * from the effective acl: */ + error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, ace->access_mask, ace->whotype, ace->who); - if (error < 0) - goto out; - - list_del(h); - kfree(ace); - acl->naces--; + if (error) + return error; + list_del(h); + kfree(ace); + acl->naces--; + break; + case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE: + /* Add this ace to the default, but leave it in + * the effective acl as well: */ + error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, + ace->access_mask, ace->whotype, ace->who); + if (error) + return error; + break; + default: + return -EINVAL; + } } - -out: - return error; + return 0; } static short -- GitLab From f3b64eb6efb1ef46f6629b66a429e7f2b5955003 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:13 -0700 Subject: [PATCH 0519/1619] [PATCH] knfsd: nfsd4: acls: simplify nfs4_acl_nfsv4_to_posix interface There's no need to handle the case where the caller passes in null for pacl or dpacl; no caller does that, because it would be a dumb thing to do. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4acl.c | 48 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 59fdd9c1d3e..105544eac9a 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -360,39 +360,33 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, if (error < 0) goto out_acl; - if (pacl != NULL) { - if (acl->naces == 0) { - error = -ENODATA; - goto try_dpacl; - } - - *pacl = _nfsv4_to_posix_one(acl, flags); - if (IS_ERR(*pacl)) { - error = PTR_ERR(*pacl); - *pacl = NULL; - goto out_acl; - } + if (acl->naces == 0) { + error = -ENODATA; + goto try_dpacl; } + *pacl = _nfsv4_to_posix_one(acl, flags); + if (IS_ERR(*pacl)) { + error = PTR_ERR(*pacl); + *pacl = NULL; + goto out_acl; + } try_dpacl: - if (dpacl != NULL) { - if (dacl->naces == 0) { - if (pacl == NULL || *pacl == NULL) - error = -ENODATA; - goto out_acl; - } - - error = 0; - *dpacl = _nfsv4_to_posix_one(dacl, flags); - if (IS_ERR(*dpacl)) { - error = PTR_ERR(*dpacl); - *dpacl = NULL; - goto out_acl; - } + if (dacl->naces == 0) { + if (pacl == NULL || *pacl == NULL) + error = -ENODATA; + goto out_acl; } + error = 0; + *dpacl = _nfsv4_to_posix_one(dacl, flags); + if (IS_ERR(*dpacl)) { + error = PTR_ERR(*dpacl); + *dpacl = NULL; + goto out_acl; + } out_acl: - if (error && pacl) { + if (error) { posix_acl_release(*pacl); *pacl = NULL; } -- GitLab From b66285cee3f9abad26cca6c9b848e1ad6b792d94 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:14 -0700 Subject: [PATCH 0520/1619] [PATCH] knfsd: nfsd4: acls: fix handling of zero-length acls It is legal to have zero-length NFSv4 acls; they just deny everything. Also, nfs4_acl_nfsv4_to_posix will always return with pacl and dpacl set on success, so the caller doesn't need to check this. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4acl.c | 15 +-------------- fs/nfsd/vfs.c | 10 ++++------ 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 105544eac9a..5d94555cdc8 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -357,33 +357,20 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, goto out; error = nfs4_acl_split(acl, dacl); - if (error < 0) + if (error) goto out_acl; - if (acl->naces == 0) { - error = -ENODATA; - goto try_dpacl; - } - *pacl = _nfsv4_to_posix_one(acl, flags); if (IS_ERR(*pacl)) { error = PTR_ERR(*pacl); *pacl = NULL; goto out_acl; } -try_dpacl: - if (dacl->naces == 0) { - if (pacl == NULL || *pacl == NULL) - error = -ENODATA; - goto out_acl; - } - error = 0; *dpacl = _nfsv4_to_posix_one(dacl, flags); if (IS_ERR(*dpacl)) { error = PTR_ERR(*dpacl); *dpacl = NULL; - goto out_acl; } out_acl: if (error) { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 137565a136d..1141bd29e4e 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -447,13 +447,11 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, } else if (error < 0) goto out_nfserr; - if (pacl) { - error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); - if (error < 0) - goto out_nfserr; - } + error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); + if (error < 0) + goto out_nfserr; - if (dpacl) { + if (S_ISDIR(inode->i_mode)) { error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); if (error < 0) goto out_nfserr; -- GitLab From 6b54dae2b0defb30babb0fe87b13463b9f4b2907 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:16:15 -0700 Subject: [PATCH 0521/1619] [PATCH] knfsd: lockd: fix refount on nsm If nlm_lookup_host finds what it is looking for it exits with an extra reference on the matching 'nsm' structure. So don't actually count the reference until we are (fairly) sure it is going to be used. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 0257a559452..fb24a973034 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -103,8 +103,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *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 (!nsm) + nsm = host->h_nsmhandle; if (host->h_proto != proto) continue; @@ -120,6 +120,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, nlm_get_host(host); goto out; } + if (nsm) + atomic_inc(&nsm->sm_count); host = NULL; -- GitLab From 44c556000a31e8079cfbb9a42a7edb93ca6b589a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:16:15 -0700 Subject: [PATCH 0522/1619] [PATCH] knfsd: fix auto-sizing of nfsd request/reply buffers totalram is measured in pages, not bytes, so PAGE_SHIFT must be used when trying to find 1/4096 of RAM. Cc: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfssvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 0603baad542..6fa6340a5fb 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -209,7 +209,7 @@ int nfsd_create_serv(void) * Of course, this is only a default. */ nfsd_max_blksize = NFSSVC_MAXBLKSIZE; - i.totalram >>= 12; + i.totalram <<= PAGE_SHIFT - 12; while (nfsd_max_blksize > i.totalram && nfsd_max_blksize >= 8*1024*2) nfsd_max_blksize /= 2; -- GitLab From 21c0d8fdd95024ffa708a938099148b8f1078d46 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:16:16 -0700 Subject: [PATCH 0523/1619] [PATCH] knfsd: close a race-opportunity in d_splice_alias There is a possible race in d_splice_alias. Though __d_find_alias(inode, 1) will only return a dentry with DCACHE_DISCONNECTED set, it is possible for it to get cleared before the BUG_ON, and it is is not possible to lock against that. There are a couple of problems here. Firstly, the code doesn't match the comment. The comment describes a 'disconnected' dentry as being IS_ROOT as well as DCACHE_DISCONNECTED, however there is not testing of IS_ROOT anythere. A dentry is marked DCACHE_DISCONNECTED when allocated with d_alloc_anon, and remains DCACHE_DISCONNECTED while a path is built up towards the root. So a dentry can have a valid name and a valid parent and even grandparent, but will still be DCACHE_DISCONNECTED until a path to the root is created. Once the path to the root is complete, everything in the path gets DCACHE_DISCONNECTED cleared. So the fact that DCACHE_DISCONNECTED isn't enough to say that a dentry is free to be spliced in with a given name. This can only be allowed if the dentry does not yet have a name, so the IS_ROOT test is needed too. However even adding that test to __d_find_alias isn't enough. As d_splice_alias drops dcache_lock before calling d_move to perform the splice, it could race with another thread calling d_splice_alias to splice the inode in with a different name in a different part of the tree (in the case where a file has hard links). So that splicing code is only really safe for directories (as we know that directories only have one link). For directories, the caller of d_splice_alias will be holding i_mutex on the (unique) parent so there is no room for a race. A consequence of this is that a non-directory will never benefit from being spliced into a pre-exisiting dentry, but that isn't a problem. It is perfectly OK for a non-directory to have multiple dentries, some anonymous, some not. And the comment for d_splice_alias says that it only happens for directories anyway. Signed-off-by: Neil Brown Cc: Christoph Hellwig Cc: Al Viro Cc: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dcache.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index fc2faa44f8d..2355bddad8d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -291,9 +291,9 @@ struct dentry * dget_locked(struct dentry *dentry) * it can be unhashed only if it has no children, or if it is the root * of a filesystem. * - * If the inode has a DCACHE_DISCONNECTED alias, then prefer + * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer * any other hashed alias over that one unless @want_discon is set, - * in which case only return a DCACHE_DISCONNECTED alias. + * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. */ static struct dentry * __d_find_alias(struct inode *inode, int want_discon) @@ -309,7 +309,8 @@ static struct dentry * __d_find_alias(struct inode *inode, int want_discon) prefetch(next); alias = list_entry(tmp, struct dentry, d_alias); if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { - if (alias->d_flags & DCACHE_DISCONNECTED) + if (IS_ROOT(alias) && + (alias->d_flags & DCACHE_DISCONNECTED)) discon_alias = alias; else if (!want_discon) { __dget_locked(alias); @@ -1004,7 +1005,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) { struct dentry *new = NULL; - if (inode) { + if (inode && S_ISDIR(inode->i_mode)) { spin_lock(&dcache_lock); new = __d_find_alias(inode, 1); if (new) { -- GitLab From b009a873de05c6e0d7613df3584b6dcb2e4280ee Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:17 -0700 Subject: [PATCH 0524/1619] [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(+) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 597b3cbf8b0..d3178de589e 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 d2a8abb5011..47d96684b61 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; -- GitLab From 933469190ed5915b0568bc564346bb8db718f460 Mon Sep 17 00:00:00 2001 From: Manoj Naik Date: Wed, 4 Oct 2006 02:16:18 -0700 Subject: [PATCH 0525/1619] [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(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index d3178de589e..e13fa23bd10 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 47d96684b61..6e78ea969f4 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 -- GitLab From 81c3f4130202a1dcb2b28ab56684eb5e9d43d8c1 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:19 -0700 Subject: [PATCH 0526/1619] [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(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4cfacc557b4..0589852007e 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 259841bb2f6..8094142d95e 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) -- GitLab From 42ca09938157105c1f573c831a35e9c3e02eb354 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:20 -0700 Subject: [PATCH 0527/1619] [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(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 38b0f91175d..8333db12cac 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 0589852007e..41fc241b729 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 8094142d95e..d0d4aae7085 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) -- GitLab From f7aa2638f288f4c67acdb55947472740bd27d27a Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Wed, 4 Oct 2006 02:16:21 -0700 Subject: [PATCH 0528/1619] [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(-) diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h index f478066f9cd..f0cc7779052 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 -- GitLab From 237fead619984cc48818fe12ee0ceada3f55b012 Mon Sep 17 00:00:00 2001 From: Michael Halcrow Date: Wed, 4 Oct 2006 02:16:22 -0700 Subject: [PATCH 0529/1619] [PATCH] ecryptfs: fs/Makefile and fs/Kconfig eCryptfs is a stacked cryptographic filesystem for Linux. It is derived from Erez Zadok's Cryptfs, implemented through the FiST framework for generating stacked filesystems. eCryptfs extends Cryptfs to provide advanced key management and policy features. eCryptfs stores cryptographic metadata in the header of each file written, so that encrypted files can be copied between hosts; the file will be decryptable with the proper key, and there is no need to keep track of any additional information aside from what is already in the encrypted file itself. [akpm@osdl.org: updates for ongoing API changes] [bunk@stusta.de: cleanups] [akpm@osdl.org: alpha build fix] [akpm@osdl.org: cleanups] [tytso@mit.edu: inode-diet updates] [pbadari@us.ibm.com: generic_file_*_read/write() interface updates] [rdunlap@xenotime.net: printk format fixes] [akpm@osdl.org: make slab creation and teardown table-driven] Signed-off-by: Phillip Hellewell Signed-off-by: Michael Halcrow Signed-off-by: Erez Zadok Signed-off-by: Adrian Bunk Signed-off-by: Stephan Mueller Signed-off-by: "Theodore Ts'o" Signed-off-by: Badari Pulavarty Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ecryptfs.txt | 77 ++ MAINTAINERS | 7 + fs/Kconfig | 12 + fs/Makefile | 1 + fs/ecryptfs/Makefile | 7 + fs/ecryptfs/crypto.c | 1659 +++++++++++++++++++++++++++++++++ fs/ecryptfs/debug.c | 123 +++ fs/ecryptfs/dentry.c | 87 ++ fs/ecryptfs/ecryptfs_kernel.h | 482 ++++++++++ fs/ecryptfs/file.c | 440 +++++++++ fs/ecryptfs/inode.c | 1079 +++++++++++++++++++++ fs/ecryptfs/keystore.c | 1061 +++++++++++++++++++++ fs/ecryptfs/main.c | 831 +++++++++++++++++ fs/ecryptfs/mmap.c | 788 ++++++++++++++++ fs/ecryptfs/super.c | 198 ++++ 15 files changed, 6852 insertions(+) create mode 100644 Documentation/ecryptfs.txt create mode 100644 fs/ecryptfs/Makefile create mode 100644 fs/ecryptfs/crypto.c create mode 100644 fs/ecryptfs/debug.c create mode 100644 fs/ecryptfs/dentry.c create mode 100644 fs/ecryptfs/ecryptfs_kernel.h create mode 100644 fs/ecryptfs/file.c create mode 100644 fs/ecryptfs/inode.c create mode 100644 fs/ecryptfs/keystore.c create mode 100644 fs/ecryptfs/main.c create mode 100644 fs/ecryptfs/mmap.c create mode 100644 fs/ecryptfs/super.c diff --git a/Documentation/ecryptfs.txt b/Documentation/ecryptfs.txt new file mode 100644 index 00000000000..01d8a08351a --- /dev/null +++ b/Documentation/ecryptfs.txt @@ -0,0 +1,77 @@ +eCryptfs: A stacked cryptographic filesystem for Linux + +eCryptfs is free software. Please see the file COPYING for details. +For documentation, please see the files in the doc/ subdirectory. For +building and installation instructions please see the INSTALL file. + +Maintainer: Phillip Hellewell +Lead developer: Michael A. Halcrow +Developers: Michael C. Thompson + Kent Yoder +Web Site: http://ecryptfs.sf.net + +This software is currently undergoing development. Make sure to +maintain a backup copy of any data you write into eCryptfs. + +eCryptfs requires the userspace tools downloadable from the +SourceForge site: + +http://sourceforge.net/projects/ecryptfs/ + +Userspace requirements include: + - David Howells' userspace keyring headers and libraries (version + 1.0 or higher), obtainable from + http://people.redhat.com/~dhowells/keyutils/ + - Libgcrypt + + +NOTES + +In the beta/experimental releases of eCryptfs, when you upgrade +eCryptfs, you should copy the files to an unencrypted location and +then copy the files back into the new eCryptfs mount to migrate the +files. + + +MOUNT-WIDE PASSPHRASE + +Create a new directory into which eCryptfs will write its encrypted +files (i.e., /root/crypt). Then, create the mount point directory +(i.e., /mnt/crypt). Now it's time to mount eCryptfs: + +mount -t ecryptfs /root/crypt /mnt/crypt + +You should be prompted for a passphrase and a salt (the salt may be +blank). + +Try writing a new file: + +echo "Hello, World" > /mnt/crypt/hello.txt + +The operation will complete. Notice that there is a new file in +/root/crypt that is at least 12288 bytes in size (depending on your +host page size). This is the encrypted underlying file for what you +just wrote. To test reading, from start to finish, you need to clear +the user session keyring: + +keyctl clear @u + +Then umount /mnt/crypt and mount again per the instructions given +above. + +cat /mnt/crypt/hello.txt + + +NOTES + +eCryptfs version 0.1 should only be mounted on (1) empty directories +or (2) directories containing files only created by eCryptfs. If you +mount a directory that has pre-existing files not created by eCryptfs, +then behavior is undefined. Do not run eCryptfs in higher verbosity +levels unless you are doing so for the sole purpose of debugging or +development, since secret values will be written out to the system log +in that case. + + +Mike Halcrow +mhalcrow@us.ibm.com diff --git a/MAINTAINERS b/MAINTAINERS index 77e58585ce5..129511c0c27 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -977,6 +977,13 @@ L: ebtables-devel@lists.sourceforge.net W: http://ebtables.sourceforge.net/ S: Maintained +ECRYPT FILE SYSTEM +P: Mike Halcrow, Phillip Hellewell +M: mhalcrow@us.ibm.com, phillip@hellewell.homeip.net +L: ecryptfs-devel@lists.sourceforge.net +W: http://ecryptfs.sourceforge.net/ +S: Supported + EDAC-CORE P: Doug Thompson M: norsk5@xmission.com diff --git a/fs/Kconfig b/fs/Kconfig index 68f4561423f..674cfbb83a9 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -995,6 +995,18 @@ config AFFS_FS To compile this file system support as a module, choose M here: the module will be called affs. If unsure, say N. +config ECRYPT_FS + tristate "eCrypt filesystem layer support (EXPERIMENTAL)" + depends on EXPERIMENTAL && KEYS && CRYPTO + help + Encrypted filesystem that operates on the VFS layer. See + to learn more about + eCryptfs. Userspace components are required and can be + obtained from . + + To compile this file system support as a module, choose M here: the + module will be called ecryptfs. + config HFS_FS tristate "Apple Macintosh file system support (EXPERIMENTAL)" depends on BLOCK && EXPERIMENTAL diff --git a/fs/Makefile b/fs/Makefile index 819b2a93beb..fd24d67a7cd 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_BFS_FS) += bfs/ obj-$(CONFIG_ISO9660_FS) += isofs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ +obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ obj-$(CONFIG_VXFS_FS) += freevxfs/ obj-$(CONFIG_NFS_FS) += nfs/ obj-$(CONFIG_EXPORTFS) += exportfs/ diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile new file mode 100644 index 00000000000..ca6562451ee --- /dev/null +++ b/fs/ecryptfs/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Linux 2.6 eCryptfs +# + +obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o + +ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o debug.o diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c new file mode 100644 index 00000000000..ed35a9712fa --- /dev/null +++ b/fs/ecryptfs/crypto.c @@ -0,0 +1,1659 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2004 Erez Zadok + * Copyright (C) 2001-2004 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * Michael C. Thompson + * + * 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 +#include +#include +#include +#include +#include "ecryptfs_kernel.h" + +static int +ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, + struct page *dst_page, int dst_offset, + struct page *src_page, int src_offset, int size, + unsigned char *iv); +static int +ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, + struct page *dst_page, int dst_offset, + struct page *src_page, int src_offset, int size, + unsigned char *iv); + +/** + * ecryptfs_to_hex + * @dst: Buffer to take hex character representation of contents of + * src; must be at least of size (src_size * 2) + * @src: Buffer to be converted to a hex string respresentation + * @src_size: number of bytes to convert + */ +void ecryptfs_to_hex(char *dst, char *src, size_t src_size) +{ + int x; + + for (x = 0; x < src_size; x++) + sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]); +} + +/** + * ecryptfs_from_hex + * @dst: Buffer to take the bytes from src hex; must be at least of + * size (src_size / 2) + * @src: Buffer to be converted from a hex string respresentation to raw value + * @dst_size: size of dst buffer, or number of hex characters pairs to convert + */ +void ecryptfs_from_hex(char *dst, char *src, int dst_size) +{ + int x; + char tmp[3] = { 0, }; + + for (x = 0; x < dst_size; x++) { + tmp[0] = src[x * 2]; + tmp[1] = src[x * 2 + 1]; + dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16); + } +} + +/** + * ecryptfs_calculate_md5 - calculates the md5 of @src + * @dst: Pointer to 16 bytes of allocated memory + * @crypt_stat: Pointer to crypt_stat struct for the current inode + * @src: Data to be md5'd + * @len: Length of @src + * + * Uses the allocated crypto context that crypt_stat references to + * generate the MD5 sum of the contents of src. + */ +static int ecryptfs_calculate_md5(char *dst, + struct ecryptfs_crypt_stat *crypt_stat, + char *src, int len) +{ + int rc = 0; + struct scatterlist sg; + + mutex_lock(&crypt_stat->cs_md5_tfm_mutex); + sg_init_one(&sg, (u8 *)src, len); + if (!crypt_stat->md5_tfm) { + crypt_stat->md5_tfm = + crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP); + if (!crypt_stat->md5_tfm) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Error attempting to " + "allocate crypto context\n"); + goto out; + } + } + crypto_digest_init(crypt_stat->md5_tfm); + crypto_digest_update(crypt_stat->md5_tfm, &sg, 1); + crypto_digest_final(crypt_stat->md5_tfm, dst); + mutex_unlock(&crypt_stat->cs_md5_tfm_mutex); +out: + return rc; +} + +/** + * ecryptfs_derive_iv + * @iv: destination for the derived iv vale + * @crypt_stat: Pointer to crypt_stat struct for the current inode + * @offset: Offset of the page whose's iv we are to derive + * + * Generate the initialization vector from the given root IV and page + * offset. + * + * Returns zero on success; non-zero on error. + */ +static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat, + pgoff_t offset) +{ + int rc = 0; + char dst[MD5_DIGEST_SIZE]; + char src[ECRYPTFS_MAX_IV_BYTES + 16]; + + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "root iv:\n"); + ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes); + } + /* TODO: It is probably secure to just cast the least + * significant bits of the root IV into an unsigned long and + * add the offset to that rather than go through all this + * hashing business. -Halcrow */ + memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes); + memset((src + crypt_stat->iv_bytes), 0, 16); + snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "source:\n"); + ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16)); + } + rc = ecryptfs_calculate_md5(dst, crypt_stat, src, + (crypt_stat->iv_bytes + 16)); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error attempting to compute " + "MD5 while generating IV for a page\n"); + goto out; + } + memcpy(iv, dst, crypt_stat->iv_bytes); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "derived iv:\n"); + ecryptfs_dump_hex(iv, crypt_stat->iv_bytes); + } +out: + return rc; +} + +/** + * ecryptfs_init_crypt_stat + * @crypt_stat: Pointer to the crypt_stat struct to initialize. + * + * Initialize the crypt_stat structure. + */ +void +ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) +{ + memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); + mutex_init(&crypt_stat->cs_mutex); + mutex_init(&crypt_stat->cs_tfm_mutex); + mutex_init(&crypt_stat->cs_md5_tfm_mutex); + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED); +} + +/** + * ecryptfs_destruct_crypt_stat + * @crypt_stat: Pointer to the crypt_stat struct to initialize. + * + * Releases all memory associated with a crypt_stat struct. + */ +void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) +{ + if (crypt_stat->tfm) + crypto_free_tfm(crypt_stat->tfm); + if (crypt_stat->md5_tfm) + crypto_free_tfm(crypt_stat->md5_tfm); + memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); +} + +void ecryptfs_destruct_mount_crypt_stat( + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) +{ + if (mount_crypt_stat->global_auth_tok_key) + key_put(mount_crypt_stat->global_auth_tok_key); + if (mount_crypt_stat->global_key_tfm) + crypto_free_tfm(mount_crypt_stat->global_key_tfm); + memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat)); +} + +/** + * virt_to_scatterlist + * @addr: Virtual address + * @size: Size of data; should be an even multiple of the block size + * @sg: Pointer to scatterlist array; set to NULL to obtain only + * the number of scatterlist structs required in array + * @sg_size: Max array size + * + * Fills in a scatterlist array with page references for a passed + * virtual address. + * + * Returns the number of scatterlist structs in array used + */ +int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, + int sg_size) +{ + int i = 0; + struct page *pg; + int offset; + int remainder_of_page; + + while (size > 0 && i < sg_size) { + pg = virt_to_page(addr); + offset = offset_in_page(addr); + if (sg) { + sg[i].page = pg; + sg[i].offset = offset; + } + remainder_of_page = PAGE_CACHE_SIZE - offset; + if (size >= remainder_of_page) { + if (sg) + sg[i].length = remainder_of_page; + addr += remainder_of_page; + size -= remainder_of_page; + } else { + if (sg) + sg[i].length = size; + addr += size; + size = 0; + } + i++; + } + if (size > 0) + return -ENOMEM; + return i; +} + +/** + * encrypt_scatterlist + * @crypt_stat: Pointer to the crypt_stat struct to initialize. + * @dest_sg: Destination of encrypted data + * @src_sg: Data to be encrypted + * @size: Length of data to be encrypted + * @iv: iv to use during encryption + * + * Returns the number of bytes encrypted; negative value on error + */ +static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, + struct scatterlist *dest_sg, + struct scatterlist *src_sg, int size, + unsigned char *iv) +{ + int rc = 0; + + BUG_ON(!crypt_stat || !crypt_stat->tfm + || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, + ECRYPTFS_STRUCT_INITIALIZED)); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n", + crypt_stat->key_size); + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + } + /* Consider doing this once, when the file is opened */ + mutex_lock(&crypt_stat->cs_tfm_mutex); + rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size); + crypto_cipher_encrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size, iv); + mutex_unlock(&crypt_stat->cs_tfm_mutex); +out: + return rc; +} + +static void +ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx, + int *byte_offset, + struct ecryptfs_crypt_stat *crypt_stat, + unsigned long extent_num) +{ + unsigned long lower_extent_num; + int extents_occupied_by_headers_at_front; + int bytes_occupied_by_headers_at_front; + int extent_offset; + int extents_per_page; + + bytes_occupied_by_headers_at_front = + ( crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front ); + extents_occupied_by_headers_at_front = + ( bytes_occupied_by_headers_at_front + / crypt_stat->extent_size ); + lower_extent_num = extents_occupied_by_headers_at_front + extent_num; + extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; + (*lower_page_idx) = lower_extent_num / extents_per_page; + extent_offset = lower_extent_num % extents_per_page; + (*byte_offset) = extent_offset * crypt_stat->extent_size; + ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = " + "[%d]\n", crypt_stat->header_extent_size); + ecryptfs_printk(KERN_DEBUG, " * crypt_stat->" + "num_header_extents_at_front = [%d]\n", + crypt_stat->num_header_extents_at_front); + ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_" + "front = [%d]\n", extents_occupied_by_headers_at_front); + ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n", + lower_extent_num); + ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n", + extents_per_page); + ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n", + (*lower_page_idx)); + ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n", + extent_offset); + ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n", + (*byte_offset)); +} + +static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx, + struct page *lower_page, + struct inode *lower_inode, + int byte_offset_in_page, int bytes_to_write) +{ + int rc = 0; + + if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) { + rc = ecryptfs_commit_lower_page(lower_page, lower_inode, + ctx->param.lower_file, + byte_offset_in_page, + bytes_to_write); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error calling lower " + "commit; rc = [%d]\n", rc); + goto out; + } + } else { + rc = ecryptfs_writepage_and_release_lower_page(lower_page, + lower_inode, + ctx->param.wbc); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error calling lower " + "writepage(); rc = [%d]\n", rc); + goto out; + } + } +out: + return rc; +} + +static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx, + struct page **lower_page, + struct inode *lower_inode, + unsigned long lower_page_idx, + int byte_offset_in_page) +{ + int rc = 0; + + if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) { + /* TODO: Limit this to only the data extents that are + * needed */ + rc = ecryptfs_get_lower_page(lower_page, lower_inode, + ctx->param.lower_file, + lower_page_idx, + byte_offset_in_page, + (PAGE_CACHE_SIZE + - byte_offset_in_page)); + if (rc) { + ecryptfs_printk( + KERN_ERR, "Error attempting to grab, map, " + "and prepare_write lower page with index " + "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc); + goto out; + } + } else { + rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, + lower_inode, + lower_page_idx); + if (rc) { + ecryptfs_printk( + KERN_ERR, "Error attempting to grab and map " + "lower page with index [0x%.16x]; rc = [%d]\n", + lower_page_idx, rc); + goto out; + } + } +out: + return rc; +} + +/** + * ecryptfs_encrypt_page + * @ctx: The context of the page + * + * Encrypt an eCryptfs page. This is done on a per-extent basis. Note + * that eCryptfs pages may straddle the lower pages -- for instance, + * if the file was created on a machine with an 8K page size + * (resulting in an 8K header), and then the file is copied onto a + * host with a 32K page size, then when reading page 0 of the eCryptfs + * file, 24K of page 0 of the lower file will be read and decrypted, + * and then 8K of page 1 of the lower file will be read and decrypted. + * + * The actual operations performed on each page depends on the + * contents of the ecryptfs_page_crypt_context struct. + * + * Returns zero on success; negative on error + */ +int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx) +{ + char extent_iv[ECRYPTFS_MAX_IV_BYTES]; + unsigned long base_extent; + unsigned long extent_offset = 0; + unsigned long lower_page_idx = 0; + unsigned long prior_lower_page_idx = 0; + struct page *lower_page; + struct inode *lower_inode; + struct ecryptfs_inode_info *inode_info; + struct ecryptfs_crypt_stat *crypt_stat; + int rc = 0; + int lower_byte_offset = 0; + int orig_byte_offset = 0; + int num_extents_per_page; +#define ECRYPTFS_PAGE_STATE_UNREAD 0 +#define ECRYPTFS_PAGE_STATE_READ 1 +#define ECRYPTFS_PAGE_STATE_MODIFIED 2 +#define ECRYPTFS_PAGE_STATE_WRITTEN 3 + int page_state; + + lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host); + inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host); + crypt_stat = &inode_info->crypt_stat; + if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) { + rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode, + ctx->param.lower_file); + if (rc) + ecryptfs_printk(KERN_ERR, "Error attempting to copy " + "page at index [0x%.16x]\n", + ctx->page->index); + goto out; + } + num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; + base_extent = (ctx->page->index * num_extents_per_page); + page_state = ECRYPTFS_PAGE_STATE_UNREAD; + while (extent_offset < num_extents_per_page) { + ecryptfs_extent_to_lwr_pg_idx_and_offset( + &lower_page_idx, &lower_byte_offset, crypt_stat, + (base_extent + extent_offset)); + if (prior_lower_page_idx != lower_page_idx + && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) { + rc = ecryptfs_write_out_page(ctx, lower_page, + lower_inode, + orig_byte_offset, + (PAGE_CACHE_SIZE + - orig_byte_offset)); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting " + "to write out page; rc = [%d]" + "\n", rc); + goto out; + } + page_state = ECRYPTFS_PAGE_STATE_WRITTEN; + } + if (page_state == ECRYPTFS_PAGE_STATE_UNREAD + || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) { + rc = ecryptfs_read_in_page(ctx, &lower_page, + lower_inode, lower_page_idx, + lower_byte_offset); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting " + "to read in lower page with " + "index [0x%.16x]; rc = [%d]\n", + lower_page_idx, rc); + goto out; + } + orig_byte_offset = lower_byte_offset; + prior_lower_page_idx = lower_page_idx; + page_state = ECRYPTFS_PAGE_STATE_READ; + } + BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED + || page_state == ECRYPTFS_PAGE_STATE_READ)); + rc = ecryptfs_derive_iv(extent_iv, crypt_stat, + (base_extent + extent_offset)); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting to " + "derive IV for extent [0x%.16x]; " + "rc = [%d]\n", + (base_extent + extent_offset), rc); + goto out; + } + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Encrypting extent " + "with iv:\n"); + ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); + ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " + "encryption:\n"); + ecryptfs_dump_hex((char *) + (page_address(ctx->page) + + (extent_offset + * crypt_stat->extent_size)), 8); + } + rc = ecryptfs_encrypt_page_offset( + crypt_stat, lower_page, lower_byte_offset, ctx->page, + (extent_offset * crypt_stat->extent_size), + crypt_stat->extent_size, extent_iv); + ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; " + "rc = [%d]\n", + (base_extent + extent_offset), rc); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " + "encryption:\n"); + ecryptfs_dump_hex((char *)(page_address(lower_page) + + lower_byte_offset), 8); + } + page_state = ECRYPTFS_PAGE_STATE_MODIFIED; + extent_offset++; + } + BUG_ON(orig_byte_offset != 0); + rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0, + (lower_byte_offset + + crypt_stat->extent_size)); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting to write out " + "page; rc = [%d]\n", rc); + goto out; + } +out: + return rc; +} + +/** + * ecryptfs_decrypt_page + * @file: The ecryptfs file + * @page: The page in ecryptfs to decrypt + * + * Decrypt an eCryptfs page. This is done on a per-extent basis. Note + * that eCryptfs pages may straddle the lower pages -- for instance, + * if the file was created on a machine with an 8K page size + * (resulting in an 8K header), and then the file is copied onto a + * host with a 32K page size, then when reading page 0 of the eCryptfs + * file, 24K of page 0 of the lower file will be read and decrypted, + * and then 8K of page 1 of the lower file will be read and decrypted. + * + * Returns zero on success; negative on error + */ +int ecryptfs_decrypt_page(struct file *file, struct page *page) +{ + char extent_iv[ECRYPTFS_MAX_IV_BYTES]; + unsigned long base_extent; + unsigned long extent_offset = 0; + unsigned long lower_page_idx = 0; + unsigned long prior_lower_page_idx = 0; + struct page *lower_page; + char *lower_page_virt = NULL; + struct inode *lower_inode; + struct ecryptfs_crypt_stat *crypt_stat; + int rc = 0; + int byte_offset; + int num_extents_per_page; + int page_state; + + crypt_stat = &(ecryptfs_inode_to_private( + page->mapping->host)->crypt_stat); + lower_inode = ecryptfs_inode_to_lower(page->mapping->host); + if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) { + rc = ecryptfs_do_readpage(file, page, page->index); + if (rc) + ecryptfs_printk(KERN_ERR, "Error attempting to copy " + "page at index [0x%.16x]\n", + page->index); + goto out; + } + 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); + if (!lower_page_virt) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Error getting page for encrypted " + "lower page(s)\n"); + goto out; + } + lower_page = virt_to_page(lower_page_virt); + page_state = ECRYPTFS_PAGE_STATE_UNREAD; + while (extent_offset < num_extents_per_page) { + ecryptfs_extent_to_lwr_pg_idx_and_offset( + &lower_page_idx, &byte_offset, crypt_stat, + (base_extent + extent_offset)); + if (prior_lower_page_idx != lower_page_idx + || page_state == ECRYPTFS_PAGE_STATE_UNREAD) { + rc = ecryptfs_do_readpage(file, lower_page, + lower_page_idx); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error reading " + "lower encrypted page; rc = " + "[%d]\n", rc); + goto out; + } + prior_lower_page_idx = lower_page_idx; + page_state = ECRYPTFS_PAGE_STATE_READ; + } + rc = ecryptfs_derive_iv(extent_iv, crypt_stat, + (base_extent + extent_offset)); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting to " + "derive IV for extent [0x%.16x]; rc = " + "[%d]\n", + (base_extent + extent_offset), rc); + goto out; + } + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Decrypting extent " + "with iv:\n"); + ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); + ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " + "decryption:\n"); + ecryptfs_dump_hex((lower_page_virt + byte_offset), 8); + } + rc = ecryptfs_decrypt_page_offset(crypt_stat, page, + (extent_offset + * crypt_stat->extent_size), + lower_page, byte_offset, + crypt_stat->extent_size, + extent_iv); + if (rc != crypt_stat->extent_size) { + ecryptfs_printk(KERN_ERR, "Error attempting to " + "decrypt extent [0x%.16x]\n", + (base_extent + extent_offset)); + goto out; + } + rc = 0; + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " + "decryption:\n"); + ecryptfs_dump_hex((char *)(page_address(page) + + byte_offset), 8); + } + extent_offset++; + } +out: + if (lower_page_virt) + kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt); + return rc; +} + +/** + * decrypt_scatterlist + * + * Returns the number of bytes decrypted; negative value on error + */ +static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, + struct scatterlist *dest_sg, + struct scatterlist *src_sg, int size, + unsigned char *iv) +{ + int rc = 0; + + /* Consider doing this once, when the file is opened */ + mutex_lock(&crypt_stat->cs_tfm_mutex); + rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", + rc); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + rc = -EINVAL; + goto out; + } + ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); + rc = crypto_cipher_decrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size, + iv); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", + rc); + goto out; + } + rc = size; +out: + return rc; +} + +/** + * ecryptfs_encrypt_page_offset + * + * Returns the number of bytes encrypted + */ +static int +ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, + struct page *dst_page, int dst_offset, + struct page *src_page, int src_offset, int size, + unsigned char *iv) +{ + struct scatterlist src_sg, dst_sg; + + src_sg.page = src_page; + src_sg.offset = src_offset; + src_sg.length = size; + dst_sg.page = dst_page; + dst_sg.offset = dst_offset; + dst_sg.length = size; + return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv); +} + +/** + * ecryptfs_decrypt_page_offset + * + * Returns the number of bytes decrypted + */ +static int +ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, + struct page *dst_page, int dst_offset, + struct page *src_page, int src_offset, int size, + unsigned char *iv) +{ + struct scatterlist src_sg, dst_sg; + + src_sg.page = src_page; + src_sg.offset = src_offset; + src_sg.length = size; + dst_sg.page = dst_page; + dst_sg.offset = dst_offset; + dst_sg.length = size; + return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv); +} + +#define ECRYPTFS_MAX_SCATTERLIST_LEN 4 + +/** + * ecryptfs_init_crypt_ctx + * @crypt_stat: Uninitilized crypt stats structure + * + * Initialize the crypto context. + * + * TODO: Performance: Keep a cache of initialized cipher contexts; + * only init if needed + */ +int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) +{ + int rc = -EINVAL; + + if (!crypt_stat->cipher) { + ecryptfs_printk(KERN_ERR, "No cipher specified\n"); + goto out; + } + ecryptfs_printk(KERN_DEBUG, + "Initializing cipher [%s]; strlen = [%d]; " + "key_size_bits = [%d]\n", + crypt_stat->cipher, (int)strlen(crypt_stat->cipher), + crypt_stat->key_size << 3); + if (crypt_stat->tfm) { + rc = 0; + goto out; + } + mutex_lock(&crypt_stat->cs_tfm_mutex); + crypt_stat->tfm = crypto_alloc_tfm(crypt_stat->cipher, + ECRYPTFS_DEFAULT_CHAINING_MODE + | CRYPTO_TFM_REQ_WEAK_KEY); + mutex_unlock(&crypt_stat->cs_tfm_mutex); + if (!crypt_stat->tfm) { + ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): " + "Error initializing cipher [%s]\n", + crypt_stat->cipher); + goto out; + } + rc = 0; +out: + return rc; +} + +static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat) +{ + int extent_size_tmp; + + crypt_stat->extent_mask = 0xFFFFFFFF; + crypt_stat->extent_shift = 0; + if (crypt_stat->extent_size == 0) + return; + extent_size_tmp = crypt_stat->extent_size; + while ((extent_size_tmp & 0x01) == 0) { + extent_size_tmp >>= 1; + crypt_stat->extent_mask <<= 1; + crypt_stat->extent_shift++; + } +} + +void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) +{ + /* Default values; may be overwritten as we are parsing the + * packets. */ + crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE; + set_extent_mask_and_shift(crypt_stat); + crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; + if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { + crypt_stat->header_extent_size = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; + } else + crypt_stat->header_extent_size = PAGE_CACHE_SIZE; + crypt_stat->num_header_extents_at_front = 1; +} + +/** + * ecryptfs_compute_root_iv + * @crypt_stats + * + * On error, sets the root IV to all 0's. + */ +int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat) +{ + int rc = 0; + char dst[MD5_DIGEST_SIZE]; + + BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE); + BUG_ON(crypt_stat->iv_bytes <= 0); + if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, "Session key not valid; " + "cannot generate root IV\n"); + goto out; + } + rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error attempting to compute " + "MD5 while generating root IV\n"); + goto out; + } + memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes); +out: + if (rc) { + memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes); + ECRYPTFS_SET_FLAG(crypt_stat->flags, + ECRYPTFS_SECURITY_WARNING); + } + return rc; +} + +static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat) +{ + get_random_bytes(crypt_stat->key, crypt_stat->key_size); + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + ecryptfs_compute_root_iv(crypt_stat); + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n"); + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + } +} + +/** + * ecryptfs_set_default_crypt_stat_vals + * @crypt_stat + * + * Default values in the event that policy does not override them. + */ +static void ecryptfs_set_default_crypt_stat_vals( + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) +{ + ecryptfs_set_default_sizes(crypt_stat); + strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER); + crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES; + ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->file_version = ECRYPTFS_FILE_VERSION; + crypt_stat->mount_crypt_stat = mount_crypt_stat; +} + +/** + * ecryptfs_new_file_context + * @ecryptfs_dentry + * + * If the crypto context for the file has not yet been established, + * this is where we do that. Establishing a new crypto context + * involves the following decisions: + * - What cipher to use? + * - What set of authentication tokens to use? + * Here we just worry about getting enough information into the + * authentication tokens so that we know that they are available. + * We associate the available authentication tokens with the new file + * via the set of signatures in the crypt_stat struct. Later, when + * the headers are actually written out, we may again defer to + * userspace to perform the encryption of the session key; for the + * foreseeable future, this will be the case with public key packets. + * + * Returns zero on success; non-zero otherwise + */ +/* Associate an authentication token(s) with the file */ +int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) +{ + int rc = 0; + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + int cipher_name_len; + + ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat); + /* See if there are mount crypt options */ + if (mount_crypt_stat->global_auth_tok) { + ecryptfs_printk(KERN_DEBUG, "Initializing context for new " + "file using mount_crypt_stat\n"); + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++], + mount_crypt_stat->global_auth_tok_sig, + ECRYPTFS_SIG_SIZE_HEX); + cipher_name_len = + strlen(mount_crypt_stat->global_default_cipher_name); + memcpy(crypt_stat->cipher, + mount_crypt_stat->global_default_cipher_name, + cipher_name_len); + crypt_stat->cipher[cipher_name_len] = '\0'; + crypt_stat->key_size = + mount_crypt_stat->global_default_cipher_key_size; + ecryptfs_generate_new_key(crypt_stat); + } else + /* We should not encounter this scenario since we + * should detect lack of global_auth_tok at mount time + * TODO: Applies to 0.1 release only; remove in future + * release */ + BUG(); + rc = ecryptfs_init_crypt_ctx(crypt_stat); + if (rc) + ecryptfs_printk(KERN_ERR, "Error initializing cryptographic " + "context for cipher [%s]: rc = [%d]\n", + crypt_stat->cipher, rc); + return rc; +} + +/** + * contains_ecryptfs_marker - check for the ecryptfs marker + * @data: The data block in which to check + * + * Returns one if marker found; zero if not found + */ +int contains_ecryptfs_marker(char *data) +{ + u32 m_1, m_2; + + memcpy(&m_1, data, 4); + m_1 = be32_to_cpu(m_1); + memcpy(&m_2, (data + 4), 4); + m_2 = be32_to_cpu(m_2); + if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2) + return 1; + ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; " + "MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2, + MAGIC_ECRYPTFS_MARKER); + ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = " + "[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER)); + return 0; +} + +struct ecryptfs_flag_map_elem { + u32 file_flag; + u32 local_flag; +}; + +/* Add support for additional flags by adding elements here. */ +static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = { + {0x00000001, ECRYPTFS_ENABLE_HMAC}, + {0x00000002, ECRYPTFS_ENCRYPTED} +}; + +/** + * ecryptfs_process_flags + * @crypt_stat + * @page_virt: Source data to be parsed + * @bytes_read: Updated with the number of bytes read + * + * Returns zero on success; non-zero if the flag set is invalid + */ +static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat, + char *page_virt, int *bytes_read) +{ + int rc = 0; + int i; + u32 flags; + + memcpy(&flags, page_virt, 4); + flags = be32_to_cpu(flags); + for (i = 0; i < ((sizeof(ecryptfs_flag_map) + / sizeof(struct ecryptfs_flag_map_elem))); i++) + if (flags & ecryptfs_flag_map[i].file_flag) { + ECRYPTFS_SET_FLAG(crypt_stat->flags, + ecryptfs_flag_map[i].local_flag); + } else + ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, + ecryptfs_flag_map[i].local_flag); + /* Version is in top 8 bits of the 32-bit flag vector */ + crypt_stat->file_version = ((flags >> 24) & 0xFF); + (*bytes_read) = 4; + return rc; +} + +/** + * write_ecryptfs_marker + * @page_virt: The pointer to in a page to begin writing the marker + * @written: Number of bytes written + * + * Marker = 0x3c81b7f5 + */ +static void write_ecryptfs_marker(char *page_virt, size_t *written) +{ + u32 m_1, m_2; + + get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2)); + m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER); + m_1 = cpu_to_be32(m_1); + memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2)); + m_2 = cpu_to_be32(m_2); + memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2, + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2)); + (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; +} + +static void +write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, + size_t *written) +{ + u32 flags = 0; + int i; + + for (i = 0; i < ((sizeof(ecryptfs_flag_map) + / sizeof(struct ecryptfs_flag_map_elem))); i++) + if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, + ecryptfs_flag_map[i].local_flag)) + flags |= ecryptfs_flag_map[i].file_flag; + /* Version is in top 8 bits of the 32-bit flag vector */ + flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000); + flags = cpu_to_be32(flags); + memcpy(page_virt, &flags, 4); + (*written) = 4; +} + +struct ecryptfs_cipher_code_str_map_elem { + char cipher_str[16]; + u16 cipher_code; +}; + +/* Add support for additional ciphers by adding elements here. The + * cipher_code is whatever OpenPGP applicatoins use to identify the + * ciphers. List in order of probability. */ +static struct ecryptfs_cipher_code_str_map_elem +ecryptfs_cipher_code_str_map[] = { + {"aes",RFC2440_CIPHER_AES_128 }, + {"blowfish", RFC2440_CIPHER_BLOWFISH}, + {"des3_ede", RFC2440_CIPHER_DES3_EDE}, + {"cast5", RFC2440_CIPHER_CAST_5}, + {"twofish", RFC2440_CIPHER_TWOFISH}, + {"cast6", RFC2440_CIPHER_CAST_6}, + {"aes", RFC2440_CIPHER_AES_192}, + {"aes", RFC2440_CIPHER_AES_256} +}; + +/** + * ecryptfs_code_for_cipher_string + * @str: The string representing the cipher name + * + * Returns zero on no match, or the cipher code on match + */ +u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) +{ + int i; + u16 code = 0; + struct ecryptfs_cipher_code_str_map_elem *map = + ecryptfs_cipher_code_str_map; + + if (strcmp(crypt_stat->cipher, "aes") == 0) { + switch (crypt_stat->key_size) { + case 16: + code = RFC2440_CIPHER_AES_128; + break; + case 24: + code = RFC2440_CIPHER_AES_192; + break; + case 32: + code = RFC2440_CIPHER_AES_256; + } + } else { + for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++) + if (strcmp(crypt_stat->cipher, map[i].cipher_str) == 0){ + code = map[i].cipher_code; + break; + } + } + return code; +} + +/** + * ecryptfs_cipher_code_to_string + * @str: Destination to write out the cipher name + * @cipher_code: The code to convert to cipher name string + * + * Returns zero on success + */ +int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code) +{ + int rc = 0; + int i; + + str[0] = '\0'; + for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++) + if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code) + strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str); + if (str[0] == '\0') { + ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: " + "[%d]\n", cipher_code); + rc = -EINVAL; + } + return rc; +} + +/** + * ecryptfs_read_header_region + * @data + * @dentry + * @nd + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_read_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt) +{ + struct file *file; + mm_segment_t oldfs; + int rc; + + mnt = mntget(mnt); + file = dentry_open(dentry, mnt, O_RDONLY); + if (IS_ERR(file)) { + ecryptfs_printk(KERN_DEBUG, "Error opening file to " + "read header region\n"); + mntput(mnt); + rc = PTR_ERR(file); + goto out; + } + file->f_pos = 0; + oldfs = get_fs(); + set_fs(get_ds()); + /* For releases 0.1 and 0.2, all of the header information + * fits in the first data extent-sized region. */ + rc = file->f_op->read(file, (char __user *)data, + ECRYPTFS_DEFAULT_EXTENT_SIZE, &file->f_pos); + set_fs(oldfs); + fput(file); + rc = 0; +out: + return rc; +} + +static void +write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat, + size_t *written) +{ + u32 header_extent_size; + u16 num_header_extents_at_front; + + header_extent_size = (u32)crypt_stat->header_extent_size; + num_header_extents_at_front = + (u16)crypt_stat->num_header_extents_at_front; + header_extent_size = cpu_to_be32(header_extent_size); + memcpy(virt, &header_extent_size, 4); + virt += 4; + num_header_extents_at_front = cpu_to_be16(num_header_extents_at_front); + memcpy(virt, &num_header_extents_at_front, 2); + (*written) = 6; +} + +struct kmem_cache *ecryptfs_header_cache_0; +struct kmem_cache *ecryptfs_header_cache_1; +struct kmem_cache *ecryptfs_header_cache_2; + +/** + * ecryptfs_write_headers_virt + * @page_virt + * @crypt_stat + * @ecryptfs_dentry + * + * Format version: 1 + * + * Header Extent: + * Octets 0-7: Unencrypted file size (big-endian) + * Octets 8-15: eCryptfs special marker + * Octets 16-19: Flags + * Octet 16: File format version number (between 0 and 255) + * Octets 17-18: Reserved + * Octet 19: Bit 1 (lsb): Reserved + * Bit 2: Encrypted? + * Bits 3-8: Reserved + * Octets 20-23: Header extent size (big-endian) + * Octets 24-25: Number of header extents at front of file + * (big-endian) + * Octet 26: Begin RFC 2440 authentication token packet set + * Data Extent 0: + * Lower data (CBC encrypted) + * Data Extent 1: + * Lower data (CBC encrypted) + * ... + * + * Returns zero on success + */ +int ecryptfs_write_headers_virt(char *page_virt, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry) +{ + int rc; + size_t written; + size_t offset; + + offset = ECRYPTFS_FILE_SIZE_BYTES; + write_ecryptfs_marker((page_virt + offset), &written); + offset += written; + write_ecryptfs_flags((page_virt + offset), crypt_stat, &written); + offset += written; + write_header_metadata((page_virt + offset), crypt_stat, &written); + offset += written; + rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat, + ecryptfs_dentry, &written, + PAGE_CACHE_SIZE - offset); + if (rc) + ecryptfs_printk(KERN_WARNING, "Error generating key packet " + "set; rc = [%d]\n", rc); + return rc; +} + +/** + * ecryptfs_write_headers + * @lower_file: The lower file struct, which was returned from dentry_open + * + * Write the file headers out. This will likely involve a userspace + * callout, in which the session key is encrypted with one or more + * public keys and/or the passphrase necessary to do the encryption is + * retrieved via a prompt. Exactly what happens at this point should + * be policy-dependent. + * + * Returns zero on success; non-zero on error + */ +int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, + struct file *lower_file) +{ + mm_segment_t oldfs; + struct ecryptfs_crypt_stat *crypt_stat; + char *page_virt; + int current_header_page; + int header_pages; + int rc = 0; + + crypt_stat = &ecryptfs_inode_to_private( + ecryptfs_dentry->d_inode)->crypt_stat; + if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags, + ECRYPTFS_ENCRYPTED))) { + if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, + ECRYPTFS_KEY_VALID)) { + ecryptfs_printk(KERN_DEBUG, "Key is " + "invalid; bailing out\n"); + rc = -EINVAL; + goto out; + } + } else { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, + "Called with crypt_stat->encrypted == 0\n"); + goto out; + } + /* Released in this function */ + page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER); + if (!page_virt) { + ecryptfs_printk(KERN_ERR, "Out of memory\n"); + rc = -ENOMEM; + goto out; + } + memset(page_virt, 0, PAGE_CACHE_SIZE); + rc = ecryptfs_write_headers_virt(page_virt, crypt_stat, + ecryptfs_dentry); + if (unlikely(rc)) { + ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); + memset(page_virt, 0, PAGE_CACHE_SIZE); + goto out_free; + } + ecryptfs_printk(KERN_DEBUG, + "Writing key packet set to underlying file\n"); + lower_file->f_pos = 0; + oldfs = get_fs(); + set_fs(get_ds()); + ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->" + "write() w/ header page; lower_file->f_pos = " + "[0x%.16x]\n", lower_file->f_pos); + lower_file->f_op->write(lower_file, (char __user *)page_virt, + PAGE_CACHE_SIZE, &lower_file->f_pos); + header_pages = ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + / PAGE_CACHE_SIZE); + memset(page_virt, 0, PAGE_CACHE_SIZE); + current_header_page = 1; + while (current_header_page < header_pages) { + ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->" + "write() w/ zero'd page; lower_file->f_pos = " + "[0x%.16x]\n", lower_file->f_pos); + lower_file->f_op->write(lower_file, (char __user *)page_virt, + PAGE_CACHE_SIZE, &lower_file->f_pos); + current_header_page++; + } + set_fs(oldfs); + ecryptfs_printk(KERN_DEBUG, + "Done writing key packet set to underlying file.\n"); +out_free: + kmem_cache_free(ecryptfs_header_cache_0, page_virt); +out: + return rc; +} + +static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, + char *virt, int *bytes_read) +{ + int rc = 0; + u32 header_extent_size; + u16 num_header_extents_at_front; + + memcpy(&header_extent_size, virt, 4); + header_extent_size = be32_to_cpu(header_extent_size); + virt += 4; + memcpy(&num_header_extents_at_front, virt, 2); + num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front); + crypt_stat->header_extent_size = (int)header_extent_size; + crypt_stat->num_header_extents_at_front = + (int)num_header_extents_at_front; + (*bytes_read) = 6; + if ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, "Invalid header extent size: " + "[%d]\n", crypt_stat->header_extent_size); + } + return rc; +} + +/** + * set_default_header_data + * + * For version 0 file format; this function is only for backwards + * compatibility for files created with the prior versions of + * eCryptfs. + */ +static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) +{ + crypt_stat->header_extent_size = 4096; + crypt_stat->num_header_extents_at_front = 1; +} + +/** + * ecryptfs_read_headers_virt + * + * Read/parse the header data. The header format is detailed in the + * comment block for the ecryptfs_write_headers_virt() function. + * + * Returns zero on success + */ +static int ecryptfs_read_headers_virt(char *page_virt, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry) +{ + int rc = 0; + int offset; + int bytes_read; + + ecryptfs_set_default_sizes(crypt_stat); + crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + offset = ECRYPTFS_FILE_SIZE_BYTES; + rc = contains_ecryptfs_marker(page_virt + offset); + if (rc == 0) { + rc = -EINVAL; + goto out; + } + offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; + rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset), + &bytes_read); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error processing flags\n"); + goto out; + } + if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) { + ecryptfs_printk(KERN_WARNING, "File version is [%d]; only " + "file version [%d] is supported by this " + "version of eCryptfs\n", + crypt_stat->file_version, + ECRYPTFS_SUPPORTED_FILE_VERSION); + rc = -EINVAL; + goto out; + } + offset += bytes_read; + if (crypt_stat->file_version >= 1) { + rc = parse_header_metadata(crypt_stat, (page_virt + offset), + &bytes_read); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error reading header " + "metadata; rc = [%d]\n", rc); + } + offset += bytes_read; + } else + set_default_header_data(crypt_stat); + rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset), + ecryptfs_dentry); +out: + return rc; +} + +/** + * ecryptfs_read_headers + * + * Returns zero if valid headers found and parsed; non-zero otherwise + */ +int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, + struct file *lower_file) +{ + int rc = 0; + char *page_virt = NULL; + mm_segment_t oldfs; + ssize_t bytes_read; + struct ecryptfs_crypt_stat *crypt_stat = + &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); + if (!page_virt) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n"); + goto out; + } + lower_file->f_pos = 0; + oldfs = get_fs(); + set_fs(get_ds()); + bytes_read = lower_file->f_op->read(lower_file, + (char __user *)page_virt, + ECRYPTFS_DEFAULT_EXTENT_SIZE, + &lower_file->f_pos); + set_fs(oldfs); + if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) { + rc = -EINVAL; + goto out; + } + rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, + ecryptfs_dentry); + if (rc) { + ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not " + "found\n"); + rc = -EINVAL; + } +out: + if (page_virt) { + memset(page_virt, 0, PAGE_CACHE_SIZE); + kmem_cache_free(ecryptfs_header_cache_1, page_virt); + } + return rc; +} + +/** + * ecryptfs_encode_filename - converts a plaintext file name to cipher text + * @crypt_stat: The crypt_stat struct associated with the file anem to encode + * @name: The plaintext name + * @length: The length of the plaintext + * @encoded_name: The encypted name + * + * Encrypts and encodes a filename into something that constitutes a + * valid filename for a filesystem, with printable characters. + * + * We assume that we have a properly initialized crypto context, + * pointed to by crypt_stat->tfm. + * + * TODO: Implement filename decoding and decryption here, in place of + * memcpy. We are keeping the framework around for now to (1) + * facilitate testing of the components needed to implement filename + * encryption and (2) to provide a code base from which other + * developers in the community can easily implement this feature. + * + * Returns the length of encoded filename; negative if error + */ +int +ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat, + const char *name, int length, char **encoded_name) +{ + int error = 0; + + (*encoded_name) = kmalloc(length + 2, GFP_KERNEL); + if (!(*encoded_name)) { + error = -ENOMEM; + goto out; + } + /* TODO: Filename encryption is a scheduled feature for a + * future version of eCryptfs. This function is here only for + * the purpose of providing a framework for other developers + * to easily implement filename encryption. Hint: Replace this + * memcpy() with a call to encrypt and encode the + * filename, the set the length accordingly. */ + memcpy((void *)(*encoded_name), (void *)name, length); + (*encoded_name)[length] = '\0'; + error = length + 1; +out: + return error; +} + +/** + * ecryptfs_decode_filename - converts the cipher text name to plaintext + * @crypt_stat: The crypt_stat struct associated with the file + * @name: The filename in cipher text + * @length: The length of the cipher text name + * @decrypted_name: The plaintext name + * + * Decodes and decrypts the filename. + * + * We assume that we have a properly initialized crypto context, + * pointed to by crypt_stat->tfm. + * + * TODO: Implement filename decoding and decryption here, in place of + * memcpy. We are keeping the framework around for now to (1) + * facilitate testing of the components needed to implement filename + * encryption and (2) to provide a code base from which other + * developers in the community can easily implement this feature. + * + * Returns the length of decoded filename; negative if error + */ +int +ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat, + const char *name, int length, char **decrypted_name) +{ + int error = 0; + + (*decrypted_name) = kmalloc(length + 2, GFP_KERNEL); + if (!(*decrypted_name)) { + error = -ENOMEM; + goto out; + } + /* TODO: Filename encryption is a scheduled feature for a + * future version of eCryptfs. This function is here only for + * the purpose of providing a framework for other developers + * to easily implement filename encryption. Hint: Replace this + * memcpy() with a call to decode and decrypt the + * filename, the set the length accordingly. */ + memcpy((void *)(*decrypted_name), (void *)name, length); + (*decrypted_name)[length + 1] = '\0'; /* Only for convenience + * in printing out the + * string in debug + * messages */ + error = length; +out: + return error; +} + +/** + * ecryptfs_process_cipher - Perform cipher initialization. + * @tfm: Crypto context set by this function + * @key_tfm: Crypto context for key material, set by this function + * @cipher_name: Name of the cipher. + * @key_size: Size of the key in bytes. + * + * Returns zero on success. Any crypto_tfm structs allocated here + * should be released by other functions, such as on a superblock put + * event, regardless of whether this function succeeds for fails. + */ +int +ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm, + char *cipher_name, size_t key_size) +{ + char dummy_key[ECRYPTFS_MAX_KEY_BYTES]; + int rc; + + *tfm = *key_tfm = NULL; + if (key_size > ECRYPTFS_MAX_KEY_BYTES) { + rc = -EINVAL; + printk(KERN_ERR "Requested key size is [%Zd] bytes; maximum " + "allowable is [%d]\n", key_size, ECRYPTFS_MAX_KEY_BYTES); + goto out; + } + *tfm = crypto_alloc_tfm(cipher_name, (ECRYPTFS_DEFAULT_CHAINING_MODE + | CRYPTO_TFM_REQ_WEAK_KEY)); + if (!(*tfm)) { + rc = -EINVAL; + printk(KERN_ERR "Unable to allocate crypto cipher with name " + "[%s]\n", cipher_name); + goto out; + } + *key_tfm = crypto_alloc_tfm(cipher_name, CRYPTO_TFM_REQ_WEAK_KEY); + if (!(*key_tfm)) { + rc = -EINVAL; + printk(KERN_ERR "Unable to allocate crypto cipher with name " + "[%s]\n", cipher_name); + goto out; + } + if (key_size < crypto_tfm_alg_min_keysize(*tfm)) { + rc = -EINVAL; + printk(KERN_ERR "Request key size is [%Zd]; minimum key size " + "supported by cipher [%s] is [%d]\n", key_size, + cipher_name, crypto_tfm_alg_min_keysize(*tfm)); + goto out; + } + if (key_size < crypto_tfm_alg_min_keysize(*key_tfm)) { + rc = -EINVAL; + printk(KERN_ERR "Request key size is [%Zd]; minimum key size " + "supported by cipher [%s] is [%d]\n", key_size, + cipher_name, crypto_tfm_alg_min_keysize(*key_tfm)); + goto out; + } + if (key_size > crypto_tfm_alg_max_keysize(*tfm)) { + rc = -EINVAL; + printk(KERN_ERR "Request key size is [%Zd]; maximum key size " + "supported by cipher [%s] is [%d]\n", key_size, + cipher_name, crypto_tfm_alg_min_keysize(*tfm)); + goto out; + } + if (key_size > crypto_tfm_alg_max_keysize(*key_tfm)) { + rc = -EINVAL; + printk(KERN_ERR "Request key size is [%Zd]; maximum key size " + "supported by cipher [%s] is [%d]\n", key_size, + cipher_name, crypto_tfm_alg_min_keysize(*key_tfm)); + goto out; + } + get_random_bytes(dummy_key, key_size); + rc = crypto_cipher_setkey(*tfm, dummy_key, key_size); + if (rc) { + printk(KERN_ERR "Error attempting to set key of size [%Zd] for " + "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc); + rc = -EINVAL; + goto out; + } + rc = crypto_cipher_setkey(*key_tfm, dummy_key, key_size); + if (rc) { + printk(KERN_ERR "Error attempting to set key of size [%Zd] for " + "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc); + rc = -EINVAL; + goto out; + } +out: + return rc; +} diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c new file mode 100644 index 00000000000..61f8e894284 --- /dev/null +++ b/fs/ecryptfs/debug.c @@ -0,0 +1,123 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * Functions only useful for debugging. + * + * Copyright (C) 2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * + * 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 "ecryptfs_kernel.h" + +/** + * ecryptfs_dump_auth_tok - debug function to print auth toks + * + * This function will print the contents of an ecryptfs authentication + * token. + */ +void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok) +{ + char salt[ECRYPTFS_SALT_SIZE * 2 + 1]; + char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; + + ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n", + auth_tok); + if (ECRYPTFS_CHECK_FLAG(auth_tok->flags, ECRYPTFS_PRIVATE_KEY)) { + ecryptfs_printk(KERN_DEBUG, " * private key type\n"); + ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT " + "IN ECRYPTFS VERSION 0.1)\n"); + } else { + ecryptfs_printk(KERN_DEBUG, " * passphrase type\n"); + ecryptfs_to_hex(salt, auth_tok->token.password.salt, + ECRYPTFS_SALT_SIZE); + salt[ECRYPTFS_SALT_SIZE * 2] = '\0'; + ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt); + if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags, + ECRYPTFS_PERSISTENT_PASSWORD)) { + ecryptfs_printk(KERN_DEBUG, " * persistent\n"); + } + memcpy(sig, auth_tok->token.password.signature, + ECRYPTFS_SIG_SIZE_HEX); + sig[ECRYPTFS_SIG_SIZE_HEX] = '\0'; + ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig); + } + ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n", + auth_tok->session_key.flags); + if (auth_tok->session_key.flags + & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT) + ecryptfs_printk(KERN_DEBUG, + " * Userspace decrypt request set\n"); + if (auth_tok->session_key.flags + & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT) + ecryptfs_printk(KERN_DEBUG, + " * Userspace encrypt request set\n"); + if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) { + ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n"); + ecryptfs_printk(KERN_DEBUG, + " * session_key.decrypted_key_size = [0x%x]\n", + auth_tok->session_key.decrypted_key_size); + ecryptfs_printk(KERN_DEBUG, " * Decrypted session key " + "dump:\n"); + if (ecryptfs_verbosity > 0) + ecryptfs_dump_hex(auth_tok->session_key.decrypted_key, + ECRYPTFS_DEFAULT_KEY_BYTES); + } + if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) { + ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n"); + ecryptfs_printk(KERN_DEBUG, + " * session_key.encrypted_key_size = [0x%x]\n", + auth_tok->session_key.encrypted_key_size); + ecryptfs_printk(KERN_DEBUG, " * Encrypted session key " + "dump:\n"); + if (ecryptfs_verbosity > 0) + ecryptfs_dump_hex(auth_tok->session_key.encrypted_key, + auth_tok->session_key. + encrypted_key_size); + } +} + +/** + * ecryptfs_dump_hex - debug hex printer + * @data: string of bytes to be printed + * @bytes: number of bytes to print + * + * Dump hexadecimal representation of char array + */ +void ecryptfs_dump_hex(char *data, int bytes) +{ + int i = 0; + int add_newline = 1; + + if (ecryptfs_verbosity < 1) + return; + if (bytes != 0) { + printk(KERN_DEBUG "0x%.2x.", (unsigned char)data[i]); + i++; + } + while (i < bytes) { + printk("0x%.2x.", (unsigned char)data[i]); + i++; + if (i % 16 == 0) { + printk("\n"); + add_newline = 0; + } else + add_newline = 1; + } + if (add_newline) + printk("\n"); +} + diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c new file mode 100644 index 00000000000..f0d2a433242 --- /dev/null +++ b/fs/ecryptfs/dentry.c @@ -0,0 +1,87 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2003 Erez Zadok + * Copyright (C) 2001-2003 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * + * 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 "ecryptfs_kernel.h" + +/** + * ecryptfs_d_revalidate - revalidate an ecryptfs dentry + * @dentry: The ecryptfs dentry + * @nd: The associated nameidata + * + * Called when the VFS needs to revalidate a dentry. This + * is called whenever a name lookup finds a dentry in the + * dcache. Most filesystems leave this as NULL, because all their + * dentries in the dcache are valid. + * + * Returns 1 if valid, 0 otherwise. + * + */ +static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); + struct dentry *dentry_save; + struct vfsmount *vfsmount_save; + int rc = 1; + + if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) + goto out; + dentry_save = nd->dentry; + vfsmount_save = nd->mnt; + nd->dentry = lower_dentry; + nd->mnt = lower_mnt; + rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd); + nd->dentry = dentry_save; + nd->mnt = vfsmount_save; +out: + return rc; +} + +struct kmem_cache *ecryptfs_dentry_info_cache; + +/** + * ecryptfs_d_release + * @dentry: The ecryptfs dentry + * + * Called when a dentry is really deallocated. + */ +static void ecryptfs_d_release(struct dentry *dentry) +{ + struct dentry *lower_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (ecryptfs_dentry_to_private(dentry)) + kmem_cache_free(ecryptfs_dentry_info_cache, + ecryptfs_dentry_to_private(dentry)); + if (lower_dentry) + dput(lower_dentry); + return; +} + +struct dentry_operations ecryptfs_dops = { + .d_revalidate = ecryptfs_d_revalidate, + .d_release = ecryptfs_d_release, +}; diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h new file mode 100644 index 00000000000..872c9958531 --- /dev/null +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -0,0 +1,482 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * Kernel declarations. + * + * Copyright (C) 1997-2003 Erez Zadok + * Copyright (C) 2001-2003 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * + * 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 ECRYPTFS_KERNEL_H +#define ECRYPTFS_KERNEL_H + +#include +#include +#include + +/* Version verification for shared data structures w/ userspace */ +#define ECRYPTFS_VERSION_MAJOR 0x00 +#define ECRYPTFS_VERSION_MINOR 0x04 +#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x01 +/* These flags indicate which features are supported by the kernel + * module; userspace tools such as the mount helper read + * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine + * how to behave. */ +#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001 +#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002 +#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004 +#define ECRYPTFS_VERSIONING_POLICY 0x00000008 +#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \ + | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH) + +#define ECRYPTFS_MAX_PASSWORD_LENGTH 64 +#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH +#define ECRYPTFS_SALT_SIZE 8 +#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2) +/* The original signature size is only for what is stored on disk; all + * in-memory representations are expanded hex, so it better adapted to + * be passed around or referenced on the command line */ +#define ECRYPTFS_SIG_SIZE 8 +#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2) +#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX +#define ECRYPTFS_MAX_KEY_BYTES 64 +#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512 +#define ECRYPTFS_DEFAULT_IV_BYTES 16 +#define ECRYPTFS_FILE_VERSION 0x01 +#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192 +#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 +#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192 + +#define RFC2440_CIPHER_DES3_EDE 0x02 +#define RFC2440_CIPHER_CAST_5 0x03 +#define RFC2440_CIPHER_BLOWFISH 0x04 +#define RFC2440_CIPHER_AES_128 0x07 +#define RFC2440_CIPHER_AES_192 0x08 +#define RFC2440_CIPHER_AES_256 0x09 +#define RFC2440_CIPHER_TWOFISH 0x0a +#define RFC2440_CIPHER_CAST_6 0x0b + +#define ECRYPTFS_SET_FLAG(flag_bit_vector, flag) (flag_bit_vector |= (flag)) +#define ECRYPTFS_CLEAR_FLAG(flag_bit_vector, flag) (flag_bit_vector &= ~(flag)) +#define ECRYPTFS_CHECK_FLAG(flag_bit_vector, flag) (flag_bit_vector & (flag)) + +/** + * For convenience, we may need to pass around the encrypted session + * key between kernel and userspace because the authentication token + * may not be extractable. For example, the TPM may not release the + * private key, instead requiring the encrypted data and returning the + * decrypted data. + */ +struct ecryptfs_session_key { +#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001 +#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002 +#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004 +#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008 + u32 flags; + u32 encrypted_key_size; + u32 decrypted_key_size; + u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES]; + u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES]; +}; + +struct ecryptfs_password { + u32 password_bytes; + s32 hash_algo; + u32 hash_iterations; + u32 session_key_encryption_key_bytes; +#define ECRYPTFS_PERSISTENT_PASSWORD 0x01 +#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02 + u32 flags; + /* Iterated-hash concatenation of salt and passphrase */ + u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES]; + u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1]; + /* Always in expanded hex */ + u8 salt[ECRYPTFS_SALT_SIZE]; +}; + +enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY}; + +/* May be a password or a private key */ +struct ecryptfs_auth_tok { + u16 version; /* 8-bit major and 8-bit minor */ + u16 token_type; + u32 flags; + struct ecryptfs_session_key session_key; + u8 reserved[32]; + union { + struct ecryptfs_password password; + /* Private key is in future eCryptfs releases */ + } token; +} __attribute__ ((packed)); + +void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok); +extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size); +extern void ecryptfs_from_hex(char *dst, char *src, int dst_size); + +struct ecryptfs_key_record { + unsigned char type; + size_t enc_key_size; + unsigned char sig[ECRYPTFS_SIG_SIZE]; + unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES]; +}; + +struct ecryptfs_auth_tok_list { + struct ecryptfs_auth_tok *auth_tok; + struct list_head list; +}; + +struct ecryptfs_crypt_stat; +struct ecryptfs_mount_crypt_stat; + +struct ecryptfs_page_crypt_context { + struct page *page; +#define ECRYPTFS_PREPARE_COMMIT_MODE 0 +#define ECRYPTFS_WRITEPAGE_MODE 1 + unsigned int mode; + union { + struct file *lower_file; + struct writeback_control *wbc; + } param; +}; + +static inline struct ecryptfs_auth_tok * +ecryptfs_get_key_payload_data(struct key *key) +{ + return (struct ecryptfs_auth_tok *) + (((struct user_key_payload*)key->payload.data)->data); +} + +#define ECRYPTFS_SUPER_MAGIC 0xf15f +#define ECRYPTFS_MAX_KEYSET_SIZE 1024 +#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32 +#define ECRYPTFS_MAX_NUM_ENC_KEYS 64 +#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */ +#define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */ +#define ECRYPTFS_SALT_BYTES 2 +#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5 +#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */ +#define ECRYPTFS_FILE_SIZE_BYTES 8 +#define ECRYPTFS_DEFAULT_CIPHER "aes" +#define ECRYPTFS_DEFAULT_KEY_BYTES 16 +#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC +#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C +#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED +#define MD5_DIGEST_SIZE 16 + +/** + * This is the primary struct associated with each encrypted file. + * + * TODO: cache align/pack? + */ +struct ecryptfs_crypt_stat { +#define ECRYPTFS_STRUCT_INITIALIZED 0x00000001 +#define ECRYPTFS_POLICY_APPLIED 0x00000002 +#define ECRYPTFS_NEW_FILE 0x00000004 +#define ECRYPTFS_ENCRYPTED 0x00000008 +#define ECRYPTFS_SECURITY_WARNING 0x00000010 +#define ECRYPTFS_ENABLE_HMAC 0x00000020 +#define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040 +#define ECRYPTFS_KEY_VALID 0x00000080 + u32 flags; + unsigned int file_version; + size_t iv_bytes; + size_t num_keysigs; + size_t header_extent_size; + size_t num_header_extents_at_front; + size_t extent_size; /* Data extent size; default is 4096 */ + size_t key_size; + size_t extent_shift; + unsigned int extent_mask; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; + struct crypto_tfm *tfm; + struct crypto_tfm *md5_tfm; /* Crypto context for generating + * the initialization vectors */ + unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; + unsigned char key[ECRYPTFS_MAX_KEY_BYTES]; + unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES]; + unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX]; + struct mutex cs_tfm_mutex; + struct mutex cs_md5_tfm_mutex; + struct mutex cs_mutex; +}; + +/* inode private data. */ +struct ecryptfs_inode_info { + struct inode vfs_inode; + struct inode *wii_inode; + struct ecryptfs_crypt_stat crypt_stat; +}; + +/* dentry private data. Each dentry must keep track of a lower + * vfsmount too. */ +struct ecryptfs_dentry_info { + struct dentry *wdi_dentry; + struct vfsmount *lower_mnt; + struct ecryptfs_crypt_stat *crypt_stat; +}; + +/** + * This struct is to enable a mount-wide passphrase/salt combo. This + * is more or less a stopgap to provide similar functionality to other + * crypto filesystems like EncFS or CFS until full policy support is + * implemented in eCryptfs. + */ +struct ecryptfs_mount_crypt_stat { + /* Pointers to memory we do not own, do not free these */ +#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001 + u32 flags; + struct ecryptfs_auth_tok *global_auth_tok; + struct key *global_auth_tok_key; + size_t global_default_cipher_key_size; + struct crypto_tfm *global_key_tfm; + struct mutex global_key_tfm_mutex; + unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + + 1]; + unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1]; +}; + +/* superblock private data. */ +struct ecryptfs_sb_info { + struct super_block *wsi_sb; + struct ecryptfs_mount_crypt_stat mount_crypt_stat; +}; + +/* file private data. */ +struct ecryptfs_file_info { + struct file *wfi_file; + struct ecryptfs_crypt_stat *crypt_stat; +}; + +/* auth_tok <=> encrypted_session_key mappings */ +struct ecryptfs_auth_tok_list_item { + unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES]; + struct list_head list; + struct ecryptfs_auth_tok auth_tok; +}; + +static inline struct ecryptfs_file_info * +ecryptfs_file_to_private(struct file *file) +{ + return (struct ecryptfs_file_info *)file->private_data; +} + +static inline void +ecryptfs_set_file_private(struct file *file, + struct ecryptfs_file_info *file_info) +{ + file->private_data = file_info; +} + +static inline struct file *ecryptfs_file_to_lower(struct file *file) +{ + return ((struct ecryptfs_file_info *)file->private_data)->wfi_file; +} + +static inline void +ecryptfs_set_file_lower(struct file *file, struct file *lower_file) +{ + ((struct ecryptfs_file_info *)file->private_data)->wfi_file = + lower_file; +} + +static inline struct ecryptfs_inode_info * +ecryptfs_inode_to_private(struct inode *inode) +{ + return container_of(inode, struct ecryptfs_inode_info, vfs_inode); +} + +static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode) +{ + return ecryptfs_inode_to_private(inode)->wii_inode; +} + +static inline void +ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode) +{ + ecryptfs_inode_to_private(inode)->wii_inode = lower_inode; +} + +static inline struct ecryptfs_sb_info * +ecryptfs_superblock_to_private(struct super_block *sb) +{ + return (struct ecryptfs_sb_info *)sb->s_fs_info; +} + +static inline void +ecryptfs_set_superblock_private(struct super_block *sb, + struct ecryptfs_sb_info *sb_info) +{ + sb->s_fs_info = sb_info; +} + +static inline struct super_block * +ecryptfs_superblock_to_lower(struct super_block *sb) +{ + return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb; +} + +static inline void +ecryptfs_set_superblock_lower(struct super_block *sb, + struct super_block *lower_sb) +{ + ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb; +} + +static inline struct ecryptfs_dentry_info * +ecryptfs_dentry_to_private(struct dentry *dentry) +{ + return (struct ecryptfs_dentry_info *)dentry->d_fsdata; +} + +static inline void +ecryptfs_set_dentry_private(struct dentry *dentry, + struct ecryptfs_dentry_info *dentry_info) +{ + dentry->d_fsdata = dentry_info; +} + +static inline struct dentry * +ecryptfs_dentry_to_lower(struct dentry *dentry) +{ + return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry; +} + +static inline void +ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry) +{ + ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry = + lower_dentry; +} + +static inline struct vfsmount * +ecryptfs_dentry_to_lower_mnt(struct dentry *dentry) +{ + return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt; +} + +static inline void +ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt) +{ + ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt = + lower_mnt; +} + +#define ecryptfs_printk(type, fmt, arg...) \ + __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg); +void __ecryptfs_printk(const char *fmt, ...); + +extern const struct file_operations ecryptfs_main_fops; +extern const struct file_operations ecryptfs_dir_fops; +extern struct inode_operations ecryptfs_main_iops; +extern struct inode_operations ecryptfs_dir_iops; +extern struct inode_operations ecryptfs_symlink_iops; +extern struct super_operations ecryptfs_sops; +extern struct dentry_operations ecryptfs_dops; +extern struct address_space_operations ecryptfs_aops; +extern int ecryptfs_verbosity; + +extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache; +extern struct kmem_cache *ecryptfs_file_info_cache; +extern struct kmem_cache *ecryptfs_dentry_info_cache; +extern struct kmem_cache *ecryptfs_inode_info_cache; +extern struct kmem_cache *ecryptfs_sb_info_cache; +extern struct kmem_cache *ecryptfs_header_cache_0; +extern struct kmem_cache *ecryptfs_header_cache_1; +extern struct kmem_cache *ecryptfs_header_cache_2; +extern struct kmem_cache *ecryptfs_lower_page_cache; + +int ecryptfs_interpose(struct dentry *hidden_dentry, + struct dentry *this_dentry, struct super_block *sb, + int flag); +int ecryptfs_fill_zeros(struct file *file, loff_t new_length); +int ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat, + const char *name, int length, + char **decrypted_name); +int ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat, + const char *name, int length, + char **encoded_name); +struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry); +void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src); +void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src); +void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src); +void ecryptfs_dump_hex(char *data, int bytes); +int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, + int sg_size); +int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat); +void ecryptfs_rotate_iv(unsigned char *iv); +void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat); +void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat); +void ecryptfs_destruct_mount_crypt_stat( + struct ecryptfs_mount_crypt_stat *mount_crypt_stat); +int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_write_inode_size_to_header(struct file *lower_file, + struct inode *lower_inode, + struct inode *inode); +int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, + struct file *lower_file, + unsigned long lower_page_index, int byte_offset, + int region_bytes); +int +ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, + struct file *lower_file, int byte_offset, + int region_size); +int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, + struct file *lower_file); +int ecryptfs_do_readpage(struct file *file, struct page *page, + pgoff_t lower_page_index); +int ecryptfs_grab_and_map_lower_page(struct page **lower_page, + char **lower_virt, + struct inode *lower_inode, + unsigned long lower_page_index); +int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, + struct inode *lower_inode, + struct writeback_control *wbc); +int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx); +int ecryptfs_decrypt_page(struct file *file, struct page *page); +int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, + struct file *lower_file); +int ecryptfs_write_headers_virt(char *page_virt, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry); +int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, + struct file *lower_file); +int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry); +int contains_ecryptfs_marker(char *data); +int ecryptfs_read_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt); +u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code); +void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_generate_key_packet_set(char *dest_base, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry, + size_t *len, size_t max); +int process_request_key_err(long err_code); +int +ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, + unsigned char *src, struct dentry *ecryptfs_dentry); +int ecryptfs_truncate(struct dentry *dentry, loff_t new_length); +int +ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm, + char *cipher_name, size_t key_size); +int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode); +int ecryptfs_inode_set(struct inode *inode, void *lower_inode); +void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode); + +#endif /* #ifndef ECRYPTFS_KERNEL_H */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c new file mode 100644 index 00000000000..c8550c9f9cd --- /dev/null +++ b/fs/ecryptfs/file.c @@ -0,0 +1,440 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2004 Erez Zadok + * Copyright (C) 2001-2004 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * Michael C. Thompson + * + * 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 +#include +#include "ecryptfs_kernel.h" + +/** + * ecryptfs_llseek + * @file: File we are seeking in + * @offset: The offset to seek to + * @origin: 2 - offset from i_size; 1 - offset from f_pos + * + * Returns the position we have seeked to, or negative on error + */ +static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t rv; + loff_t new_end_pos; + int rc; + int expanding_file = 0; + struct inode *inode = file->f_mapping->host; + + /* If our offset is past the end of our file, we're going to + * need to grow it so we have a valid length of 0's */ + new_end_pos = offset; + switch (origin) { + case 2: + new_end_pos += i_size_read(inode); + expanding_file = 1; + break; + case 1: + new_end_pos += file->f_pos; + if (new_end_pos > i_size_read(inode)) { + ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " + "> i_size_read(inode)(=[0x%.16x])\n", + new_end_pos, i_size_read(inode)); + expanding_file = 1; + } + break; + default: + if (new_end_pos > i_size_read(inode)) { + ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " + "> i_size_read(inode)(=[0x%.16x])\n", + new_end_pos, i_size_read(inode)); + expanding_file = 1; + } + } + ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos); + if (expanding_file) { + rc = ecryptfs_truncate(file->f_dentry, new_end_pos); + if (rc) { + rv = rc; + ecryptfs_printk(KERN_ERR, "Error on attempt to " + "truncate to (higher) offset [0x%.16x];" + " rc = [%d]\n", new_end_pos, rc); + goto out; + } + } + rv = generic_file_llseek(file, offset, origin); +out: + return rv; +} + +/** + * ecryptfs_read_update_atime + * + * generic_file_read updates the atime of upper layer inode. But, it + * doesn't give us a chance to update the atime of the lower layer + * inode. This function is a wrapper to generic_file_read. It + * updates the atime of the lower level inode if generic_file_read + * returns without any errors. This is to be used only for file reads. + * The function to be used for directory reads is ecryptfs_read. + */ +static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) +{ + int rc; + struct dentry *lower_dentry; + struct vfsmount *lower_vfsmount; + struct file *file = iocb->ki_filp; + + rc = generic_file_aio_read(iocb, iov, nr_segs, pos); + /* + * Even though this is a async interface, we need to wait + * for IO to finish to update atime + */ + if (-EIOCBQUEUED == rc) + rc = wait_on_sync_kiocb(iocb); + if (rc >= 0) { + lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry); + lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry); + touch_atime(lower_vfsmount, lower_dentry); + } + return rc; +} + +struct ecryptfs_getdents_callback { + void *dirent; + struct dentry *dentry; + filldir_t filldir; + int err; + int filldir_called; + int entries_written; +}; + +/* Inspired by generic filldir in fs/readir.c */ +static int +ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset, + u64 ino, unsigned int d_type) +{ + struct ecryptfs_crypt_stat *crypt_stat; + struct ecryptfs_getdents_callback *buf = + (struct ecryptfs_getdents_callback *)dirent; + int rc; + int decoded_length; + char *decoded_name; + + crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat; + buf->filldir_called++; + decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen, + &decoded_name); + if (decoded_length < 0) { + rc = decoded_length; + goto out; + } + rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset, + ino, d_type); + kfree(decoded_name); + if (rc >= 0) + buf->entries_written++; +out: + return rc; +} + +/** + * ecryptfs_readdir + * @file: The ecryptfs file struct + * @dirent: Directory entry + * @filldir: The filldir callback function + */ +static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int rc; + struct file *lower_file; + struct inode *inode; + struct ecryptfs_getdents_callback buf; + + lower_file = ecryptfs_file_to_lower(file); + lower_file->f_pos = file->f_pos; + inode = file->f_dentry->d_inode; + memset(&buf, 0, sizeof(buf)); + buf.dirent = dirent; + buf.dentry = file->f_dentry; + buf.filldir = filldir; +retry: + buf.filldir_called = 0; + buf.entries_written = 0; + buf.err = 0; + rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf); + if (buf.err) + rc = buf.err; + if (buf.filldir_called && !buf.entries_written) + goto retry; + file->f_pos = lower_file->f_pos; + if (rc >= 0) + ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode); + return rc; +} + +struct kmem_cache *ecryptfs_file_info_cache; + +/** + * ecryptfs_open + * @inode: inode speciying file to open + * @file: Structure to return filled in + * + * Opens the file specified by inode. + * + * Returns zero on success; non-zero otherwise + */ +static int ecryptfs_open(struct inode *inode, struct file *file) +{ + int rc = 0; + struct ecryptfs_crypt_stat *crypt_stat = NULL; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; + struct dentry *ecryptfs_dentry = file->f_dentry; + /* Private value of ecryptfs_dentry allocated in + * ecryptfs_lookup() */ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + struct inode *lower_inode = NULL; + struct file *lower_file = NULL; + struct vfsmount *lower_mnt; + struct ecryptfs_file_info *file_info; + int lower_flags; + + /* Released in ecryptfs_release or end of function if failure */ + file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL); + ecryptfs_set_file_private(file, file_info); + if (!file_info) { + ecryptfs_printk(KERN_ERR, + "Error attempting to allocate memory\n"); + rc = -ENOMEM; + goto out; + } + memset(file_info, 0, sizeof(*file_info)); + lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + mount_crypt_stat = &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + mutex_lock(&crypt_stat->cs_mutex); + if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) { + ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); + /* Policy code enabled in future release */ + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED); + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + } + mutex_unlock(&crypt_stat->cs_mutex); + /* This mntget & dget is undone via fput when the file is released */ + dget(lower_dentry); + lower_flags = file->f_flags; + if ((lower_flags & O_ACCMODE) == O_WRONLY) + lower_flags = (lower_flags & O_ACCMODE) | O_RDWR; + if (file->f_flags & O_APPEND) + lower_flags &= ~O_APPEND; + lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); + mntget(lower_mnt); + /* Corresponding fput() in ecryptfs_release() */ + lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags); + if (IS_ERR(lower_file)) { + rc = PTR_ERR(lower_file); + ecryptfs_printk(KERN_ERR, "Error opening lower file\n"); + goto out_puts; + } + ecryptfs_set_file_lower(file, lower_file); + /* Isn't this check the same as the one in lookup? */ + lower_inode = lower_dentry->d_inode; + if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { + ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); + ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + rc = 0; + goto out; + } + mutex_lock(&crypt_stat->cs_mutex); + if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { + if (!(mount_crypt_stat->flags + & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { + rc = -EIO; + printk(KERN_WARNING "Attempt to read file that is " + "not in a valid eCryptfs format, and plaintext " + "passthrough mode is not enabled; returning " + "-EIO\n"); + mutex_unlock(&crypt_stat->cs_mutex); + goto out_puts; + } + crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); + rc = 0; + mutex_unlock(&crypt_stat->cs_mutex); + goto out; + } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, + ECRYPTFS_POLICY_APPLIED) + || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, + ECRYPTFS_KEY_VALID)) { + rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file); + if (rc) { + ecryptfs_printk(KERN_DEBUG, + "Valid headers not found\n"); + if (!(mount_crypt_stat->flags + & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { + rc = -EIO; + printk(KERN_WARNING "Attempt to read file that " + "is not in a valid eCryptfs format, " + "and plaintext passthrough mode is not " + "enabled; returning -EIO\n"); + mutex_unlock(&crypt_stat->cs_mutex); + goto out_puts; + } + ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, + ECRYPTFS_ENCRYPTED); + rc = 0; + mutex_unlock(&crypt_stat->cs_mutex); + goto out; + } + } + mutex_unlock(&crypt_stat->cs_mutex); + ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " + "size: [0x%.16x]\n", inode, inode->i_ino, + i_size_read(inode)); + ecryptfs_set_file_lower(file, lower_file); + goto out; +out_puts: + mntput(lower_mnt); + dput(lower_dentry); + kmem_cache_free(ecryptfs_file_info_cache, + ecryptfs_file_to_private(file)); +out: + return rc; +} + +static int ecryptfs_flush(struct file *file, fl_owner_t td) +{ + int rc = 0; + struct file *lower_file = NULL; + + lower_file = ecryptfs_file_to_lower(file); + if (lower_file->f_op && lower_file->f_op->flush) + rc = lower_file->f_op->flush(lower_file, td); + return rc; +} + +static int ecryptfs_release(struct inode *inode, struct file *file) +{ + struct file *lower_file = ecryptfs_file_to_lower(file); + struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file); + struct inode *lower_inode = ecryptfs_inode_to_lower(inode); + + fput(lower_file); + inode->i_blocks = lower_inode->i_blocks; + kmem_cache_free(ecryptfs_file_info_cache, file_info); + return 0; +} + +static int +ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct file *lower_file = ecryptfs_file_to_lower(file); + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct inode *lower_inode = lower_dentry->d_inode; + int rc = -EINVAL; + + if (lower_inode->i_fop->fsync) { + mutex_lock(&lower_inode->i_mutex); + rc = lower_inode->i_fop->fsync(lower_file, lower_dentry, + datasync); + mutex_unlock(&lower_inode->i_mutex); + } + return rc; +} + +static int ecryptfs_fasync(int fd, struct file *file, int flag) +{ + int rc = 0; + struct file *lower_file = NULL; + + lower_file = ecryptfs_file_to_lower(file); + if (lower_file->f_op && lower_file->f_op->fasync) + rc = lower_file->f_op->fasync(fd, lower_file, flag); + return rc; +} + +static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos, + size_t count, read_actor_t actor, void *target) +{ + struct file *lower_file = NULL; + int rc = -EINVAL; + + lower_file = ecryptfs_file_to_lower(file); + if (lower_file->f_op && lower_file->f_op->sendfile) + rc = lower_file->f_op->sendfile(lower_file, ppos, count, + actor, target); + + return rc; +} + +static int ecryptfs_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +const struct file_operations ecryptfs_dir_fops = { + .readdir = ecryptfs_readdir, + .ioctl = ecryptfs_ioctl, + .mmap = generic_file_mmap, + .open = ecryptfs_open, + .flush = ecryptfs_flush, + .release = ecryptfs_release, + .fsync = ecryptfs_fsync, + .fasync = ecryptfs_fasync, + .sendfile = ecryptfs_sendfile, +}; + +const struct file_operations ecryptfs_main_fops = { + .llseek = ecryptfs_llseek, + .read = do_sync_read, + .aio_read = ecryptfs_read_update_atime, + .write = do_sync_write, + .aio_write = generic_file_aio_write, + .readdir = ecryptfs_readdir, + .ioctl = ecryptfs_ioctl, + .mmap = generic_file_mmap, + .open = ecryptfs_open, + .flush = ecryptfs_flush, + .release = ecryptfs_release, + .fsync = ecryptfs_fsync, + .fasync = ecryptfs_fasync, + .sendfile = ecryptfs_sendfile, +}; + +static int +ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rc = 0; + struct file *lower_file = NULL; + + if (ecryptfs_file_to_private(file)) + lower_file = ecryptfs_file_to_lower(file); + if (lower_file && lower_file->f_op && lower_file->f_op->ioctl) + rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode), + lower_file, cmd, arg); + else + rc = -ENOTTY; + return rc; +} diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c new file mode 100644 index 00000000000..efdd2b7b62d --- /dev/null +++ b/fs/ecryptfs/inode.c @@ -0,0 +1,1079 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2004 Erez Zadok + * Copyright (C) 2001-2004 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * Michael C. Thompsion + * + * 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 +#include +#include "ecryptfs_kernel.h" + +static struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir; + + dir = dget(dentry->d_parent); + mutex_lock(&(dir->d_inode->i_mutex)); + return dir; +} + +static void unlock_parent(struct dentry *dentry) +{ + mutex_unlock(&(dentry->d_parent->d_inode->i_mutex)); + dput(dentry->d_parent); +} + +static void unlock_dir(struct dentry *dir) +{ + mutex_unlock(&dir->d_inode->i_mutex); + dput(dir); +} + +void ecryptfs_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; +} + +void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src) +{ + dest->i_atime = src->i_atime; +} + +static void ecryptfs_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; +} + +static void ecryptfs_copy_attr_timesizes(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; + ecryptfs_copy_inode_size(dest, src); +} + +void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src) +{ + dest->i_mode = src->i_mode; + dest->i_nlink = src->i_nlink; + 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; +} + +/** + * ecryptfs_create_underlying_file + * @lower_dir_inode: inode of the parent in the lower fs of the new file + * @lower_dentry: New file's dentry in the lower fs + * @ecryptfs_dentry: New file's dentry in ecryptfs + * @mode: The mode of the new file + * @nd: nameidata of ecryptfs' parent's dentry & vfsmount + * + * Creates the file in the lower file system. + * + * Returns zero on success; non-zero on error condition + */ +static int +ecryptfs_create_underlying_file(struct inode *lower_dir_inode, + struct dentry *dentry, int mode, + struct nameidata *nd) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); + struct dentry *dentry_save; + struct vfsmount *vfsmount_save; + int rc; + + dentry_save = nd->dentry; + vfsmount_save = nd->mnt; + nd->dentry = lower_dentry; + nd->mnt = lower_mnt; + rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); + nd->dentry = dentry_save; + nd->mnt = vfsmount_save; + return rc; +} + +/** + * ecryptfs_do_create + * @directory_inode: inode of the new file's dentry's parent in ecryptfs + * @ecryptfs_dentry: New file's dentry in ecryptfs + * @mode: The mode of the new file + * @nd: nameidata of ecryptfs' parent's dentry & vfsmount + * + * Creates the underlying file and the eCryptfs inode which will link to + * it. It will also update the eCryptfs directory inode to mimic the + * stat of the lower directory inode. + * + * Returns zero on success; non-zero on error condition + */ +static int +ecryptfs_do_create(struct inode *directory_inode, + struct dentry *ecryptfs_dentry, int mode, + struct nameidata *nd) +{ + int rc; + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + if (unlikely(IS_ERR(lower_dir_dentry))) { + ecryptfs_printk(KERN_ERR, "Error locking directory of " + "dentry\n"); + rc = PTR_ERR(lower_dir_dentry); + goto out; + } + rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, + ecryptfs_dentry, mode, nd); + if (unlikely(rc)) { + ecryptfs_printk(KERN_ERR, + "Failure to create underlying file\n"); + goto out_lock; + } + rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, + directory_inode->i_sb, 0); + if (rc) { + ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n"); + goto out_lock; + } + ecryptfs_copy_attr_timesizes(directory_inode, + lower_dir_dentry->d_inode); +out_lock: + unlock_dir(lower_dir_dentry); +out: + return rc; +} + +/** + * grow_file + * @ecryptfs_dentry: the ecryptfs dentry + * @lower_file: The lower file + * @inode: The ecryptfs inode + * @lower_inode: The lower inode + * + * This is the code which will grow the file to its correct size. + */ +static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file, + struct inode *inode, struct inode *lower_inode) +{ + int rc = 0; + struct file fake_file; + struct ecryptfs_file_info tmp_file_info; + + memset(&fake_file, 0, sizeof(fake_file)); + fake_file.f_dentry = ecryptfs_dentry; + memset(&tmp_file_info, 0, sizeof(tmp_file_info)); + ecryptfs_set_file_private(&fake_file, &tmp_file_info); + ecryptfs_set_file_lower(&fake_file, lower_file); + rc = ecryptfs_fill_zeros(&fake_file, 1); + if (rc) { + ECRYPTFS_SET_FLAG( + ecryptfs_inode_to_private(inode)->crypt_stat.flags, + ECRYPTFS_SECURITY_WARNING); + ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros " + "in file; rc = [%d]\n", rc); + goto out; + } + i_size_write(inode, 0); + ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode); + ECRYPTFS_SET_FLAG(ecryptfs_inode_to_private(inode)->crypt_stat.flags, + ECRYPTFS_NEW_FILE); +out: + return rc; +} + +/** + * ecryptfs_initialize_file + * + * Cause the file to be changed from a basic empty file to an ecryptfs + * file with a header and first data page. + * + * Returns zero on success + */ +static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) +{ + int rc = 0; + int lower_flags; + struct ecryptfs_crypt_stat *crypt_stat; + struct dentry *lower_dentry; + struct dentry *tlower_dentry = NULL; + struct file *lower_file; + struct inode *inode, *lower_inode; + struct vfsmount *lower_mnt; + + lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n", + lower_dentry->d_name.name); + inode = ecryptfs_dentry->d_inode; + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + tlower_dentry = dget(lower_dentry); + if (!tlower_dentry) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry\n"); + goto out; + } + lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR; +#if BITS_PER_LONG != 32 + lower_flags |= O_LARGEFILE; +#endif + lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); + mntget(lower_mnt); + /* Corresponding fput() at end of this function */ + lower_file = dentry_open(tlower_dentry, lower_mnt, lower_flags); + if (IS_ERR(lower_file)) { + rc = PTR_ERR(lower_file); + ecryptfs_printk(KERN_ERR, + "Error opening dentry; rc = [%i]\n", rc); + goto out; + } + /* fput(lower_file) should handle the puts if we do this */ + lower_file->f_dentry = tlower_dentry; + lower_file->f_vfsmnt = lower_mnt; + lower_inode = tlower_dentry->d_inode; + if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { + ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); + ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + goto out_fput; + } + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE); + ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); + rc = ecryptfs_new_file_context(ecryptfs_dentry); + if (rc) { + ecryptfs_printk(KERN_DEBUG, "Error creating new file " + "context\n"); + goto out_fput; + } + rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file); + if (rc) { + ecryptfs_printk(KERN_DEBUG, "Error writing headers\n"); + goto out_fput; + } + rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode); +out_fput: + fput(lower_file); +out: + return rc; +} + +/** + * ecryptfs_create + * @dir: The inode of the directory in which to create the file. + * @dentry: The eCryptfs dentry + * @mode: The mode of the new file. + * @nd: nameidata + * + * Creates a new file. + * + * Returns zero on success; non-zero on error condition + */ +static int +ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, + int mode, struct nameidata *nd) +{ + int rc; + + rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd); + if (unlikely(rc)) { + ecryptfs_printk(KERN_WARNING, "Failed to create file in" + "lower filesystem\n"); + goto out; + } + /* At this point, a file exists on "disk"; we need to make sure + * that this on disk file is prepared to be an ecryptfs file */ + rc = ecryptfs_initialize_file(ecryptfs_dentry); +out: + return rc; +} + +/** + * ecryptfs_lookup + * @dir: inode + * @dentry: The dentry + * @nd: nameidata, may be NULL + * + * Find a file on disk. If the file does not exist, then we'll add it to the + * dentry cache and continue on to read it from the disk. + */ +static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + int rc = 0; + struct dentry *lower_dir_dentry; + struct dentry *lower_dentry; + struct vfsmount *lower_mnt; + struct dentry *tlower_dentry = NULL; + char *encoded_name; + unsigned int encoded_namelen; + struct ecryptfs_crypt_stat *crypt_stat = NULL; + char *page_virt = NULL; + struct inode *lower_inode; + u64 file_size; + + lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); + dentry->d_op = &ecryptfs_dops; + if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, ".")) + || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, ".."))) + goto out_drop; + encoded_namelen = ecryptfs_encode_filename(crypt_stat, + dentry->d_name.name, + dentry->d_name.len, + &encoded_name); + if (encoded_namelen < 0) { + rc = encoded_namelen; + goto out_drop; + } + ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen " + "= [%d]\n", encoded_name, encoded_namelen); + lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry, + encoded_namelen - 1); + kfree(encoded_name); + lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); + if (IS_ERR(lower_dentry)) { + ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n"); + rc = PTR_ERR(lower_dentry); + goto out_drop; + } + ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->" + "d_name.name = [%s]\n", lower_dentry, + lower_dentry->d_name.name); + lower_inode = lower_dentry->d_inode; + ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode); + BUG_ON(!atomic_read(&lower_dentry->d_count)); + ecryptfs_set_dentry_private(dentry, + kmem_cache_alloc(ecryptfs_dentry_info_cache, + SLAB_KERNEL)); + if (!ecryptfs_dentry_to_private(dentry)) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting " + "to allocate ecryptfs_dentry_info struct\n"); + goto out_dput; + } + ecryptfs_set_dentry_lower(dentry, lower_dentry); + ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt); + if (!lower_dentry->d_inode) { + /* We want to add because we couldn't find in lower */ + d_add(dentry, NULL); + goto out; + } + rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 1); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error interposing\n"); + goto out_dput; + } + if (S_ISDIR(lower_inode->i_mode)) { + ecryptfs_printk(KERN_DEBUG, "Is a directory; returning\n"); + goto out; + } + if (S_ISLNK(lower_inode->i_mode)) { + ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n"); + goto out; + } + if (!nd) { + ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave" + "as we *think* we are about to unlink\n"); + goto out; + } + tlower_dentry = dget(lower_dentry); + if (!tlower_dentry || IS_ERR(tlower_dentry)) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Cannot dget lower_dentry\n"); + goto out_dput; + } + /* Released in this function */ + page_virt = + (char *)kmem_cache_alloc(ecryptfs_header_cache_2, + SLAB_USER); + if (!page_virt) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, + "Cannot ecryptfs_kmalloc a page\n"); + goto out_dput; + } + memset(page_virt, 0, PAGE_CACHE_SIZE); + rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt); + crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; + if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) + ecryptfs_set_default_sizes(crypt_stat); + if (rc) { + rc = 0; + ecryptfs_printk(KERN_WARNING, "Error reading header region;" + " assuming unencrypted\n"); + } else { + if (!contains_ecryptfs_marker(page_virt + + ECRYPTFS_FILE_SIZE_BYTES)) { + kmem_cache_free(ecryptfs_header_cache_2, page_virt); + goto out; + } + memcpy(&file_size, page_virt, sizeof(file_size)); + file_size = be64_to_cpu(file_size); + i_size_write(dentry->d_inode, (loff_t)file_size); + } + kmem_cache_free(ecryptfs_header_cache_2, page_virt); + goto out; + +out_dput: + dput(lower_dentry); + if (tlower_dentry) + dput(tlower_dentry); +out_drop: + d_drop(dentry); +out: + return ERR_PTR(rc); +} + +static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + struct dentry *lower_old_dentry; + struct dentry *lower_new_dentry; + struct dentry *lower_dir_dentry; + u64 file_size_save; + int rc; + + file_size_save = i_size_read(old_dentry->d_inode); + lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); + lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); + dget(lower_old_dentry); + dget(lower_new_dentry); + lower_dir_dentry = lock_parent(lower_new_dentry); + rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, + lower_new_dentry); + if (rc || !lower_new_dentry->d_inode) + goto out_lock; + rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); + if (rc) + goto out_lock; + ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode); + old_dentry->d_inode->i_nlink = + ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink; + i_size_write(new_dentry->d_inode, file_size_save); +out_lock: + unlock_dir(lower_dir_dentry); + dput(lower_new_dentry); + dput(lower_old_dentry); + if (!new_dentry->d_inode) + d_drop(new_dentry); + return rc; +} + +static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); + + lock_parent(lower_dentry); + rc = vfs_unlink(lower_dir_inode, lower_dentry); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error in vfs_unlink\n"); + goto out_unlock; + } + ecryptfs_copy_attr_times(dir, lower_dir_inode); + dentry->d_inode->i_nlink = + ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink; + dentry->d_inode->i_ctime = dir->i_ctime; +out_unlock: + unlock_parent(lower_dentry); + return rc; +} + +static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + int rc; + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + umode_t mode; + char *encoded_symname; + unsigned int encoded_symlen; + struct ecryptfs_crypt_stat *crypt_stat = NULL; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + mode = S_IALLUGO; + encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname, + strlen(symname), + &encoded_symname); + if (encoded_symlen < 0) { + rc = encoded_symlen; + goto out_lock; + } + rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, + encoded_symname, mode); + kfree(encoded_symname); + if (rc || !lower_dentry->d_inode) + goto out_lock; + rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); + if (rc) + goto out_lock; + ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode); +out_lock: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + if (!dentry->d_inode) + d_drop(dentry); + return rc; +} + +static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int rc; + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_dir_dentry = lock_parent(lower_dentry); + rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode); + if (rc || !lower_dentry->d_inode) + goto out; + rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); + if (rc) + goto out; + ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode); + dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; +out: + unlock_dir(lower_dir_dentry); + if (!dentry->d_inode) + d_drop(dentry); + return rc; +} + +static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + struct dentry *tdentry = NULL; + struct dentry *lower_dentry; + struct dentry *tlower_dentry = NULL; + struct dentry *lower_dir_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!(tdentry = dget(dentry))) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Error dget'ing dentry [%p]\n", + dentry); + goto out; + } + lower_dir_dentry = lock_parent(lower_dentry); + if (!(tlower_dentry = dget(lower_dentry))) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry " + "[%p]\n", lower_dentry); + goto out; + } + rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + if (!rc) { + d_delete(tlower_dentry); + tlower_dentry = NULL; + } + ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode); + dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; + unlock_dir(lower_dir_dentry); + if (!rc) + d_drop(dentry); +out: + if (tdentry) + dput(tdentry); + if (tlower_dentry) + dput(tlower_dentry); + return rc; +} + +static int +ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + int rc; + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_dir_dentry = lock_parent(lower_dentry); + rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev); + if (rc || !lower_dentry->d_inode) + goto out; + rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); + if (rc) + goto out; + ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode); +out: + unlock_dir(lower_dir_dentry); + if (!dentry->d_inode) + d_drop(dentry); + return rc; +} + +static int +ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int rc; + struct dentry *lower_old_dentry; + struct dentry *lower_new_dentry; + struct dentry *lower_old_dir_dentry; + struct dentry *lower_new_dir_dentry; + + lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); + lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); + dget(lower_old_dentry); + dget(lower_new_dentry); + lower_old_dir_dentry = dget_parent(lower_old_dentry); + lower_new_dir_dentry = dget_parent(lower_new_dentry); + lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, + lower_new_dir_dentry->d_inode, lower_new_dentry); + if (rc) + goto out_lock; + ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); + if (new_dir != old_dir) + ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); +out_lock: + unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + dput(lower_new_dentry); + dput(lower_old_dentry); + return rc; +} + +static int +ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz) +{ + int rc; + struct dentry *lower_dentry; + char *decoded_name; + char *lower_buf; + mm_segment_t old_fs; + struct ecryptfs_crypt_stat *crypt_stat; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op || + !lower_dentry->d_inode->i_op->readlink) { + rc = -EINVAL; + goto out; + } + /* Released in this function */ + lower_buf = kmalloc(bufsiz, GFP_KERNEL); + if (lower_buf == NULL) { + ecryptfs_printk(KERN_ERR, "Out of memory\n"); + rc = -ENOMEM; + goto out; + } + old_fs = get_fs(); + set_fs(get_ds()); + ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ " + "lower_dentry->d_name.name = [%s]\n", + lower_dentry->d_name.name); + rc = lower_dentry->d_inode->i_op->readlink(lower_dentry, + (char __user *)lower_buf, + bufsiz); + set_fs(old_fs); + if (rc >= 0) { + crypt_stat = NULL; + rc = ecryptfs_decode_filename(crypt_stat, lower_buf, rc, + &decoded_name); + if (rc == -ENOMEM) + goto out_free_lower_buf; + if (rc > 0) { + ecryptfs_printk(KERN_DEBUG, "Copying [%d] bytes " + "to userspace: [%*s]\n", rc, + decoded_name); + if (copy_to_user(buf, decoded_name, rc)) + rc = -EFAULT; + } + kfree(decoded_name); + ecryptfs_copy_attr_atime(dentry->d_inode, + lower_dentry->d_inode); + } +out_free_lower_buf: + kfree(lower_buf); +out: + return rc; +} + +static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *buf; + int len = PAGE_SIZE, rc; + mm_segment_t old_fs; + + /* Released in ecryptfs_put_link(); only release here on error */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto out; + } + old_fs = get_fs(); + set_fs(get_ds()); + ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ " + "dentry->d_name.name = [%s]\n", dentry->d_name.name); + rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); + buf[rc] = '\0'; + set_fs(old_fs); + if (rc < 0) + goto out_free; + rc = 0; + nd_set_link(nd, buf); + goto out; +out_free: + kfree(buf); +out: + return ERR_PTR(rc); +} + +static void +ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) +{ + /* Free the char* */ + kfree(nd_get_link(nd)); +} + +/** + * upper_size_to_lower_size + * @crypt_stat: Crypt_stat associated with file + * @upper_size: Size of the upper file + * + * Calculate the requried size of the lower file based on the + * specified size of the upper file. This calculation is based on the + * number of headers in the underlying file and the extent size. + * + * Returns Calculated size of the lower file. + */ +static loff_t +upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, + loff_t upper_size) +{ + loff_t lower_size; + + lower_size = ( crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front ); + if (upper_size != 0) { + loff_t num_extents; + + num_extents = upper_size >> crypt_stat->extent_shift; + if (upper_size & ~crypt_stat->extent_mask) + num_extents++; + lower_size += (num_extents * crypt_stat->extent_size); + } + return lower_size; +} + +/** + * ecryptfs_truncate + * @dentry: The ecryptfs layer dentry + * @new_length: The length to expand the file to + * + * Function to handle truncations modifying the size of the file. Note + * that the file sizes are interpolated. When expanding, we are simply + * writing strings of 0's out. When truncating, we need to modify the + * underlying file size according to the page index interpolations. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) +{ + int rc = 0; + struct inode *inode = dentry->d_inode; + struct dentry *lower_dentry; + struct vfsmount *lower_mnt; + struct file fake_ecryptfs_file, *lower_file = NULL; + struct ecryptfs_crypt_stat *crypt_stat; + loff_t i_size = i_size_read(inode); + loff_t lower_size_before_truncate; + loff_t lower_size_after_truncate; + + if (unlikely((new_length == i_size))) + goto out; + crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; + /* Set up a fake ecryptfs file, this is used to interface with + * the file in the underlying filesystem so that the + * truncation has an effect there as well. */ + memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file)); + fake_ecryptfs_file.f_dentry = dentry; + /* Released at out_free: label */ + ecryptfs_set_file_private(&fake_ecryptfs_file, + kmem_cache_alloc(ecryptfs_file_info_cache, + SLAB_KERNEL)); + if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) { + rc = -ENOMEM; + goto out; + } + lower_dentry = ecryptfs_dentry_to_lower(dentry); + /* This dget & mntget is released through fput at out_fput: */ + dget(lower_dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); + mntget(lower_mnt); + lower_file = dentry_open(lower_dentry, lower_mnt, O_RDWR); + if (unlikely(IS_ERR(lower_file))) { + rc = PTR_ERR(lower_file); + goto out_free; + } + ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file); + /* Switch on growing or shrinking file */ + if (new_length > i_size) { + rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Problem with fill_zeros\n"); + goto out_fput; + } + i_size_write(inode, new_length); + rc = ecryptfs_write_inode_size_to_header(lower_file, + lower_dentry->d_inode, + inode); + if (rc) { + ecryptfs_printk(KERN_ERR, + "Problem with ecryptfs_write" + "_inode_size\n"); + goto out_fput; + } + } else { /* new_length < i_size_read(inode) */ + vmtruncate(inode, new_length); + ecryptfs_write_inode_size_to_header(lower_file, + lower_dentry->d_inode, + inode); + /* We are reducing the size of the ecryptfs file, and need to + * know if we need to reduce the size of the lower file. */ + lower_size_before_truncate = + upper_size_to_lower_size(crypt_stat, i_size); + lower_size_after_truncate = + upper_size_to_lower_size(crypt_stat, new_length); + if (lower_size_after_truncate < lower_size_before_truncate) + vmtruncate(lower_dentry->d_inode, + lower_size_after_truncate); + } + /* Update the access times */ + lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime + = CURRENT_TIME; + mark_inode_dirty_sync(inode); +out_fput: + fput(lower_file); +out_free: + if (ecryptfs_file_to_private(&fake_ecryptfs_file)) + kmem_cache_free(ecryptfs_file_info_cache, + ecryptfs_file_to_private(&fake_ecryptfs_file)); +out: + return rc; +} + +static int +ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + int rc; + + if (nd) { + struct vfsmount *vfsmnt_save = nd->mnt; + struct dentry *dentry_save = nd->dentry; + + nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry); + nd->dentry = ecryptfs_dentry_to_lower(nd->dentry); + rc = permission(ecryptfs_inode_to_lower(inode), mask, nd); + nd->mnt = vfsmnt_save; + nd->dentry = dentry_save; + } else + rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL); + return rc; +} + +/** + * ecryptfs_setattr + * @dentry: dentry handle to the inode to modify + * @ia: Structure with flags of what to change and values + * + * Updates the metadata of an inode. If the update is to the size + * i.e. truncation, then ecryptfs_truncate will handle the size modification + * of both the ecryptfs inode and the lower inode. + * + * All other metadata changes will be passed right to the lower filesystem, + * and we will just update our inode to look like the lower. + */ +static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int rc = 0; + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + struct ecryptfs_crypt_stat *crypt_stat; + + crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; + lower_dentry = ecryptfs_dentry_to_lower(dentry); + inode = dentry->d_inode; + lower_inode = ecryptfs_inode_to_lower(inode); + if (ia->ia_valid & ATTR_SIZE) { + ecryptfs_printk(KERN_DEBUG, + "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n", + ia->ia_valid, ATTR_SIZE); + rc = ecryptfs_truncate(dentry, ia->ia_size); + /* ecryptfs_truncate handles resizing of the lower file */ + ia->ia_valid &= ~ATTR_SIZE; + ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n", + ia->ia_valid); + if (rc < 0) + goto out; + } + rc = notify_change(lower_dentry, ia); +out: + ecryptfs_copy_attr_all(inode, lower_inode); + return rc; +} + +static int +ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags) +{ + int rc = 0; + struct dentry *lower_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->setxattr) { + rc = -ENOSYS; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); + rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value, + size, flags); + mutex_unlock(&lower_dentry->d_inode->i_mutex); +out: + return rc; +} + +static ssize_t +ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, + size_t size) +{ + int rc = 0; + struct dentry *lower_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->getxattr) { + rc = -ENOSYS; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); + rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value, + size); + mutex_unlock(&lower_dentry->d_inode->i_mutex); +out: + return rc; +} + +static ssize_t +ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size) +{ + int rc = 0; + struct dentry *lower_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->listxattr) { + rc = -ENOSYS; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); + rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size); + mutex_unlock(&lower_dentry->d_inode->i_mutex); +out: + return rc; +} + +static int ecryptfs_removexattr(struct dentry *dentry, const char *name) +{ + int rc = 0; + struct dentry *lower_dentry; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->removexattr) { + rc = -ENOSYS; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); + rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name); + mutex_unlock(&lower_dentry->d_inode->i_mutex); +out: + return rc; +} + +int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode) +{ + if ((ecryptfs_inode_to_lower(inode) + == (struct inode *)candidate_lower_inode)) + return 1; + else + return 0; +} + +int ecryptfs_inode_set(struct inode *inode, void *lower_inode) +{ + ecryptfs_init_inode(inode, (struct inode *)lower_inode); + return 0; +} + +struct inode_operations ecryptfs_symlink_iops = { + .readlink = ecryptfs_readlink, + .follow_link = ecryptfs_follow_link, + .put_link = ecryptfs_put_link, + .permission = ecryptfs_permission, + .setattr = ecryptfs_setattr, + .setxattr = ecryptfs_setxattr, + .getxattr = ecryptfs_getxattr, + .listxattr = ecryptfs_listxattr, + .removexattr = ecryptfs_removexattr +}; + +struct inode_operations ecryptfs_dir_iops = { + .create = ecryptfs_create, + .lookup = ecryptfs_lookup, + .link = ecryptfs_link, + .unlink = ecryptfs_unlink, + .symlink = ecryptfs_symlink, + .mkdir = ecryptfs_mkdir, + .rmdir = ecryptfs_rmdir, + .mknod = ecryptfs_mknod, + .rename = ecryptfs_rename, + .permission = ecryptfs_permission, + .setattr = ecryptfs_setattr, + .setxattr = ecryptfs_setxattr, + .getxattr = ecryptfs_getxattr, + .listxattr = ecryptfs_listxattr, + .removexattr = ecryptfs_removexattr +}; + +struct inode_operations ecryptfs_main_iops = { + .permission = ecryptfs_permission, + .setattr = ecryptfs_setattr, + .setxattr = ecryptfs_setxattr, + .getxattr = ecryptfs_getxattr, + .listxattr = ecryptfs_listxattr, + .removexattr = ecryptfs_removexattr +}; diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c new file mode 100644 index 00000000000..ba454785a0c --- /dev/null +++ b/fs/ecryptfs/keystore.c @@ -0,0 +1,1061 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * In-kernel key management code. Includes functions to parse and + * write authentication token-related packets with the underlying + * file. + * + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * Michael C. Thompson + * + * 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 +#include +#include +#include "ecryptfs_kernel.h" + +/** + * request_key returned an error instead of a valid key address; + * determine the type of error, make appropriate log entries, and + * return an error code. + */ +int process_request_key_err(long err_code) +{ + int rc = 0; + + switch (err_code) { + case ENOKEY: + ecryptfs_printk(KERN_WARNING, "No key\n"); + rc = -ENOENT; + break; + case EKEYEXPIRED: + ecryptfs_printk(KERN_WARNING, "Key expired\n"); + rc = -ETIME; + break; + case EKEYREVOKED: + ecryptfs_printk(KERN_WARNING, "Key revoked\n"); + rc = -EINVAL; + break; + default: + ecryptfs_printk(KERN_WARNING, "Unknown error code: " + "[0x%.16x]\n", err_code); + rc = -EINVAL; + } + return rc; +} + +static void wipe_auth_tok_list(struct list_head *auth_tok_list_head) +{ + struct list_head *walker; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item; + + walker = auth_tok_list_head->next; + while (walker != auth_tok_list_head) { + auth_tok_list_item = + list_entry(walker, struct ecryptfs_auth_tok_list_item, + list); + walker = auth_tok_list_item->list.next; + memset(auth_tok_list_item, 0, + sizeof(struct ecryptfs_auth_tok_list_item)); + kmem_cache_free(ecryptfs_auth_tok_list_item_cache, + auth_tok_list_item); + } +} + +struct kmem_cache *ecryptfs_auth_tok_list_item_cache; + +/** + * parse_packet_length + * @data: Pointer to memory containing length at offset + * @size: This function writes the decoded size to this memory + * address; zero on error + * @length_size: The number of bytes occupied by the encoded length + * + * Returns Zero on success + */ +static int parse_packet_length(unsigned char *data, size_t *size, + size_t *length_size) +{ + int rc = 0; + + (*length_size) = 0; + (*size) = 0; + if (data[0] < 192) { + /* One-byte length */ + (*size) = data[0]; + (*length_size) = 1; + } else if (data[0] < 224) { + /* Two-byte length */ + (*size) = ((data[0] - 192) * 256); + (*size) += (data[1] + 192); + (*length_size) = 2; + } else if (data[0] == 255) { + /* Five-byte length; we're not supposed to see this */ + ecryptfs_printk(KERN_ERR, "Five-byte packet length not " + "supported\n"); + rc = -EINVAL; + goto out; + } else { + ecryptfs_printk(KERN_ERR, "Error parsing packet length\n"); + rc = -EINVAL; + goto out; + } +out: + return rc; +} + +/** + * write_packet_length + * @dest: The byte array target into which to write the + * length. Must have at least 5 bytes allocated. + * @size: The length to write. + * @packet_size_length: The number of bytes used to encode the + * packet length is written to this address. + * + * Returns zero on success; non-zero on error. + */ +static int write_packet_length(char *dest, size_t size, + size_t *packet_size_length) +{ + int rc = 0; + + if (size < 192) { + dest[0] = size; + (*packet_size_length) = 1; + } else if (size < 65536) { + dest[0] = (((size - 192) / 256) + 192); + dest[1] = ((size - 192) % 256); + (*packet_size_length) = 2; + } else { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, + "Unsupported packet size: [%d]\n", size); + } + return rc; +} + +/** + * parse_tag_3_packet + * @crypt_stat: The cryptographic context to modify based on packet + * contents. + * @data: The raw bytes of the packet. + * @auth_tok_list: eCryptfs parses packets into authentication tokens; + * a new authentication token will be placed at the end + * of this list for this packet. + * @new_auth_tok: Pointer to a pointer to memory that this function + * allocates; sets the memory address of the pointer to + * NULL on error. This object is added to the + * auth_tok_list. + * @packet_size: This function writes the size of the parsed packet + * into this memory location; zero on error. + * @max_packet_size: maximum number of bytes to parse + * + * Returns zero on success; non-zero on error. + */ +static int +parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, + unsigned char *data, struct list_head *auth_tok_list, + struct ecryptfs_auth_tok **new_auth_tok, + size_t *packet_size, size_t max_packet_size) +{ + int rc = 0; + size_t body_size; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item; + size_t length_size; + + (*packet_size) = 0; + (*new_auth_tok) = NULL; + + /* we check that: + * one byte for the Tag 3 ID flag + * two bytes for the body size + * do not exceed the maximum_packet_size + */ + if (unlikely((*packet_size) + 3 > max_packet_size)) { + ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + rc = -EINVAL; + goto out; + } + + /* check for Tag 3 identifyer - one byte */ + if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) { + ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n", + ECRYPTFS_TAG_3_PACKET_TYPE); + rc = -EINVAL; + goto out; + } + /* 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); + if (!auth_tok_list_item) { + ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); + rc = -ENOMEM; + goto out; + } + memset(auth_tok_list_item, 0, + sizeof(struct ecryptfs_auth_tok_list_item)); + (*new_auth_tok) = &auth_tok_list_item->auth_tok; + + /* check for body size - one to two bytes */ + rc = parse_packet_length(&data[(*packet_size)], &body_size, + &length_size); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " + "rc = [%d]\n", rc); + goto out_free; + } + if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) { + ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", + body_size); + rc = -EINVAL; + goto out_free; + } + (*packet_size) += length_size; + + /* now we know the length of the remainting Tag 3 packet size: + * 5 fix bytes for: version string, cipher, S2K ID, hash algo, + * number of hash iterations + * ECRYPTFS_SALT_SIZE bytes for salt + * body_size bytes minus the stuff above is the encrypted key size + */ + if (unlikely((*packet_size) + body_size > max_packet_size)) { + ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + rc = -EINVAL; + goto out_free; + } + + /* There are 5 characters of additional information in the + * packet */ + (*new_auth_tok)->session_key.encrypted_key_size = + body_size - (0x05 + ECRYPTFS_SALT_SIZE); + ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n", + (*new_auth_tok)->session_key.encrypted_key_size); + + /* Version 4 (from RFC2440) - one byte */ + if (unlikely(data[(*packet_size)++] != 0x04)) { + ecryptfs_printk(KERN_DEBUG, "Unknown version number " + "[%d]\n", data[(*packet_size) - 1]); + rc = -EINVAL; + goto out_free; + } + + /* cipher - one byte */ + ecryptfs_cipher_code_to_string(crypt_stat->cipher, + (u16)data[(*packet_size)]); + /* A little extra work to differentiate among the AES key + * sizes; see RFC2440 */ + switch(data[(*packet_size)++]) { + case RFC2440_CIPHER_AES_192: + crypt_stat->key_size = 24; + break; + default: + crypt_stat->key_size = + (*new_auth_tok)->session_key.encrypted_key_size; + } + ecryptfs_init_crypt_ctx(crypt_stat); + /* S2K identifier 3 (from RFC2440) */ + if (unlikely(data[(*packet_size)++] != 0x03)) { + ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently " + "supported\n"); + rc = -ENOSYS; + goto out_free; + } + + /* TODO: finish the hash mapping */ + /* hash algorithm - one byte */ + switch (data[(*packet_size)++]) { + case 0x01: /* See RFC2440 for these numbers and their mappings */ + /* Choose MD5 */ + /* salt - ECRYPTFS_SALT_SIZE bytes */ + memcpy((*new_auth_tok)->token.password.salt, + &data[(*packet_size)], ECRYPTFS_SALT_SIZE); + (*packet_size) += ECRYPTFS_SALT_SIZE; + + /* This conversion was taken straight from RFC2440 */ + /* number of hash iterations - one byte */ + (*new_auth_tok)->token.password.hash_iterations = + ((u32) 16 + (data[(*packet_size)] & 15)) + << ((data[(*packet_size)] >> 4) + 6); + (*packet_size)++; + + /* encrypted session key - + * (body_size-5-ECRYPTFS_SALT_SIZE) bytes */ + memcpy((*new_auth_tok)->session_key.encrypted_key, + &data[(*packet_size)], + (*new_auth_tok)->session_key.encrypted_key_size); + (*packet_size) += + (*new_auth_tok)->session_key.encrypted_key_size; + (*new_auth_tok)->session_key.flags &= + ~ECRYPTFS_CONTAINS_DECRYPTED_KEY; + (*new_auth_tok)->session_key.flags |= + ECRYPTFS_CONTAINS_ENCRYPTED_KEY; + (*new_auth_tok)->token.password.hash_algo = 0x01; + break; + default: + ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: " + "[%d]\n", data[(*packet_size) - 1]); + rc = -ENOSYS; + goto out_free; + } + (*new_auth_tok)->token_type = ECRYPTFS_PASSWORD; + /* TODO: Parametarize; we might actually want userspace to + * decrypt the session key. */ + ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags, + ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT); + ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags, + ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT); + list_add(&auth_tok_list_item->list, auth_tok_list); + goto out; +out_free: + (*new_auth_tok) = NULL; + memset(auth_tok_list_item, 0, + sizeof(struct ecryptfs_auth_tok_list_item)); + kmem_cache_free(ecryptfs_auth_tok_list_item_cache, + auth_tok_list_item); +out: + if (rc) + (*packet_size) = 0; + return rc; +} + +/** + * parse_tag_11_packet + * @data: The raw bytes of the packet + * @contents: This function writes the data contents of the literal + * packet into this memory location + * @max_contents_bytes: The maximum number of bytes that this function + * is allowed to write into contents + * @tag_11_contents_size: This function writes the size of the parsed + * contents into this memory location; zero on + * error + * @packet_size: This function writes the size of the parsed packet + * into this memory location; zero on error + * @max_packet_size: maximum number of bytes to parse + * + * Returns zero on success; non-zero on error. + */ +static int +parse_tag_11_packet(unsigned char *data, unsigned char *contents, + size_t max_contents_bytes, size_t *tag_11_contents_size, + size_t *packet_size, size_t max_packet_size) +{ + int rc = 0; + size_t body_size; + size_t length_size; + + (*packet_size) = 0; + (*tag_11_contents_size) = 0; + + /* check that: + * one byte for the Tag 11 ID flag + * two bytes for the Tag 11 length + * do not exceed the maximum_packet_size + */ + if (unlikely((*packet_size) + 3 > max_packet_size)) { + ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + rc = -EINVAL; + goto out; + } + + /* check for Tag 11 identifyer - one byte */ + if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) { + ecryptfs_printk(KERN_WARNING, + "Invalid tag 11 packet format\n"); + rc = -EINVAL; + goto out; + } + + /* get Tag 11 content length - one or two bytes */ + rc = parse_packet_length(&data[(*packet_size)], &body_size, + &length_size); + if (rc) { + ecryptfs_printk(KERN_WARNING, + "Invalid tag 11 packet format\n"); + goto out; + } + (*packet_size) += length_size; + + if (body_size < 13) { + ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", + body_size); + rc = -EINVAL; + goto out; + } + /* We have 13 bytes of surrounding packet values */ + (*tag_11_contents_size) = (body_size - 13); + + /* now we know the length of the remainting Tag 11 packet size: + * 14 fix bytes for: special flag one, special flag two, + * 12 skipped bytes + * body_size bytes minus the stuff above is the Tag 11 content + */ + /* FIXME why is the body size one byte smaller than the actual + * size of the body? + * this seems to be an error here as well as in + * write_tag_11_packet() */ + if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) { + ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + rc = -EINVAL; + goto out; + } + + /* special flag one - one byte */ + if (data[(*packet_size)++] != 0x62) { + ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n"); + rc = -EINVAL; + goto out; + } + + /* special flag two - one byte */ + if (data[(*packet_size)++] != 0x08) { + ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n"); + rc = -EINVAL; + goto out; + } + + /* skip the next 12 bytes */ + (*packet_size) += 12; /* We don't care about the filename or + * the timestamp */ + + /* get the Tag 11 contents - tag_11_contents_size bytes */ + memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size)); + (*packet_size) += (*tag_11_contents_size); + +out: + if (rc) { + (*packet_size) = 0; + (*tag_11_contents_size) = 0; + } + return rc; +} + +/** + * decrypt_session_key - Decrypt the session key with the given auth_tok. + * + * Returns Zero on success; non-zero error otherwise. + */ +static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat) +{ + int rc = 0; + struct ecryptfs_password *password_s_ptr; + struct crypto_tfm *tfm = NULL; + struct scatterlist src_sg[2], dst_sg[2]; + struct mutex *tfm_mutex = NULL; + /* TODO: Use virt_to_scatterlist for these */ + char *encrypted_session_key; + char *session_key; + + password_s_ptr = &auth_tok->token.password; + if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags, + ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) + ecryptfs_printk(KERN_DEBUG, "Session key encryption key " + "set; skipping key generation\n"); + ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])" + ":\n", + password_s_ptr->session_key_encryption_key_bytes); + if (ecryptfs_verbosity > 0) + ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key, + password_s_ptr-> + session_key_encryption_key_bytes); + if (!strcmp(crypt_stat->cipher, + crypt_stat->mount_crypt_stat->global_default_cipher_name) + && crypt_stat->mount_crypt_stat->global_key_tfm) { + tfm = crypt_stat->mount_crypt_stat->global_key_tfm; + tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex; + } else { + tfm = crypto_alloc_tfm(crypt_stat->cipher, + CRYPTO_TFM_REQ_WEAK_KEY); + if (!tfm) { + printk(KERN_ERR "Error allocating crypto context\n"); + rc = -ENOMEM; + goto out; + } + } + if (password_s_ptr->session_key_encryption_key_bytes + < crypto_tfm_alg_min_keysize(tfm)) { + printk(KERN_WARNING "Session key encryption key is [%d] bytes; " + "minimum keysize for selected cipher is [%d] bytes.\n", + password_s_ptr->session_key_encryption_key_bytes, + crypto_tfm_alg_min_keysize(tfm)); + rc = -EINVAL; + goto out; + } + if (tfm_mutex) + mutex_lock(tfm_mutex); + crypto_cipher_setkey(tfm, password_s_ptr->session_key_encryption_key, + crypt_stat->key_size); + /* TODO: virt_to_scatterlist */ + encrypted_session_key = (char *)__get_free_page(GFP_KERNEL); + if (!encrypted_session_key) { + ecryptfs_printk(KERN_ERR, "Out of memory\n"); + rc = -ENOMEM; + goto out_free_tfm; + } + session_key = (char *)__get_free_page(GFP_KERNEL); + if (!session_key) { + kfree(encrypted_session_key); + ecryptfs_printk(KERN_ERR, "Out of memory\n"); + rc = -ENOMEM; + goto out_free_tfm; + } + memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key, + auth_tok->session_key.encrypted_key_size); + src_sg[0].page = virt_to_page(encrypted_session_key); + src_sg[0].offset = 0; + BUG_ON(auth_tok->session_key.encrypted_key_size > PAGE_CACHE_SIZE); + src_sg[0].length = auth_tok->session_key.encrypted_key_size; + dst_sg[0].page = virt_to_page(session_key); + dst_sg[0].offset = 0; + auth_tok->session_key.decrypted_key_size = + auth_tok->session_key.encrypted_key_size; + dst_sg[0].length = auth_tok->session_key.encrypted_key_size; + /* TODO: Handle error condition */ + crypto_cipher_decrypt(tfm, dst_sg, src_sg, + auth_tok->session_key.encrypted_key_size); + auth_tok->session_key.decrypted_key_size = + auth_tok->session_key.encrypted_key_size; + memcpy(auth_tok->session_key.decrypted_key, session_key, + auth_tok->session_key.decrypted_key_size); + auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY; + memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key, + auth_tok->session_key.decrypted_key_size); + ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n"); + if (ecryptfs_verbosity > 0) + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + memset(encrypted_session_key, 0, PAGE_CACHE_SIZE); + free_page((unsigned long)encrypted_session_key); + memset(session_key, 0, PAGE_CACHE_SIZE); + free_page((unsigned long)session_key); +out_free_tfm: + if (tfm_mutex) + mutex_unlock(tfm_mutex); + else + crypto_free_tfm(tfm); +out: + return rc; +} + +/** + * ecryptfs_parse_packet_set + * @dest: The header page in memory + * @version: Version of file format, to guide parsing behavior + * + * Get crypt_stat to have the file's session key if the requisite key + * is available to decrypt the session key. + * + * Returns Zero if a valid authentication token was retrieved and + * processed; negative value for file not encrypted or for error + * conditions. + */ +int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, + unsigned char *src, + struct dentry *ecryptfs_dentry) +{ + size_t i = 0; + int rc = 0; + size_t found_auth_tok = 0; + size_t next_packet_is_auth_tok_packet; + char sig[ECRYPTFS_SIG_SIZE_HEX]; + struct list_head auth_tok_list; + struct list_head *walker; + struct ecryptfs_auth_tok *chosen_auth_tok = NULL; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + struct ecryptfs_auth_tok *candidate_auth_tok = NULL; + size_t packet_size; + struct ecryptfs_auth_tok *new_auth_tok; + unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE]; + size_t tag_11_contents_size; + size_t tag_11_packet_size; + + INIT_LIST_HEAD(&auth_tok_list); + /* Parse the header to find as many packets as we can, these will be + * added the our &auth_tok_list */ + next_packet_is_auth_tok_packet = 1; + while (next_packet_is_auth_tok_packet) { + size_t max_packet_size = ((PAGE_CACHE_SIZE - 8) - i); + + switch (src[i]) { + case ECRYPTFS_TAG_3_PACKET_TYPE: + rc = parse_tag_3_packet(crypt_stat, + (unsigned char *)&src[i], + &auth_tok_list, &new_auth_tok, + &packet_size, max_packet_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error parsing " + "tag 3 packet\n"); + rc = -EIO; + goto out_wipe_list; + } + i += packet_size; + rc = parse_tag_11_packet((unsigned char *)&src[i], + sig_tmp_space, + ECRYPTFS_SIG_SIZE, + &tag_11_contents_size, + &tag_11_packet_size, + max_packet_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "No valid " + "(ecryptfs-specific) literal " + "packet containing " + "authentication token " + "signature found after " + "tag 3 packet\n"); + rc = -EIO; + goto out_wipe_list; + } + i += tag_11_packet_size; + if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) { + ecryptfs_printk(KERN_ERR, "Expected " + "signature of size [%d]; " + "read size [%d]\n", + ECRYPTFS_SIG_SIZE, + tag_11_contents_size); + rc = -EIO; + goto out_wipe_list; + } + ecryptfs_to_hex(new_auth_tok->token.password.signature, + sig_tmp_space, tag_11_contents_size); + new_auth_tok->token.password.signature[ + ECRYPTFS_PASSWORD_SIG_SIZE] = '\0'; + ECRYPTFS_SET_FLAG(crypt_stat->flags, + ECRYPTFS_ENCRYPTED); + break; + case ECRYPTFS_TAG_11_PACKET_TYPE: + ecryptfs_printk(KERN_WARNING, "Invalid packet set " + "(Tag 11 not allowed by itself)\n"); + rc = -EIO; + goto out_wipe_list; + break; + default: + ecryptfs_printk(KERN_DEBUG, "No packet at offset " + "[%d] of the file header; hex value of " + "character is [0x%.2x]\n", i, src[i]); + next_packet_is_auth_tok_packet = 0; + } + } + if (list_empty(&auth_tok_list)) { + rc = -EINVAL; /* Do not support non-encrypted files in + * the 0.1 release */ + goto out; + } + /* If we have a global auth tok, then we should try to use + * it */ + if (mount_crypt_stat->global_auth_tok) { + memcpy(sig, mount_crypt_stat->global_auth_tok_sig, + ECRYPTFS_SIG_SIZE_HEX); + chosen_auth_tok = mount_crypt_stat->global_auth_tok; + } else + BUG(); /* We should always have a global auth tok in + * the 0.1 release */ + /* Scan list to see if our chosen_auth_tok works */ + list_for_each(walker, &auth_tok_list) { + struct ecryptfs_auth_tok_list_item *auth_tok_list_item; + auth_tok_list_item = + list_entry(walker, struct ecryptfs_auth_tok_list_item, + list); + candidate_auth_tok = &auth_tok_list_item->auth_tok; + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, + "Considering cadidate auth tok:\n"); + ecryptfs_dump_auth_tok(candidate_auth_tok); + } + /* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */ + if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD + && !strncmp(candidate_auth_tok->token.password.signature, + sig, ECRYPTFS_SIG_SIZE_HEX)) { + found_auth_tok = 1; + goto leave_list; + /* TODO: Transfer the common salt into the + * crypt_stat salt */ + } + } +leave_list: + if (!found_auth_tok) { + ecryptfs_printk(KERN_ERR, "Could not find authentication " + "token on temporary list for sig [%.*s]\n", + ECRYPTFS_SIG_SIZE_HEX, sig); + rc = -EIO; + goto out_wipe_list; + } else { + memcpy(&(candidate_auth_tok->token.password), + &(chosen_auth_tok->token.password), + sizeof(struct ecryptfs_password)); + rc = decrypt_session_key(candidate_auth_tok, crypt_stat); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error decrypting the " + "session key\n"); + goto out_wipe_list; + } + rc = ecryptfs_compute_root_iv(crypt_stat); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error computing " + "the root IV\n"); + goto out_wipe_list; + } + } + rc = ecryptfs_init_crypt_ctx(crypt_stat); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error initializing crypto " + "context for cipher [%s]; rc = [%d]\n", + crypt_stat->cipher, rc); + } +out_wipe_list: + wipe_auth_tok_list(&auth_tok_list); +out: + return rc; +} + +/** + * write_tag_11_packet + * @dest: Target into which Tag 11 packet is to be written + * @max: Maximum packet length + * @contents: Byte array of contents to copy in + * @contents_length: Number of bytes in contents + * @packet_length: Length of the Tag 11 packet written; zero on error + * + * Returns zero on success; non-zero on error. + */ +static int +write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length, + size_t *packet_length) +{ + int rc = 0; + size_t packet_size_length; + + (*packet_length) = 0; + if ((13 + contents_length) > max) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Packet length larger than " + "maximum allowable\n"); + goto out; + } + /* General packet header */ + /* Packet tag */ + dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE; + /* Packet length */ + rc = write_packet_length(&dest[(*packet_length)], + (13 + contents_length), &packet_size_length); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 11 packet " + "header; cannot generate packet length\n"); + goto out; + } + (*packet_length) += packet_size_length; + /* Tag 11 specific */ + /* One-octet field that describes how the data is formatted */ + dest[(*packet_length)++] = 0x62; /* binary data */ + /* One-octet filename length followed by filename */ + dest[(*packet_length)++] = 8; + memcpy(&dest[(*packet_length)], "_CONSOLE", 8); + (*packet_length) += 8; + /* Four-octet number indicating modification date */ + memset(&dest[(*packet_length)], 0x00, 4); + (*packet_length) += 4; + /* Remainder is literal data */ + memcpy(&dest[(*packet_length)], contents, contents_length); + (*packet_length) += contents_length; + out: + if (rc) + (*packet_length) = 0; + return rc; +} + +/** + * write_tag_3_packet + * @dest: Buffer into which to write the packet + * @max: Maximum number of bytes that can be written + * @auth_tok: Authentication token + * @crypt_stat: The cryptographic context + * @key_rec: encrypted key + * @packet_size: This function will write the number of bytes that end + * up constituting the packet; set to zero on error + * + * Returns zero on success; non-zero on error. + */ +static int +write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_key_record *key_rec, size_t *packet_size) +{ + int rc = 0; + + size_t i; + size_t signature_is_valid = 0; + size_t encrypted_session_key_valid = 0; + char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES]; + struct scatterlist dest_sg[2]; + struct scatterlist src_sg[2]; + struct crypto_tfm *tfm = NULL; + struct mutex *tfm_mutex = NULL; + size_t key_rec_size; + size_t packet_size_length; + size_t cipher_code; + + (*packet_size) = 0; + /* Check for a valid signature on the auth_tok */ + for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++) + signature_is_valid |= auth_tok->token.password.signature[i]; + if (!signature_is_valid) + BUG(); + ecryptfs_from_hex((*key_rec).sig, auth_tok->token.password.signature, + ECRYPTFS_SIG_SIZE); + encrypted_session_key_valid = 0; + for (i = 0; i < crypt_stat->key_size; i++) + encrypted_session_key_valid |= + auth_tok->session_key.encrypted_key[i]; + if (encrypted_session_key_valid) { + memcpy((*key_rec).enc_key, + auth_tok->session_key.encrypted_key, + auth_tok->session_key.encrypted_key_size); + goto encrypted_session_key_set; + } + if (auth_tok->session_key.encrypted_key_size == 0) + auth_tok->session_key.encrypted_key_size = + crypt_stat->key_size; + if (crypt_stat->key_size == 24 + && strcmp("aes", crypt_stat->cipher) == 0) { + memset((crypt_stat->key + 24), 0, 8); + auth_tok->session_key.encrypted_key_size = 32; + } + (*key_rec).enc_key_size = + auth_tok->session_key.encrypted_key_size; + if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags, + ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) { + ecryptfs_printk(KERN_DEBUG, "Using previously generated " + "session key encryption key of size [%d]\n", + auth_tok->token.password. + session_key_encryption_key_bytes); + memcpy(session_key_encryption_key, + auth_tok->token.password.session_key_encryption_key, + crypt_stat->key_size); + ecryptfs_printk(KERN_DEBUG, + "Cached session key " "encryption key: \n"); + if (ecryptfs_verbosity > 0) + ecryptfs_dump_hex(session_key_encryption_key, 16); + } + if (unlikely(ecryptfs_verbosity > 0)) { + ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n"); + ecryptfs_dump_hex(session_key_encryption_key, 16); + } + rc = virt_to_scatterlist(crypt_stat->key, + (*key_rec).enc_key_size, src_sg, 2); + if (!rc) { + ecryptfs_printk(KERN_ERR, "Error generating scatterlist " + "for crypt_stat session key\n"); + rc = -ENOMEM; + goto out; + } + rc = virt_to_scatterlist((*key_rec).enc_key, + (*key_rec).enc_key_size, dest_sg, 2); + if (!rc) { + ecryptfs_printk(KERN_ERR, "Error generating scatterlist " + "for crypt_stat encrypted session key\n"); + rc = -ENOMEM; + goto out; + } + if (!strcmp(crypt_stat->cipher, + crypt_stat->mount_crypt_stat->global_default_cipher_name) + && crypt_stat->mount_crypt_stat->global_key_tfm) { + tfm = crypt_stat->mount_crypt_stat->global_key_tfm; + tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex; + } else + tfm = crypto_alloc_tfm(crypt_stat->cipher, 0); + if (!tfm) { + ecryptfs_printk(KERN_ERR, "Could not initialize crypto " + "context for cipher [%s]\n", + crypt_stat->cipher); + rc = -EINVAL; + goto out; + } + if (tfm_mutex) + mutex_lock(tfm_mutex); + rc = crypto_cipher_setkey(tfm, session_key_encryption_key, + crypt_stat->key_size); + if (rc < 0) { + if (tfm_mutex) + mutex_unlock(tfm_mutex); + ecryptfs_printk(KERN_ERR, "Error setting key for crypto " + "context\n"); + goto out; + } + rc = 0; + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n", + crypt_stat->key_size); + crypto_cipher_encrypt(tfm, dest_sg, src_sg, + (*key_rec).enc_key_size); + if (tfm_mutex) + mutex_unlock(tfm_mutex); + ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n"); + if (ecryptfs_verbosity > 0) + ecryptfs_dump_hex((*key_rec).enc_key, + (*key_rec).enc_key_size); +encrypted_session_key_set: + /* Now we have a valid key_rec. Append it to the + * key_rec set. */ + key_rec_size = (sizeof(struct ecryptfs_key_record) + - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES + + ((*key_rec).enc_key_size)); + /* TODO: Include a packet size limit as a parameter to this + * function once we have multi-packet headers (for versions + * later than 0.1 */ + if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) { + ecryptfs_printk(KERN_ERR, "Keyset too large\n"); + rc = -EINVAL; + goto out; + } + /* TODO: Packet size limit */ + /* We have 5 bytes of surrounding packet data */ + if ((0x05 + ECRYPTFS_SALT_SIZE + + (*key_rec).enc_key_size) >= max) { + ecryptfs_printk(KERN_ERR, "Authentication token is too " + "large\n"); + rc = -EINVAL; + goto out; + } + /* This format is inspired by OpenPGP; see RFC 2440 + * packet tag 3 */ + dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE; + /* ver+cipher+s2k+hash+salt+iter+enc_key */ + rc = write_packet_length(&dest[(*packet_size)], + (0x05 + ECRYPTFS_SALT_SIZE + + (*key_rec).enc_key_size), + &packet_size_length); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet " + "header; cannot generate packet length\n"); + goto out; + } + (*packet_size) += packet_size_length; + dest[(*packet_size)++] = 0x04; /* version 4 */ + cipher_code = ecryptfs_code_for_cipher_string(crypt_stat); + if (cipher_code == 0) { + ecryptfs_printk(KERN_WARNING, "Unable to generate code for " + "cipher [%s]\n", crypt_stat->cipher); + rc = -EINVAL; + goto out; + } + dest[(*packet_size)++] = cipher_code; + dest[(*packet_size)++] = 0x03; /* S2K */ + dest[(*packet_size)++] = 0x01; /* MD5 (TODO: parameterize) */ + memcpy(&dest[(*packet_size)], auth_tok->token.password.salt, + ECRYPTFS_SALT_SIZE); + (*packet_size) += ECRYPTFS_SALT_SIZE; /* salt */ + dest[(*packet_size)++] = 0x60; /* hash iterations (65536) */ + memcpy(&dest[(*packet_size)], (*key_rec).enc_key, + (*key_rec).enc_key_size); + (*packet_size) += (*key_rec).enc_key_size; +out: + if (tfm && !tfm_mutex) + crypto_free_tfm(tfm); + if (rc) + (*packet_size) = 0; + return rc; +} + +/** + * ecryptfs_generate_key_packet_set + * @dest: Virtual address from which to write the key record set + * @crypt_stat: The cryptographic context from which the + * authentication tokens will be retrieved + * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat + * for the global parameters + * @len: The amount written + * @max: The maximum amount of data allowed to be written + * + * Generates a key packet set and writes it to the virtual address + * passed in. + * + * Returns zero on success; non-zero on error. + */ +int +ecryptfs_generate_key_packet_set(char *dest_base, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry, size_t *len, + size_t max) +{ + int rc = 0; + struct ecryptfs_auth_tok *auth_tok; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + size_t written; + struct ecryptfs_key_record key_rec; + + (*len) = 0; + if (mount_crypt_stat->global_auth_tok) { + auth_tok = mount_crypt_stat->global_auth_tok; + if (auth_tok->token_type == ECRYPTFS_PASSWORD) { + rc = write_tag_3_packet((dest_base + (*len)), + max, auth_tok, + crypt_stat, &key_rec, + &written); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error " + "writing tag 3 packet\n"); + goto out; + } + (*len) += written; + /* Write auth tok signature packet */ + rc = write_tag_11_packet( + (dest_base + (*len)), + (max - (*len)), + key_rec.sig, ECRYPTFS_SIG_SIZE, &written); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error writing " + "auth tok signature packet\n"); + goto out; + } + (*len) += written; + } else { + ecryptfs_printk(KERN_WARNING, "Unsupported " + "authentication token type\n"); + rc = -EINVAL; + goto out; + } + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error writing " + "authentication token packet with sig " + "= [%s]\n", + mount_crypt_stat->global_auth_tok_sig); + rc = -EIO; + goto out; + } + } else + BUG(); + if (likely((max - (*len)) > 0)) { + dest_base[(*len)] = 0x00; + } else { + ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n"); + rc = -EIO; + } +out: + if (rc) + (*len) = 0; + return rc; +} diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c new file mode 100644 index 00000000000..7a11b8ae664 --- /dev/null +++ b/fs/ecryptfs/main.c @@ -0,0 +1,831 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2003 Erez Zadok + * Copyright (C) 2001-2003 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * Michael C. Thompson + * + * 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 +#include +#include +#include +#include +#include +#include +#include "ecryptfs_kernel.h" + +/** + * Module parameter that defines the ecryptfs_verbosity level. + */ +int ecryptfs_verbosity = 0; + +module_param(ecryptfs_verbosity, int, 0); +MODULE_PARM_DESC(ecryptfs_verbosity, + "Initial verbosity level (0 or 1; defaults to " + "0, which is Quiet)"); + +void __ecryptfs_printk(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (fmt[1] == '7') { /* KERN_DEBUG */ + if (ecryptfs_verbosity >= 1) + vprintk(fmt, args); + } else + vprintk(fmt, args); + va_end(args); +} + +/** + * ecryptfs_interpose + * @lower_dentry: Existing dentry in the lower filesystem + * @dentry: ecryptfs' dentry + * @sb: ecryptfs's super_block + * @flag: If set to true, then d_add is called, else d_instantiate is called + * + * Interposes upper and lower dentries. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, + struct super_block *sb, int flag) +{ + struct inode *lower_inode; + struct inode *inode; + int rc = 0; + + lower_inode = lower_dentry->d_inode; + if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) { + rc = -EXDEV; + goto out; + } + if (!igrab(lower_inode)) { + rc = -ESTALE; + goto out; + } + inode = iget5_locked(sb, (unsigned long)lower_inode, + ecryptfs_inode_test, ecryptfs_inode_set, + lower_inode); + if (!inode) { + rc = -EACCES; + iput(lower_inode); + goto out; + } + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + else + iput(lower_inode); + if (S_ISLNK(lower_inode->i_mode)) + inode->i_op = &ecryptfs_symlink_iops; + else if (S_ISDIR(lower_inode->i_mode)) + inode->i_op = &ecryptfs_dir_iops; + if (S_ISDIR(lower_inode->i_mode)) + inode->i_fop = &ecryptfs_dir_fops; + /* TODO: Is there a better way to identify if the inode is + * special? */ + if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || + S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) + init_special_inode(inode, lower_inode->i_mode, + lower_inode->i_rdev); + dentry->d_op = &ecryptfs_dops; + if (flag) + d_add(dentry, inode); + else + d_instantiate(dentry, inode); + ecryptfs_copy_attr_all(inode, lower_inode); + /* This size will be overwritten for real files w/ headers and + * other metadata */ + ecryptfs_copy_inode_size(inode, lower_inode); +out: + return rc; +} + +enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug, + ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher, + ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes, + ecryptfs_opt_passthrough, ecryptfs_opt_err }; + +static match_table_t tokens = { + {ecryptfs_opt_sig, "sig=%s"}, + {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"}, + {ecryptfs_opt_debug, "debug=%u"}, + {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"}, + {ecryptfs_opt_cipher, "cipher=%s"}, + {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"}, + {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"}, + {ecryptfs_opt_passthrough, "ecryptfs_passthrough"}, + {ecryptfs_opt_err, NULL} +}; + +/** + * ecryptfs_verify_version + * @version: The version number to confirm + * + * Returns zero on good version; non-zero otherwise + */ +static int ecryptfs_verify_version(u16 version) +{ + int rc = 0; + unsigned char major; + unsigned char minor; + + major = ((version >> 8) & 0xFF); + minor = (version & 0xFF); + if (major != ECRYPTFS_VERSION_MAJOR) { + ecryptfs_printk(KERN_ERR, "Major version number mismatch. " + "Expected [%d]; got [%d]\n", + ECRYPTFS_VERSION_MAJOR, major); + rc = -EINVAL; + goto out; + } + if (minor != ECRYPTFS_VERSION_MINOR) { + ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " + "Expected [%d]; got [%d]\n", + ECRYPTFS_VERSION_MINOR, minor); + rc = -EINVAL; + goto out; + } +out: + return rc; +} + +/** + * ecryptfs_parse_options + * @sb: The ecryptfs super block + * @options: The options pased to the kernel + * + * Parse mount options: + * debug=N - ecryptfs_verbosity level for debug output + * sig=XXX - description(signature) of the key to use + * + * Returns the dentry object of the lower-level (lower/interposed) + * directory; We want to mount our stackable file system on top of + * that lower directory. + * + * The signature of the key to use must be the description of a key + * already in the keyring. Mounting will fail if the key can not be + * found. + * + * Returns zero on success; non-zero on error + */ +static int ecryptfs_parse_options(struct super_block *sb, char *options) +{ + char *p; + int rc = 0; + int sig_set = 0; + int cipher_name_set = 0; + int cipher_key_bytes; + int cipher_key_bytes_set = 0; + struct key *auth_tok_key = NULL; + struct ecryptfs_auth_tok *auth_tok = NULL; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(sb)->mount_crypt_stat; + substring_t args[MAX_OPT_ARGS]; + int token; + char *sig_src; + char *sig_dst; + char *debug_src; + char *cipher_name_dst; + char *cipher_name_src; + char *cipher_key_bytes_src; + struct crypto_tfm *tmp_tfm; + int cipher_name_len; + + if (!options) { + rc = -EINVAL; + goto out; + } + while ((p = strsep(&options, ",")) != NULL) { + if (!*p) + continue; + token = match_token(p, tokens, args); + switch (token) { + case ecryptfs_opt_sig: + case ecryptfs_opt_ecryptfs_sig: + sig_src = args[0].from; + sig_dst = + mount_crypt_stat->global_auth_tok_sig; + memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX); + sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0'; + ecryptfs_printk(KERN_DEBUG, + "The mount_crypt_stat " + "global_auth_tok_sig set to: " + "[%s]\n", sig_dst); + sig_set = 1; + break; + case ecryptfs_opt_debug: + case ecryptfs_opt_ecryptfs_debug: + debug_src = args[0].from; + ecryptfs_verbosity = + (int)simple_strtol(debug_src, &debug_src, + 0); + ecryptfs_printk(KERN_DEBUG, + "Verbosity set to [%d]" "\n", + ecryptfs_verbosity); + break; + case ecryptfs_opt_cipher: + case ecryptfs_opt_ecryptfs_cipher: + cipher_name_src = args[0].from; + cipher_name_dst = + mount_crypt_stat-> + global_default_cipher_name; + strncpy(cipher_name_dst, cipher_name_src, + ECRYPTFS_MAX_CIPHER_NAME_SIZE); + ecryptfs_printk(KERN_DEBUG, + "The mount_crypt_stat " + "global_default_cipher_name set to: " + "[%s]\n", cipher_name_dst); + cipher_name_set = 1; + break; + case ecryptfs_opt_ecryptfs_key_bytes: + cipher_key_bytes_src = args[0].from; + cipher_key_bytes = + (int)simple_strtol(cipher_key_bytes_src, + &cipher_key_bytes_src, 0); + mount_crypt_stat->global_default_cipher_key_size = + cipher_key_bytes; + ecryptfs_printk(KERN_DEBUG, + "The mount_crypt_stat " + "global_default_cipher_key_size " + "set to: [%d]\n", mount_crypt_stat-> + global_default_cipher_key_size); + cipher_key_bytes_set = 1; + break; + case ecryptfs_opt_passthrough: + mount_crypt_stat->flags |= + ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED; + break; + case ecryptfs_opt_err: + default: + ecryptfs_printk(KERN_WARNING, + "eCryptfs: unrecognized option '%s'\n", + p); + } + } + /* Do not support lack of mount-wide signature in 0.1 + * release */ + if (!sig_set) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "You must supply a valid " + "passphrase auth tok signature as a mount " + "parameter; see the eCryptfs README\n"); + goto out; + } + if (!cipher_name_set) { + cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER); + if (unlikely(cipher_name_len + >= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) { + rc = -EINVAL; + BUG(); + goto out; + } + memcpy(mount_crypt_stat->global_default_cipher_name, + ECRYPTFS_DEFAULT_CIPHER, cipher_name_len); + mount_crypt_stat->global_default_cipher_name[cipher_name_len] + = '\0'; + } + if (!cipher_key_bytes_set) { + mount_crypt_stat->global_default_cipher_key_size = + ECRYPTFS_DEFAULT_KEY_BYTES; + ecryptfs_printk(KERN_DEBUG, "Cipher key size was not " + "specified. Defaulting to [%d]\n", + mount_crypt_stat-> + global_default_cipher_key_size); + } + rc = ecryptfs_process_cipher( + &tmp_tfm, + &mount_crypt_stat->global_key_tfm, + mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size); + if (tmp_tfm) + crypto_free_tfm(tmp_tfm); + if (rc) { + printk(KERN_ERR "Error attempting to initialize cipher [%s] " + "with key size [%Zd] bytes; rc = [%d]\n", + mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size, rc); + rc = -EINVAL; + goto out; + } + mutex_init(&mount_crypt_stat->global_key_tfm_mutex); + ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: " + "[%s]\n", mount_crypt_stat->global_auth_tok_sig); + /* The reference to this key is held until umount is done The + * call to key_put is done in ecryptfs_put_super() */ + auth_tok_key = request_key(&key_type_user, + mount_crypt_stat->global_auth_tok_sig, + NULL); + if (!auth_tok_key || IS_ERR(auth_tok_key)) { + ecryptfs_printk(KERN_ERR, "Could not find key with " + "description: [%s]\n", + mount_crypt_stat->global_auth_tok_sig); + process_request_key_err(PTR_ERR(auth_tok_key)); + rc = -EINVAL; + goto out; + } + auth_tok = ecryptfs_get_key_payload_data(auth_tok_key); + if (ecryptfs_verify_version(auth_tok->version)) { + ecryptfs_printk(KERN_ERR, "Data structure version mismatch. " + "Userspace tools must match eCryptfs kernel " + "module with major version [%d] and minor " + "version [%d]\n", ECRYPTFS_VERSION_MAJOR, + ECRYPTFS_VERSION_MINOR); + rc = -EINVAL; + goto out; + } + if (auth_tok->token_type != ECRYPTFS_PASSWORD) { + ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure " + "returned from key\n"); + rc = -EINVAL; + goto out; + } + mount_crypt_stat->global_auth_tok_key = auth_tok_key; + mount_crypt_stat->global_auth_tok = auth_tok; +out: + return rc; +} + +struct kmem_cache *ecryptfs_sb_info_cache; + +/** + * ecryptfs_fill_super + * @sb: The ecryptfs super block + * @raw_data: The options passed to mount + * @silent: Not used but required by function prototype + * + * Sets up what we can of the sb, rest is done in ecryptfs_read_super + * + * Returns zero on success; non-zero otherwise + */ +static int +ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent) +{ + int rc = 0; + + /* Released in ecryptfs_put_super() */ + ecryptfs_set_superblock_private(sb, + kmem_cache_alloc(ecryptfs_sb_info_cache, + SLAB_KERNEL)); + if (!ecryptfs_superblock_to_private(sb)) { + ecryptfs_printk(KERN_WARNING, "Out of memory\n"); + rc = -ENOMEM; + goto out; + } + memset(ecryptfs_superblock_to_private(sb), 0, + sizeof(struct ecryptfs_sb_info)); + sb->s_op = &ecryptfs_sops; + /* Released through deactivate_super(sb) from get_sb_nodev */ + sb->s_root = d_alloc(NULL, &(const struct qstr) { + .hash = 0,.name = "/",.len = 1}); + if (!sb->s_root) { + ecryptfs_printk(KERN_ERR, "d_alloc failed\n"); + rc = -ENOMEM; + goto out; + } + sb->s_root->d_op = &ecryptfs_dops; + sb->s_root->d_sb = sb; + sb->s_root->d_parent = sb->s_root; + /* Released in d_release when dput(sb->s_root) is called */ + /* through deactivate_super(sb) from get_sb_nodev() */ + ecryptfs_set_dentry_private(sb->s_root, + kmem_cache_alloc(ecryptfs_dentry_info_cache, + SLAB_KERNEL)); + if (!ecryptfs_dentry_to_private(sb->s_root)) { + ecryptfs_printk(KERN_ERR, + "dentry_info_cache alloc failed\n"); + rc = -ENOMEM; + goto out; + } + memset(ecryptfs_dentry_to_private(sb->s_root), 0, + sizeof(struct ecryptfs_dentry_info)); + rc = 0; +out: + /* Should be able to rely on deactivate_super called from + * get_sb_nodev */ + return rc; +} + +/** + * ecryptfs_read_super + * @sb: The ecryptfs super block + * @dev_name: The path to mount over + * + * Read the super block of the lower filesystem, and use + * ecryptfs_interpose to create our initial inode and super block + * struct. + */ +static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) +{ + int rc; + struct nameidata nd; + struct dentry *lower_root; + struct vfsmount *lower_mnt; + + memset(&nd, 0, sizeof(struct nameidata)); + rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); + if (rc) { + ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); + goto out_free; + } + lower_root = nd.dentry; + if (!lower_root->d_inode) { + ecryptfs_printk(KERN_WARNING, + "No directory to interpose on\n"); + rc = -ENOENT; + goto out_free; + } + lower_mnt = nd.mnt; + ecryptfs_set_superblock_lower(sb, lower_root->d_sb); + sb->s_maxbytes = lower_root->d_sb->s_maxbytes; + ecryptfs_set_dentry_lower(sb->s_root, lower_root); + ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt); + if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0))) + goto out_free; + rc = 0; + goto out; +out_free: + path_release(&nd); +out: + return rc; +} + +/** + * ecryptfs_get_sb + * @fs_type + * @flags + * @dev_name: The path to mount over + * @raw_data: The options passed into the kernel + * + * The whole ecryptfs_get_sb process is broken into 4 functions: + * ecryptfs_parse_options(): handle options passed to ecryptfs, if any + * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block + * with as much information as it can before needing + * the lower filesystem. + * ecryptfs_read_super(): this accesses the lower filesystem and uses + * ecryptfs_interpolate to perform most of the linking + * ecryptfs_interpolate(): links the lower filesystem into ecryptfs + */ +static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data, + struct vfsmount *mnt) +{ + int rc; + struct super_block *sb; + + rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt); + if (rc < 0) { + printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc); + goto out; + } + sb = mnt->mnt_sb; + rc = ecryptfs_parse_options(sb, raw_data); + if (rc) { + printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc); + goto out_abort; + } + rc = ecryptfs_read_super(sb, dev_name); + if (rc) { + printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc); + goto out_abort; + } + goto out; +out_abort: + dput(sb->s_root); + up_write(&sb->s_umount); + deactivate_super(sb); +out: + return rc; +} + +/** + * ecryptfs_kill_block_super + * @sb: The ecryptfs super block + * + * Used to bring the superblock down and free the private data. + * Private data is free'd in ecryptfs_put_super() + */ +static void ecryptfs_kill_block_super(struct super_block *sb) +{ + generic_shutdown_super(sb); +} + +static struct file_system_type ecryptfs_fs_type = { + .owner = THIS_MODULE, + .name = "ecryptfs", + .get_sb = ecryptfs_get_sb, + .kill_sb = ecryptfs_kill_block_super, + .fs_flags = 0 +}; + +/** + * inode_info_init_once + * + * Initializes the ecryptfs_inode_info_cache when it is created + */ +static void +inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags) +{ + struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr; + + if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(&ei->vfs_inode); +} + +static struct ecryptfs_cache_info { + kmem_cache_t **cache; + const char *name; + size_t size; + void (*ctor)(void*, struct kmem_cache *, unsigned long); +} ecryptfs_cache_infos[] = { + { + .cache = &ecryptfs_auth_tok_list_item_cache, + .name = "ecryptfs_auth_tok_list_item", + .size = sizeof(struct ecryptfs_auth_tok_list_item), + }, + { + .cache = &ecryptfs_file_info_cache, + .name = "ecryptfs_file_cache", + .size = sizeof(struct ecryptfs_file_info), + }, + { + .cache = &ecryptfs_dentry_info_cache, + .name = "ecryptfs_dentry_info_cache", + .size = sizeof(struct ecryptfs_dentry_info), + }, + { + .cache = &ecryptfs_inode_info_cache, + .name = "ecryptfs_inode_cache", + .size = sizeof(struct ecryptfs_inode_info), + .ctor = inode_info_init_once, + }, + { + .cache = &ecryptfs_sb_info_cache, + .name = "ecryptfs_sb_cache", + .size = sizeof(struct ecryptfs_sb_info), + }, + { + .cache = &ecryptfs_header_cache_0, + .name = "ecryptfs_headers_0", + .size = PAGE_CACHE_SIZE, + }, + { + .cache = &ecryptfs_header_cache_1, + .name = "ecryptfs_headers_1", + .size = PAGE_CACHE_SIZE, + }, + { + .cache = &ecryptfs_header_cache_2, + .name = "ecryptfs_headers_2", + .size = PAGE_CACHE_SIZE, + }, + { + .cache = &ecryptfs_lower_page_cache, + .name = "ecryptfs_lower_page_cache", + .size = PAGE_CACHE_SIZE, + }, +}; + +static void ecryptfs_free_kmem_caches(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) { + struct ecryptfs_cache_info *info; + + info = &ecryptfs_cache_infos[i]; + if (*(info->cache)) + kmem_cache_destroy(*(info->cache)); + } +} + +/** + * ecryptfs_init_kmem_caches + * + * Returns zero on success; non-zero otherwise + */ +static int ecryptfs_init_kmem_caches(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) { + struct ecryptfs_cache_info *info; + + info = &ecryptfs_cache_infos[i]; + *(info->cache) = kmem_cache_create(info->name, info->size, + 0, SLAB_HWCACHE_ALIGN, info->ctor, NULL); + if (!*(info->cache)) { + ecryptfs_free_kmem_caches(); + ecryptfs_printk(KERN_WARNING, "%s: " + "kmem_cache_create failed\n", + info->name); + return -ENOMEM; + } + } + return 0; +} + +struct ecryptfs_obj { + char *name; + struct list_head slot_list; + struct kobject kobj; +}; + +struct ecryptfs_attribute { + struct attribute attr; + ssize_t(*show) (struct ecryptfs_obj *, char *); + ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t); +}; + +static ssize_t +ecryptfs_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj, + kobj); + struct ecryptfs_attribute *attribute = + container_of(attr, struct ecryptfs_attribute, attr); + + return (attribute->store ? attribute->store(obj, buf, len) : 0); +} + +static ssize_t +ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj, + kobj); + struct ecryptfs_attribute *attribute = + container_of(attr, struct ecryptfs_attribute, attr); + + return (attribute->show ? attribute->show(obj, buf) : 0); +} + +static struct sysfs_ops ecryptfs_sysfs_ops = { + .show = ecryptfs_attr_show, + .store = ecryptfs_attr_store +}; + +static struct kobj_type ecryptfs_ktype = { + .sysfs_ops = &ecryptfs_sysfs_ops +}; + +static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL); + +static ssize_t version_show(struct ecryptfs_obj *obj, char *buff) +{ + return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK); +} + +static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version); + +struct ecryptfs_version_str_map_elem { + u32 flag; + char *str; +} ecryptfs_version_str_map[] = { + {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"}, + {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"}, + {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"}, + {ECRYPTFS_VERSIONING_POLICY, "policy"} +}; + +static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff) +{ + int i; + int remaining = PAGE_SIZE; + int total_written = 0; + + buff[0] = '\0'; + for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) { + int entry_size; + + if (!(ECRYPTFS_VERSIONING_MASK + & ecryptfs_version_str_map[i].flag)) + continue; + entry_size = strlen(ecryptfs_version_str_map[i].str); + if ((entry_size + 2) > remaining) + goto out; + memcpy(buff, ecryptfs_version_str_map[i].str, entry_size); + buff[entry_size++] = '\n'; + buff[entry_size] = '\0'; + buff += entry_size; + total_written += entry_size; + remaining -= entry_size; + } +out: + return total_written; +} + +static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str); + +static int do_sysfs_registration(void) +{ + int rc; + + if ((rc = subsystem_register(&ecryptfs_subsys))) { + printk(KERN_ERR + "Unable to register ecryptfs sysfs subsystem\n"); + goto out; + } + rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj, + &sysfs_attr_version.attr); + if (rc) { + printk(KERN_ERR + "Unable to create ecryptfs version attribute\n"); + subsystem_unregister(&ecryptfs_subsys); + goto out; + } + rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj, + &sysfs_attr_version_str.attr); + if (rc) { + printk(KERN_ERR + "Unable to create ecryptfs version_str attribute\n"); + sysfs_remove_file(&ecryptfs_subsys.kset.kobj, + &sysfs_attr_version.attr); + subsystem_unregister(&ecryptfs_subsys); + goto out; + } +out: + return rc; +} + +static int __init ecryptfs_init(void) +{ + int rc; + + if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is " + "larger than the host's page size, and so " + "eCryptfs cannot run on this system. The " + "default eCryptfs extent size is [%d] bytes; " + "the page size is [%d] bytes.\n", + ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE); + goto out; + } + rc = ecryptfs_init_kmem_caches(); + if (rc) { + printk(KERN_ERR + "Failed to allocate one or more kmem_cache objects\n"); + goto out; + } + rc = register_filesystem(&ecryptfs_fs_type); + if (rc) { + printk(KERN_ERR "Failed to register filesystem\n"); + ecryptfs_free_kmem_caches(); + goto out; + } + kset_set_kset_s(&ecryptfs_subsys, fs_subsys); + sysfs_attr_version.attr.owner = THIS_MODULE; + sysfs_attr_version_str.attr.owner = THIS_MODULE; + rc = do_sysfs_registration(); + if (rc) { + printk(KERN_ERR "sysfs registration failed\n"); + unregister_filesystem(&ecryptfs_fs_type); + ecryptfs_free_kmem_caches(); + goto out; + } +out: + return rc; +} + +static void __exit ecryptfs_exit(void) +{ + sysfs_remove_file(&ecryptfs_subsys.kset.kobj, + &sysfs_attr_version.attr); + sysfs_remove_file(&ecryptfs_subsys.kset.kobj, + &sysfs_attr_version_str.attr); + subsystem_unregister(&ecryptfs_subsys); + unregister_filesystem(&ecryptfs_fs_type); + ecryptfs_free_kmem_caches(); +} + +MODULE_AUTHOR("Michael A. Halcrow "); +MODULE_DESCRIPTION("eCryptfs"); + +MODULE_LICENSE("GPL"); + +module_init(ecryptfs_init) +module_exit(ecryptfs_exit) diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c new file mode 100644 index 00000000000..924dd90a4cf --- /dev/null +++ b/fs/ecryptfs/mmap.c @@ -0,0 +1,788 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * This is where eCryptfs coordinates the symmetric encryption and + * decryption of the file data as it passes between the lower + * encrypted file and the upper decrypted file. + * + * Copyright (C) 1997-2003 Erez Zadok + * Copyright (C) 2001-2003 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * + * 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 +#include +#include "ecryptfs_kernel.h" + +struct kmem_cache *ecryptfs_lower_page_cache; + +/** + * ecryptfs_get1page + * + * Get one page from cache or lower f/s, return error otherwise. + * + * Returns unlocked and up-to-date page (if ok), with increased + * refcnt. + */ +static struct page *ecryptfs_get1page(struct file *file, int index) +{ + struct page *page; + struct dentry *dentry; + struct inode *inode; + struct address_space *mapping; + + dentry = file->f_dentry; + inode = dentry->d_inode; + mapping = inode->i_mapping; + page = read_cache_page(mapping, index, + (filler_t *)mapping->a_ops->readpage, + (void *)file); + if (IS_ERR(page)) + goto out; + wait_on_page_locked(page); +out: + return page; +} + +static +int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); + +/** + * ecryptfs_fill_zeros + * @file: The ecryptfs file + * @new_length: The new length of the data in the underlying file; + * everything between the prior end of the file and the + * new end of the file will be filled with zero's. + * new_length must be greater than current length + * + * Function for handling lseek-ing past the end of the file. + * + * This function does not support shrinking, only growing a file. + * + * Returns zero on success; non-zero otherwise. + */ +int ecryptfs_fill_zeros(struct file *file, loff_t new_length) +{ + int rc = 0; + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + pgoff_t old_end_page_index = 0; + pgoff_t index = old_end_page_index; + int old_end_pos_in_page = -1; + pgoff_t new_end_page_index; + int new_end_pos_in_page; + loff_t cur_length = i_size_read(inode); + + if (cur_length != 0) { + index = old_end_page_index = + ((cur_length - 1) >> PAGE_CACHE_SHIFT); + old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK); + } + new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT); + new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK); + ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; " + "old_end_pos_in_page = [%d]; " + "new_end_page_index = [0x%.16x]; " + "new_end_pos_in_page = [%d]\n", + old_end_page_index, old_end_pos_in_page, + new_end_page_index, new_end_pos_in_page); + if (old_end_page_index == new_end_page_index) { + /* Start and end are in the same page; we just need to + * set a portion of the existing page to zero's */ + rc = write_zeros(file, index, (old_end_pos_in_page + 1), + (new_end_pos_in_page - old_end_pos_in_page)); + if (rc) + ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " + "index=[0x%.16x], " + "old_end_pos_in_page=[d], " + "(PAGE_CACHE_SIZE - new_end_pos_in_page" + "=[%d]" + ")=[d]) returned [%d]\n", file, index, + old_end_pos_in_page, + new_end_pos_in_page, + (PAGE_CACHE_SIZE - new_end_pos_in_page), + rc); + goto out; + } + /* Fill the remainder of the previous last page with zeros */ + rc = write_zeros(file, index, (old_end_pos_in_page + 1), + ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page)); + if (rc) { + ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " + "index=[0x%.16x], old_end_pos_in_page=[d], " + "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) " + "returned [%d]\n", file, index, + old_end_pos_in_page, + (PAGE_CACHE_SIZE - old_end_pos_in_page), rc); + goto out; + } + index++; + while (index < new_end_page_index) { + /* Fill all intermediate pages with zeros */ + rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE); + if (rc) { + ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " + "index=[0x%.16x], " + "old_end_pos_in_page=[d], " + "(PAGE_CACHE_SIZE - new_end_pos_in_page" + "=[%d]" + ")=[d]) returned [%d]\n", file, index, + old_end_pos_in_page, + new_end_pos_in_page, + (PAGE_CACHE_SIZE - new_end_pos_in_page), + rc); + goto out; + } + index++; + } + /* Fill the portion at the beginning of the last new page with + * zero's */ + rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1)); + if (rc) { + ecryptfs_printk(KERN_ERR, "write_zeros(file=" + "[%p], index=[0x%.16x], 0, " + "new_end_pos_in_page=[%d]" + "returned [%d]\n", file, index, + new_end_pos_in_page, rc); + goto out; + } +out: + return rc; +} + +/** + * ecryptfs_writepage + * @page: Page that is locked before this call is made + * + * Returns zero on success; non-zero otherwise + */ +static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) +{ + struct ecryptfs_page_crypt_context ctx; + int rc; + + ctx.page = page; + ctx.mode = ECRYPTFS_WRITEPAGE_MODE; + ctx.param.wbc = wbc; + rc = ecryptfs_encrypt_page(&ctx); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error encrypting " + "page (upper index [0x%.16x])\n", page->index); + ClearPageUptodate(page); + goto out; + } + SetPageUptodate(page); + unlock_page(page); +out: + return rc; +} + +/** + * Reads the data from the lower file file at index lower_page_index + * and copies that data into page. + * + * @param page Page to fill + * @param lower_page_index Index of the page in the lower file to get + */ +int ecryptfs_do_readpage(struct file *file, struct page *page, + pgoff_t lower_page_index) +{ + int rc; + struct dentry *dentry; + struct file *lower_file; + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + char *page_data; + struct page *lower_page = NULL; + char *lower_page_data; + const struct address_space_operations *lower_a_ops; + + dentry = file->f_dentry; + lower_file = ecryptfs_file_to_lower(file); + lower_dentry = ecryptfs_dentry_to_lower(dentry); + inode = dentry->d_inode; + lower_inode = ecryptfs_inode_to_lower(inode); + lower_a_ops = lower_inode->i_mapping->a_ops; + lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index, + (filler_t *)lower_a_ops->readpage, + (void *)lower_file); + if (IS_ERR(lower_page)) { + rc = PTR_ERR(lower_page); + lower_page = NULL; + ecryptfs_printk(KERN_ERR, "Error reading from page cache\n"); + goto out; + } + wait_on_page_locked(lower_page); + page_data = (char *)kmap(page); + if (!page_data) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Error mapping page\n"); + goto out; + } + lower_page_data = (char *)kmap(lower_page); + if (!lower_page_data) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Error mapping page\n"); + kunmap(page); + goto out; + } + memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); + kunmap(lower_page); + kunmap(page); + rc = 0; +out: + if (likely(lower_page)) + page_cache_release(lower_page); + if (rc == 0) + SetPageUptodate(page); + else + ClearPageUptodate(page); + return rc; +} + +/** + * ecryptfs_readpage + * @file: This is an ecryptfs file + * @page: ecryptfs associated page to stick the read data into + * + * Read in a page, decrypting if necessary. + * + * Returns zero on success; non-zero on error. + */ +static int ecryptfs_readpage(struct file *file, struct page *page) +{ + int rc = 0; + struct ecryptfs_crypt_stat *crypt_stat; + + BUG_ON(!(file && file->f_dentry && file->f_dentry->d_inode)); + crypt_stat = + &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat; + if (!crypt_stat + || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED) + || ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) { + ecryptfs_printk(KERN_DEBUG, + "Passing through unencrypted page\n"); + rc = ecryptfs_do_readpage(file, page, page->index); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error reading page; rc = " + "[%d]\n", rc); + goto out; + } + } else { + rc = ecryptfs_decrypt_page(file, page); + if (rc) { + + ecryptfs_printk(KERN_ERR, "Error decrypting page; " + "rc = [%d]\n", rc); + goto out; + } + } + SetPageUptodate(page); +out: + if (rc) + ClearPageUptodate(page); + ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", + page->index); + unlock_page(page); + return rc; +} + +static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) +{ + struct inode *inode = page->mapping->host; + int end_byte_in_page; + int rc = 0; + char *page_virt; + + if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) { + end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; + if (to > end_byte_in_page) + end_byte_in_page = to; + page_virt = kmap(page); + if (!page_virt) { + rc = -ENOMEM; + ecryptfs_printk(KERN_WARNING, + "Could not map page\n"); + goto out; + } + memset((page_virt + end_byte_in_page), 0, + (PAGE_CACHE_SIZE - end_byte_in_page)); + kunmap(page); + } +out: + return rc; +} + +static int ecryptfs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + int rc = 0; + + kmap(page); + if (from == 0 && to == PAGE_CACHE_SIZE) + goto out; /* If we are writing a full page, it will be + up to date. */ + if (!PageUptodate(page)) + rc = ecryptfs_do_readpage(file, page, page->index); +out: + return rc; +} + +int ecryptfs_grab_and_map_lower_page(struct page **lower_page, + char **lower_virt, + struct inode *lower_inode, + unsigned long lower_page_index) +{ + int rc = 0; + + (*lower_page) = grab_cache_page(lower_inode->i_mapping, + lower_page_index); + if (!(*lower_page)) { + ecryptfs_printk(KERN_ERR, "grab_cache_page for " + "lower_page_index = [0x%.16x] failed\n", + lower_page_index); + rc = -EINVAL; + goto out; + } + if (lower_virt) + (*lower_virt) = kmap((*lower_page)); + else + kmap((*lower_page)); +out: + return rc; +} + +int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, + struct inode *lower_inode, + struct writeback_control *wbc) +{ + int rc = 0; + + rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); " + "rc = [%d]\n", rc); + goto out; + } + lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; + page_cache_release(lower_page); +out: + return rc; +} + +static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page) +{ + kunmap(lower_page); + ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = " + "[0x%.16x]\n", lower_page->index); + unlock_page(lower_page); + page_cache_release(lower_page); +} + +/** + * ecryptfs_write_inode_size_to_header + * + * Writes the lower file size to the first 8 bytes of the header. + * + * Returns zero on success; non-zero on error. + */ +int +ecryptfs_write_inode_size_to_header(struct file *lower_file, + struct inode *lower_inode, + struct inode *inode) +{ + int rc = 0; + struct page *header_page; + char *header_virt; + const struct address_space_operations *lower_a_ops; + u64 file_size; + + rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt, + lower_inode, 0); + if (rc) { + ecryptfs_printk(KERN_ERR, "grab_cache_page for header page " + "failed\n"); + goto out; + } + lower_a_ops = lower_inode->i_mapping->a_ops; + rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8); + file_size = (u64)i_size_read(inode); + ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size); + file_size = cpu_to_be64(file_size); + memcpy(header_virt, &file_size, sizeof(u64)); + rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8); + if (rc < 0) + ecryptfs_printk(KERN_ERR, "Error commiting header page " + "write\n"); + ecryptfs_unmap_and_release_lower_page(header_page); + lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; + mark_inode_dirty_sync(inode); +out: + return rc; +} + +int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, + struct file *lower_file, + unsigned long lower_page_index, int byte_offset, + int region_bytes) +{ + int rc = 0; + + rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, lower_inode, + lower_page_index); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting to grab and map " + "lower page with index [0x%.16x]\n", + lower_page_index); + goto out; + } + rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file, + (*lower_page), + byte_offset, + region_bytes); + if (rc) { + ecryptfs_printk(KERN_ERR, "prepare_write for " + "lower_page_index = [0x%.16x] failed; rc = " + "[%d]\n", lower_page_index, rc); + } +out: + if (rc && (*lower_page)) { + ecryptfs_unmap_and_release_lower_page(*lower_page); + (*lower_page) = NULL; + } + return rc; +} + +/** + * ecryptfs_commit_lower_page + * + * Returns zero on success; non-zero on error + */ +int +ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, + struct file *lower_file, int byte_offset, + int region_size) +{ + int rc = 0; + + rc = lower_inode->i_mapping->a_ops->commit_write( + lower_file, lower_page, byte_offset, region_size); + if (rc < 0) { + ecryptfs_printk(KERN_ERR, + "Error committing write; rc = [%d]\n", rc); + } else + rc = 0; + ecryptfs_unmap_and_release_lower_page(lower_page); + return rc; +} + +/** + * ecryptfs_copy_page_to_lower + * + * Used for plaintext pass-through; no page index interpolation + * required. + */ +int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, + struct file *lower_file) +{ + int rc = 0; + struct page *lower_page; + + rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file, + page->index, 0, PAGE_CACHE_SIZE); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error attempting to get page " + "at index [0x%.16x]\n", page->index); + goto out; + } + /* TODO: aops */ + memcpy((char *)page_address(lower_page), page_address(page), + PAGE_CACHE_SIZE); + rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file, + 0, PAGE_CACHE_SIZE); + if (rc) + ecryptfs_printk(KERN_ERR, "Error attempting to commit page " + "at index [0x%.16x]\n", page->index); +out: + return rc; +} + +static int +process_new_file(struct ecryptfs_crypt_stat *crypt_stat, + struct file *file, struct inode *inode) +{ + struct page *header_page; + const struct address_space_operations *lower_a_ops; + struct inode *lower_inode; + struct file *lower_file; + char *header_virt; + int rc = 0; + int current_header_page = 0; + int header_pages; + int more_header_data_to_be_written = 1; + + lower_inode = ecryptfs_inode_to_lower(inode); + lower_file = ecryptfs_file_to_lower(file); + lower_a_ops = lower_inode->i_mapping->a_ops; + header_pages = ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + / PAGE_CACHE_SIZE); + BUG_ON(header_pages < 1); + while (current_header_page < header_pages) { + rc = ecryptfs_grab_and_map_lower_page(&header_page, + &header_virt, + lower_inode, + current_header_page); + if (rc) { + ecryptfs_printk(KERN_ERR, "grab_cache_page for " + "header page [%d] failed; rc = [%d]\n", + current_header_page, rc); + goto out; + } + rc = lower_a_ops->prepare_write(lower_file, header_page, 0, + PAGE_CACHE_SIZE); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error preparing to write " + "header page out; rc = [%d]\n", rc); + goto out; + } + memset(header_virt, 0, PAGE_CACHE_SIZE); + if (more_header_data_to_be_written) { + rc = ecryptfs_write_headers_virt(header_virt, + crypt_stat, + file->f_dentry); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error " + "generating header; rc = " + "[%d]\n", rc); + rc = -EIO; + memset(header_virt, 0, PAGE_CACHE_SIZE); + ecryptfs_unmap_and_release_lower_page( + header_page); + goto out; + } + if (current_header_page == 0) + memset(header_virt, 0, 8); + more_header_data_to_be_written = 0; + } + rc = lower_a_ops->commit_write(lower_file, header_page, 0, + PAGE_CACHE_SIZE); + ecryptfs_unmap_and_release_lower_page(header_page); + if (rc < 0) { + ecryptfs_printk(KERN_ERR, + "Error commiting header page write; " + "rc = [%d]\n", rc); + break; + } + current_header_page++; + } + if (rc >= 0) { + rc = 0; + ecryptfs_printk(KERN_DEBUG, "lower_inode->i_blocks = " + "[0x%.16x]\n", lower_inode->i_blocks); + i_size_write(inode, 0); + lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; + mark_inode_dirty_sync(inode); + } + ecryptfs_printk(KERN_DEBUG, "Clearing ECRYPTFS_NEW_FILE flag in " + "crypt_stat at memory location [%p]\n", crypt_stat); + ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE); +out: + return rc; +} + +/** + * ecryptfs_commit_write + * @file: The eCryptfs file object + * @page: The eCryptfs page + * @from: Ignored (we rotate the page IV on each write) + * @to: Ignored + * + * This is where we encrypt the data and pass the encrypted data to + * the lower filesystem. In OpenPGP-compatible mode, we operate on + * entire underlying packets. + */ +static int ecryptfs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct ecryptfs_page_crypt_context ctx; + loff_t pos; + struct inode *inode; + struct inode *lower_inode; + struct file *lower_file; + struct ecryptfs_crypt_stat *crypt_stat; + int rc; + + inode = page->mapping->host; + lower_inode = ecryptfs_inode_to_lower(inode); + lower_file = ecryptfs_file_to_lower(file); + mutex_lock(&lower_inode->i_mutex); + crypt_stat = + &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat; + if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) { + ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " + "crypt_stat at memory location [%p]\n", crypt_stat); + rc = process_new_file(crypt_stat, file, inode); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error processing new " + "file; rc = [%d]\n", rc); + goto out; + } + } else + ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); + ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" + "(page w/ index = [0x%.16x], to = [%d])\n", page->index, + to); + rc = fill_zeros_to_end_of_page(page, to); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error attempting to fill " + "zeros in page with index = [0x%.16x]\n", + page->index); + goto out; + } + ctx.page = page; + ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE; + ctx.param.lower_file = lower_file; + rc = ecryptfs_encrypt_page(&ctx); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " + "index [0x%.16x])\n", page->index); + goto out; + } + rc = 0; + inode->i_blocks = lower_inode->i_blocks; + pos = (page->index << PAGE_CACHE_SHIFT) + to; + if (pos > i_size_read(inode)) { + i_size_write(inode, pos); + ecryptfs_printk(KERN_DEBUG, "Expanded file size to " + "[0x%.16x]\n", i_size_read(inode)); + } + ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode); + lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; + mark_inode_dirty_sync(inode); +out: + kunmap(page); /* mapped in prior call (prepare_write) */ + if (rc < 0) + ClearPageUptodate(page); + else + SetPageUptodate(page); + mutex_unlock(&lower_inode->i_mutex); + return rc; +} + +/** + * write_zeros + * @file: The ecryptfs file + * @index: The index in which we are writing + * @start: The position after the last block of data + * @num_zeros: The number of zeros to write + * + * Write a specified number of zero's to a page. + * + * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE + */ +static +int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) +{ + int rc = 0; + struct page *tmp_page; + + tmp_page = ecryptfs_get1page(file, index); + if (IS_ERR(tmp_page)) { + ecryptfs_printk(KERN_ERR, "Error getting page at index " + "[0x%.16x]\n", index); + rc = PTR_ERR(tmp_page); + goto out; + } + kmap(tmp_page); + rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " + "to remainder of page at index [0x%.16x]\n", + index); + kunmap(tmp_page); + page_cache_release(tmp_page); + goto out; + } + memset(((char *)page_address(tmp_page) + start), 0, num_zeros); + rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); + if (rc < 0) { + ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " + "to remainder of page at index [0x%.16x]\n", + index); + kunmap(tmp_page); + page_cache_release(tmp_page); + goto out; + } + rc = 0; + kunmap(tmp_page); + page_cache_release(tmp_page); +out: + return rc; +} + +static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) +{ + int rc = 0; + struct inode *inode; + struct inode *lower_inode; + + inode = (struct inode *)mapping->host; + lower_inode = ecryptfs_inode_to_lower(inode); + if (lower_inode->i_mapping->a_ops->bmap) + rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping, + block); + return rc; +} + +static void ecryptfs_sync_page(struct page *page) +{ + struct inode *inode; + struct inode *lower_inode; + struct page *lower_page; + + inode = page->mapping->host; + lower_inode = ecryptfs_inode_to_lower(inode); + /* NOTE: Recently swapped with grab_cache_page(), since + * sync_page() just makes sure that pending I/O gets done. */ + lower_page = find_lock_page(lower_inode->i_mapping, page->index); + if (!lower_page) { + ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n"); + return; + } + lower_page->mapping->a_ops->sync_page(lower_page); + ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", + lower_page->index); + unlock_page(lower_page); + page_cache_release(lower_page); +} + +struct address_space_operations ecryptfs_aops = { + .writepage = ecryptfs_writepage, + .readpage = ecryptfs_readpage, + .prepare_write = ecryptfs_prepare_write, + .commit_write = ecryptfs_commit_write, + .bmap = ecryptfs_bmap, + .sync_page = ecryptfs_sync_page, +}; diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c new file mode 100644 index 00000000000..c337c0410fb --- /dev/null +++ b/fs/ecryptfs/super.c @@ -0,0 +1,198 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2003 Erez Zadok + * Copyright (C) 2001-2003 Stony Brook University + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow + * Michael C. Thompson + * + * 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 "ecryptfs_kernel.h" + +struct kmem_cache *ecryptfs_inode_info_cache; + +/** + * ecryptfs_alloc_inode - allocate an ecryptfs inode + * @sb: Pointer to the ecryptfs super block + * + * Called to bring an inode into existence. + * + * Only handle allocation, setting up structures should be done in + * ecryptfs_read_inode. This is because the kernel, between now and + * then, will 0 out the private data pointer. + * + * Returns a pointer to a newly allocated inode, NULL otherwise + */ +static struct inode *ecryptfs_alloc_inode(struct super_block *sb) +{ + struct ecryptfs_inode_info *ecryptfs_inode; + struct inode *inode = NULL; + + ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache, + SLAB_KERNEL); + if (unlikely(!ecryptfs_inode)) + goto out; + ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat); + inode = &ecryptfs_inode->vfs_inode; +out: + return inode; +} + +/** + * ecryptfs_destroy_inode + * @inode: The ecryptfs inode + * + * This is used during the final destruction of the inode. + * All allocation of memory related to the inode, including allocated + * memory in the crypt_stat struct, will be released here. + * There should be no chance that this deallocation will be missed. + */ +static void ecryptfs_destroy_inode(struct inode *inode) +{ + struct ecryptfs_inode_info *inode_info; + + inode_info = ecryptfs_inode_to_private(inode); + ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat); + kmem_cache_free(ecryptfs_inode_info_cache, inode_info); +} + +/** + * ecryptfs_init_inode + * @inode: The ecryptfs inode + * + * Set up the ecryptfs inode. + */ +void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode) +{ + ecryptfs_set_inode_lower(inode, lower_inode); + inode->i_ino = lower_inode->i_ino; + inode->i_version++; + inode->i_op = &ecryptfs_main_iops; + inode->i_fop = &ecryptfs_main_fops; + inode->i_mapping->a_ops = &ecryptfs_aops; +} + +/** + * ecryptfs_put_super + * @sb: Pointer to the ecryptfs super block + * + * Final actions when unmounting a file system. + * This will handle deallocation and release of our private data. + */ +static void ecryptfs_put_super(struct super_block *sb) +{ + struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb); + + ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat); + kmem_cache_free(ecryptfs_sb_info_cache, sb_info); + ecryptfs_set_superblock_private(sb, NULL); +} + +/** + * ecryptfs_statfs + * @sb: The ecryptfs super block + * @buf: The struct kstatfs to fill in with stats + * + * Get the filesystem statistics. Currently, we let this pass right through + * to the lower filesystem and take no action ourselves. + */ +static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf); +} + +/** + * ecryptfs_clear_inode + * @inode - The ecryptfs inode + * + * Called by iput() when the inode reference count reached zero + * and the inode is not hashed anywhere. Used to clear anything + * that needs to be, before the inode is completely destroyed and put + * on the inode free list. We use this to drop out reference to the + * lower inode. + */ +static void ecryptfs_clear_inode(struct inode *inode) +{ + iput(ecryptfs_inode_to_lower(inode)); +} + +/** + * ecryptfs_umount_begin + * + * Called in do_umount(). + */ +static void ecryptfs_umount_begin(struct vfsmount *vfsmnt, int flags) +{ + struct vfsmount *lower_mnt = + ecryptfs_dentry_to_lower_mnt(vfsmnt->mnt_sb->s_root); + struct super_block *lower_sb; + + mntput(lower_mnt); + lower_sb = lower_mnt->mnt_sb; + if (lower_sb->s_op->umount_begin) + lower_sb->s_op->umount_begin(lower_mnt, flags); +} + +/** + * ecryptfs_show_options + * + * Prints the directory we are currently mounted over. + * Returns zero on success; non-zero otherwise + */ +static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct super_block *sb = mnt->mnt_sb; + struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root); + char *tmp_page; + char *path; + int rc = 0; + + tmp_page = (char *)__get_free_page(GFP_KERNEL); + if (!tmp_page) { + rc = -ENOMEM; + goto out; + } + path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE); + if (IS_ERR(path)) { + rc = PTR_ERR(path); + goto out; + } + seq_printf(m, ",dir=%s", path); + free_page((unsigned long)tmp_page); +out: + return rc; +} + +struct super_operations ecryptfs_sops = { + .alloc_inode = ecryptfs_alloc_inode, + .destroy_inode = ecryptfs_destroy_inode, + .drop_inode = generic_delete_inode, + .put_super = ecryptfs_put_super, + .statfs = ecryptfs_statfs, + .remount_fs = NULL, + .clear_inode = ecryptfs_clear_inode, + .umount_begin = ecryptfs_umount_begin, + .show_options = ecryptfs_show_options +}; -- GitLab From 0271eb947db2704a0ff8be68d72915ab021d1ead Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 4 Oct 2006 02:16:24 -0700 Subject: [PATCH 0530/1619] [PATCH] fbdev: riva warning fix drivers/video/riva/fbdev.c: In function `riva_get_EDID_OF': drivers/video/riva/fbdev.c:1846: warning: assignment discards qualifiers from pointer target type This code is being bad: copying a pointer to read-only OF data into a non-const pointer. Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/riva/fbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index b120896c8ab..a433cc78ef9 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1843,7 +1843,7 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) for (i = 0; propnames[i] != NULL; ++i) { pedid = get_property(dp, propnames[i], NULL); if (pedid != NULL) { - par->EDID = pedid; + par->EDID = (unsigned char *)pedid; NVTRACE("LCD found.\n"); return 1; } -- GitLab From f29bd1ba68c8c6a0f50bd678bbd5a26674018f7c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 4 Oct 2006 02:16:25 -0700 Subject: [PATCH 0531/1619] [PATCH] genirq: convert the x86_64 architecture to irq-chips This patch converts all the x86_64 PIC controllers layers to the new and simpler irq-chip interrupt handling layer. [mingo@elte.hu: The patch also enables the fasteoi handler for x86_64] Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Roland Dreier Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/i8259.c | 50 ++++---------- arch/x86_64/kernel/io_apic.c | 130 ++++++++--------------------------- arch/x86_64/kernel/irq.c | 5 +- include/asm-x86_64/hw_irq.h | 2 - 4 files changed, 44 insertions(+), 143 deletions(-) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 2dd51f364ea..ae1101cd525 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -121,42 +121,15 @@ void (*interrupt[NR_IRQS])(void) = { * moves to arch independent land */ -DEFINE_SPINLOCK(i8259A_lock); - static int i8259A_auto_eoi; - -static void end_8259A_irq (unsigned int irq) -{ - if (irq > 256) { - char var; - printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current)); - - BUG(); - } - - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && - irq_desc[irq].action) - enable_8259A_irq(irq); -} - -#define shutdown_8259A_irq disable_8259A_irq - +DEFINE_SPINLOCK(i8259A_lock); static void mask_and_ack_8259A(unsigned int); -static unsigned int startup_8259A_irq(unsigned int irq) -{ - enable_8259A_irq(irq); - return 0; /* never anything pending */ -} - -static struct hw_interrupt_type i8259A_irq_type = { - .typename = "XT-PIC", - .startup = startup_8259A_irq, - .shutdown = shutdown_8259A_irq, - .enable = enable_8259A_irq, - .disable = disable_8259A_irq, - .ack = mask_and_ack_8259A, - .end = end_8259A_irq, +static struct irq_chip i8259A_chip = { + .name = "XT-PIC", + .mask = disable_8259A_irq, + .unmask = enable_8259A_irq, + .mask_ack = mask_and_ack_8259A, }; /* @@ -231,7 +204,7 @@ void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); io_apic_irqs &= ~(1<typename); + seq_printf(p, " %8s", irq_desc[i].chip->name); + seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -117,7 +118,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) #ifdef CONFIG_DEBUG_STACKOVERFLOW stack_overflow_check(regs); #endif - __do_IRQ(irq, regs); + generic_handle_irq(irq, regs); irq_exit(); return 1; diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 48a4a5364e8..f5da94af9c4 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -19,8 +19,6 @@ #include #include #include - -struct hw_interrupt_type; #endif #define NMI_VECTOR 0x02 -- GitLab From f5b9ed7acdcfea4bf73a70dececa7483787503ed Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 4 Oct 2006 02:16:26 -0700 Subject: [PATCH 0532/1619] [PATCH] genirq: convert the i386 architecture to irq-chips This patch converts all the i386 PIC controllers (except VisWS and Voyager, which I could not test - but which should still work as old-style IRQ layers) to the new and simpler irq-chip interrupt handling layer. [akpm@osdl.org: build fix] [mingo@elte.hu: enable fasteoi handler for i386 level-triggered IO-APIC irqs] Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/i8259.c | 45 +++-------- arch/i386/kernel/io_apic.c | 160 +++++++++++++------------------------ arch/i386/kernel/irq.c | 19 +++-- include/asm-i386/hw_irq.h | 2 - 4 files changed, 80 insertions(+), 146 deletions(-) diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index ea5f4e7958d..d07ed31f11e 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -34,35 +34,15 @@ * moves to arch independent land */ -DEFINE_SPINLOCK(i8259A_lock); - -static void end_8259A_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && - irq_desc[irq].action) - enable_8259A_irq(irq); -} - -#define shutdown_8259A_irq disable_8259A_irq - static int i8259A_auto_eoi; - +DEFINE_SPINLOCK(i8259A_lock); static void mask_and_ack_8259A(unsigned int); -unsigned int startup_8259A_irq(unsigned int irq) -{ - enable_8259A_irq(irq); - return 0; /* never anything pending */ -} - -static struct hw_interrupt_type i8259A_irq_type = { - .typename = "XT-PIC", - .startup = startup_8259A_irq, - .shutdown = shutdown_8259A_irq, - .enable = enable_8259A_irq, - .disable = disable_8259A_irq, - .ack = mask_and_ack_8259A, - .end = end_8259A_irq, +static struct irq_chip i8259A_chip = { + .name = "XT-PIC", + .mask = disable_8259A_irq, + .unmask = enable_8259A_irq, + .mask_ack = mask_and_ack_8259A, }; /* @@ -133,7 +113,7 @@ void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); io_apic_irqs &= ~(1<orig_eax; + struct irq_desc *desc = irq_desc + irq; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; u32 *isp; @@ -94,7 +95,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, ebx; + int arg1, arg2, arg3, ebx; /* build the stack frame on the IRQ stack */ isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); @@ -110,16 +111,17 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) (curctx->tinfo.preempt_count & SOFTIRQ_MASK); asm volatile( - " xchgl %%ebx,%%esp \n" - " call __do_IRQ \n" + " xchgl %%ebx,%%esp \n" + " call *%%edi \n" " movl %%ebx,%%esp \n" - : "=a" (arg1), "=d" (arg2), "=b" (ebx) - : "0" (irq), "1" (regs), "2" (isp) - : "memory", "cc", "ecx" + : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx) + : "0" (irq), "1" (desc), "2" (regs), "3" (isp), + "D" (desc->handle_irq) + : "memory", "cc" ); } else #endif - __do_IRQ(irq, regs); + desc->handle_irq(irq, desc, regs); irq_exit(); @@ -253,7 +255,8 @@ int show_interrupts(struct seq_file *p, void *v) for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %14s", irq_desc[i].chip->typename); + seq_printf(p, " %8s", irq_desc[i].chip->name); + seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 87e5a351d88..8e8fbfaa252 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -17,8 +17,6 @@ #include #include -struct hw_interrupt_type; - #define NMI_VECTOR 0x02 /* -- GitLab From a24ceab4f44f21749aa0b6bd38bee37c775e036f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:27 -0700 Subject: [PATCH 0533/1619] [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(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 48d3cb3b6a4..3eab46f590a 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 a57ebe9fa6f..9b234df810d 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; -- GitLab From e7b946e98a456077dd6897f726f3d6197bd7e3b9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:29 -0700 Subject: [PATCH 0534/1619] [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(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 3eab46f590a..a31a7d8acdb 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 9b234df810d..4baa3bbcd25 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); +} + -- GitLab From 0be6652f1e61b647f738eb25af057bf9551a9841 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:30 -0700 Subject: [PATCH 0535/1619] [PATCH] genirq: x86_64 irq: Reenable migrating irqs to other cpus In the latest changes the code for migrating x86_64 irqs was dropped. This reads it in a fashion that will work even if we change the vector on level triggered irqs when we migrate them. [akpm@osdl.org: build fix] 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 --- arch/x86_64/kernel/io_apic.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index e1d1b4217cb..12dd938f5d5 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1254,18 +1254,48 @@ static int ioapic_retrigger_vector(unsigned int vector) * races. */ -static void ack_apic(unsigned int vector) +static void ack_apic(unsigned int irq) { ack_APIC_irq(); } +static void ack_apic_edge(unsigned int irq) +{ + move_native_irq(irq); + ack_APIC_irq(); +} + +static void ack_apic_level(unsigned int irq) +{ + int do_unmask_irq = 0; + +#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) + /* If we are moving the irq we need to mask it */ + if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { + do_unmask_irq = 1; + mask_IO_APIC_irq(irq); + } +#endif + + /* + * We must acknowledge the irq before we move it or the acknowledge will + * not propogate properly. + */ + ack_APIC_irq(); + + /* Now we can move and renable the irq */ + move_masked_irq(irq); + if (unlikely(do_unmask_irq)) + unmask_IO_APIC_irq(irq); +} + static struct irq_chip ioapic_chip __read_mostly = { .name = "IO-APIC", .startup = startup_ioapic_vector, .mask = mask_ioapic_vector, .unmask = unmask_ioapic_vector, - .ack = ack_apic, - .eoi = ack_apic, + .ack = ack_apic_edge, + .eoi = ack_apic_level, #ifdef CONFIG_SMP .set_affinity = set_ioapic_affinity_vector, #endif -- GitLab From 7bd007e480672c99d8656c7b7b12ef0549432c37 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:31 -0700 Subject: [PATCH 0536/1619] [PATCH] genirq: msi: simplify msi enable and disable The problem. Because the disable routines leave the msi interrupts in all sorts of half enabled states the enable routines become impossible to implement correctly, and almost impossible to understand. Simplifing this allows me to simply kill the buggy reroute_msix_table, and generally makes the code more maintainable. 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" Cc: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/msi.c | 122 ++++++---------------------------------------- 1 file changed, 16 insertions(+), 106 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 27a057409ec..75d1c0dacff 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -933,7 +933,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; @@ -948,27 +947,8 @@ int pci_enable_msi(struct pci_dev* dev) if (!pos) return -EINVAL; - if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { - /* Lookup Sucess */ - unsigned long flags; + WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI)); - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (control & PCI_MSI_FLAGS_ENABLE) - return 0; /* Already in MSI mode */ - spin_lock_irqsave(&msi_lock, flags); - if (!vector_irq[dev->irq]) { - msi_desc[dev->irq]->msi_attrib.state = 0; - vector_irq[dev->irq] = -1; - nr_released_vectors--; - spin_unlock_irqrestore(&msi_lock, flags); - status = msi_register_init(dev, msi_desc[dev->irq]); - if (status == 0) - enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); - return status; - } - spin_unlock_irqrestore(&msi_lock, flags); - dev->irq = temp; - } /* Check whether driver already requested for MSI-X vectors */ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { @@ -1010,6 +990,8 @@ void pci_disable_msi(struct pci_dev* dev) if (!(control & PCI_MSI_FLAGS_ENABLE)) return; + disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[dev->irq]; if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { @@ -1023,14 +1005,12 @@ void pci_disable_msi(struct pci_dev* dev) pci_name(dev), dev->irq); BUG_ON(entry->msi_attrib.state > 0); } else { - vector_irq[dev->irq] = 0; /* free it */ - nr_released_vectors++; default_vector = entry->msi_attrib.default_vector; spin_unlock_irqrestore(&msi_lock, flags); + msi_free_vector(dev, dev->irq, 0); + /* Restore dev->irq to its default pin-assertion vector */ dev->irq = default_vector; - disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), - PCI_CAP_ID_MSI); } } @@ -1078,57 +1058,6 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) return 0; } -static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) -{ - int vector = head, tail = 0; - int i, j = 0, nr_entries = 0; - void __iomem *base; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - while (head != tail) { - nr_entries++; - tail = msi_desc[vector]->link.tail; - if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr) - j = vector; - vector = tail; - } - if (*nvec > nr_entries) { - spin_unlock_irqrestore(&msi_lock, flags); - *nvec = nr_entries; - return -EINVAL; - } - vector = ((j > 0) ? j : head); - for (i = 0; i < *nvec; i++) { - j = msi_desc[vector]->msi_attrib.entry_nr; - msi_desc[vector]->msi_attrib.state = 0; /* Mark it not active */ - vector_irq[vector] = -1; /* Mark it busy */ - nr_released_vectors--; - entries[i].vector = vector; - if (j != (entries + i)->entry) { - base = msi_desc[vector]->mask_base; - msi_desc[vector]->msi_attrib.entry_nr = - (entries + i)->entry; - writel( readl(base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base + - (entries + i)->entry * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel( readl(base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base + - (entries + i)->entry * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector, - base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_DATA_OFFSET); - } - vector = msi_desc[vector]->link.tail; - } - spin_unlock_irqrestore(&msi_lock, flags); - - return 0; -} - /** * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function @@ -1163,9 +1092,6 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) return -EINVAL; pci_read_config_word(dev, msi_control_reg(pos), &control); - if (control & PCI_MSIX_FLAGS_ENABLE) - return -EINVAL; /* Already in MSI-X mode */ - nr_entries = multi_msix_capable(control); if (nvec > nr_entries) return -EINVAL; @@ -1180,19 +1106,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) } } temp = dev->irq; - if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { - /* Lookup Sucess */ - nr_entries = nvec; - /* Reroute MSI-X table */ - if (reroute_msix_table(dev->irq, entries, &nr_entries)) { - /* #requested > #previous-assigned */ - dev->irq = temp; - return nr_entries; - } - dev->irq = temp; - enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); - return 0; - } + WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)); + /* Check whether driver already requested for MSI vector */ if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { @@ -1251,37 +1166,32 @@ void pci_disable_msix(struct pci_dev* dev) if (!(control & PCI_MSIX_FLAGS_ENABLE)) return; + disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); + temp = dev->irq; if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { int state, vector, head, tail = 0, warning = 0; unsigned long flags; vector = head = dev->irq; - spin_lock_irqsave(&msi_lock, flags); + dev->irq = temp; /* Restore pin IRQ */ while (head != tail) { + spin_lock_irqsave(&msi_lock, flags); state = msi_desc[vector]->msi_attrib.state; + tail = msi_desc[vector]->link.tail; + spin_unlock_irqrestore(&msi_lock, flags); if (state) warning = 1; - else { - vector_irq[vector] = 0; /* free it */ - nr_released_vectors++; - } - tail = msi_desc[vector]->link.tail; + else if (vector != head) /* Release MSI-X vector */ + msi_free_vector(dev, vector, 0); vector = tail; } - spin_unlock_irqrestore(&msi_lock, flags); + msi_free_vector(dev, vector, 0); if (warning) { - dev->irq = temp; printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " "free_irq() on all MSI-X vectors\n", pci_name(dev)); BUG_ON(warning > 0); - } else { - dev->irq = temp; - disable_msi_mode(dev, - pci_find_capability(dev, PCI_CAP_ID_MSIX), - PCI_CAP_ID_MSIX); - } } } -- GitLab From dd159eeca971d594fa30176733b66d37acda82a3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:32 -0700 Subject: [PATCH 0537/1619] [PATCH] genirq: msi: make the msi boolean tests return either 0 or 1 This allows the output of the msi tests to be stored directly in a bit field. If you don't do this a value greater than one will be truncated and become 0. Changing true to false with bizare consequences. 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.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 56951c39d3a..9b31d4cbbce 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -110,8 +110,8 @@ extern int pci_vector_resources(int last, int nr_released); (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1)) #define multi_msi_enable(control, num) \ control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE); -#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT) -#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT) +#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) +#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) #define msi_enable(control, num) multi_msi_enable(control, num); \ control |= PCI_MSI_FLAGS_ENABLE -- GitLab From 0366f8f7137deb072991e4c50769c6da31f8940c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:33 -0700 Subject: [PATCH 0538/1619] [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(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 75d1c0dacff..cca6cb3ccda 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 9b31d4cbbce..62f61b61d2c 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 4431ce4e1e6..b9bb6c46e05 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;} -- GitLab From 38bc0361303535c86f6b67b151a541728d7bdae6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:34 -0700 Subject: [PATCH 0539/1619] [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(-) diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index bed4183a5e3..7aedc2ac8c2 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 5ed798b319c..afc0ed13aa8 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 cca6cb3ccda..6d9de026e14 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 62f61b61d2c..3519eca50d8 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 b9bb6c46e05..2aabe90f1cd 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); -- GitLab From 92db6d10bc1bc43330a4c540fa5b64c83d9d865f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:35 -0700 Subject: [PATCH 0540/1619] [PATCH] genirq: msi: simplify the msi irq limit policy Currently we attempt to predict how many irqs we will be able to allocate with msi using pci_vector_resources and some complicated accounting, and then we only allow each device as many irqs as we think are available on average. Only the s2io driver even takes advantage of this feature all other drivers have a fixed number of irqs they need and bail if they can't get them. pci_vector_resources is inaccurate if anyone ever frees an irq. The whole implmentation is racy. The current irq limit policy does not appear to make sense with current drivers. So I have simplified things. We can revisit this we we need a more sophisticated policy. 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 --- arch/i386/pci/irq.c | 30 ------------------------- arch/ia64/pci/pci.c | 9 -------- drivers/pci/msi.c | 53 +++++++-------------------------------------- drivers/pci/msi.h | 11 ---------- 4 files changed, 8 insertions(+), 95 deletions(-) diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 4a8995c9c76..960f364cab6 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -1169,33 +1169,3 @@ static int pirq_enable_irq(struct pci_dev *dev) } return 0; } - -int pci_vector_resources(int last, int nr_released) -{ - int count = nr_released; - - int next = last; - int offset = (last % 8); - - while (next < FIRST_SYSTEM_VECTOR) { - next += 8; -#ifdef CONFIG_X86_64 - if (next == IA32_SYSCALL_VECTOR) - continue; -#else - if (next == SYSCALL_VECTOR) - continue; -#endif - count++; - if (next >= FIRST_SYSTEM_VECTOR) { - if (offset%8) { - next = FIRST_DEVICE_VECTOR + offset; - offset++; - continue; - } - count--; - } - } - - return count; -} diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 15c7c670da3..b30be7c48ba 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -810,12 +810,3 @@ pcibios_prep_mwi (struct pci_dev *dev) } return rc; } - -int pci_vector_resources(int last, int nr_released) -{ - int count = nr_released; - - count += (IA64_LAST_DEVICE_VECTOR - last); - - return count; -} diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 6d9de026e14..a32e75a4417 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -29,8 +29,6 @@ static kmem_cache_t* msi_cachep; static int pci_msi_enable = 1; static int last_alloc_vector; static int nr_released_vectors; -static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS; -static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; @@ -534,11 +532,6 @@ void pci_scan_msi_device(struct pci_dev *dev) { if (!dev) return; - - if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0) - nr_msix_devices++; - else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0) - nr_reserved_vectors++; } #ifdef CONFIG_PM @@ -869,13 +862,19 @@ static int msix_capability_init(struct pci_dev *dev, attach_msi_entry(entry, vector); } if (i != nvec) { + int avail = i - 1; i--; for (; i >= 0; i--) { vector = (entries + i)->vector; msi_free_vector(dev, vector, 0); (entries + i)->vector = 0; } - return -EBUSY; + /* If we had some success report the number of irqs + * we succeeded in setting up. + */ + if (avail <= 0) + avail = -EBUSY; + return avail; } /* Set MSI-X enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); @@ -954,14 +953,6 @@ int pci_enable_msi(struct pci_dev* dev) return -EINVAL; } status = msi_capability_init(dev); - if (!status) { - if (!pos) - nr_reserved_vectors--; /* Only MSI capable */ - else if (nr_msix_devices > 0) - nr_msix_devices--; /* Both MSI and MSI-X capable, - but choose enabling MSI */ - } - return status; } @@ -1070,10 +1061,9 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) **/ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { - int status, pos, nr_entries, free_vectors; + int status, pos, nr_entries; int i, j, temp; u16 control; - unsigned long flags; if (!entries || pci_msi_supported(dev) < 0) return -EINVAL; @@ -1112,34 +1102,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) dev->irq = temp; return -EINVAL; } - - spin_lock_irqsave(&msi_lock, flags); - /* - * msi_lock is provided to ensure that enough vectors resources are - * available before granting. - */ - free_vectors = pci_vector_resources(last_alloc_vector, - nr_released_vectors); - /* Ensure that each MSI/MSI-X device has one vector reserved by - default to avoid any MSI-X driver to take all available - resources */ - free_vectors -= nr_reserved_vectors; - /* Find the average of free vectors among MSI-X devices */ - if (nr_msix_devices > 0) - free_vectors /= nr_msix_devices; - spin_unlock_irqrestore(&msi_lock, flags); - - if (nvec > free_vectors) { - if (free_vectors > 0) - return free_vectors; - else - return -EBUSY; - } - status = msix_capability_init(dev, entries, nvec); - if (!status && nr_msix_devices > 0) - nr_msix_devices--; - return status; } diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 3519eca50d8..6793241f388 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -8,19 +8,8 @@ #include -/* - * Assume the maximum number of hot plug slots supported by the system is about - * ten. The worstcase is that each of these slots is hot-added with a device, - * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which - * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined - * as below to ensure at least one message is assigned to each detected MSI/ - * MSI-X device function. - */ -#define NR_HP_RESERVED_VECTORS 20 - extern int vector_irq[NR_VECTORS]; extern void (*interrupt[NR_IRQS])(void); -extern int pci_vector_resources(int last, int nr_released); /* * MSI-X Address Register -- GitLab From 3a16d713626735f3016da0521b7bf251cd78e836 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:37 -0700 Subject: [PATCH 0541/1619] [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(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index a31a7d8acdb..82dbb0e8f40 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 736cb0bd498..0dc24386dd9 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 -- GitLab From b6cf2583ba026ca563ff8b15805fcf30b8e192a7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:38 -0700 Subject: [PATCH 0542/1619] [PATCH] genirq: ia64 irq: Dynamic irq support [akpm@osdl.org: build fix] 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 --- arch/ia64/kernel/irq_ia64.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index aafca18ab33..ab2d19c3661 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,25 @@ reserve_irq_vector (int vector) return test_and_set_bit(pos, ia64_vector_mask); } +/* + * Dynamic irq allocate and deallocation for MSI + */ +int create_irq(void) +{ + int vector = assign_irq_vector(AUTO_ASSIGN); + + if (vector >= 0) + dynamic_irq_init(vector); + + return vector; +} + +void destroy_irq(unsigned int irq) +{ + dynamic_irq_cleanup(irq); + free_irq_vector(irq); +} + #ifdef CONFIG_SMP # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) #else -- GitLab From 3fc471ede99579211c44b6a64829c4318976990f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:39 -0700 Subject: [PATCH 0543/1619] [PATCH] genirq: i386 irq: Dynamic irq support The current implementation of create_irq() is a hack but it is the current hack that msi.c uses, and unfortunately the ``generic'' apic msi ops depend on this hack. Thus we are stuck this hack of assuming irq == vector until the depencencies in the generic msi code are removed. 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 --- arch/i386/kernel/io_apic.c | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index b3b01894ca6..fca689cfb0c 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2483,6 +2483,54 @@ static int __init ioapic_init_sysfs(void) device_initcall(ioapic_init_sysfs); +#ifdef CONFIG_PCI_MSI +/* + * Dynamic irq allocate and deallocation for MSI + */ +int create_irq(void) +{ + /* Hack of the day: irq == vector. + * + * Ultimately this will be be more general, + * and not depend on the irq to vector identity mapping. + * But this version is needed until msi.c can cope with + * the more general form. + */ + int irq, vector; + unsigned long flags; + vector = assign_irq_vector(AUTO_ASSIGN); + irq = vector; + + if (vector >= 0) { + struct irq_desc *desc; + + spin_lock_irqsave(&vector_lock, flags); + vector_irq[vector] = irq; + irq_vector[irq] = vector; + spin_unlock_irqrestore(&vector_lock, flags); + + set_intr_gate(vector, interrupt[irq]); + + dynamic_irq_init(irq); + } + return irq; +} + +void destroy_irq(unsigned int irq) +{ + unsigned long flags; + unsigned int vector; + + dynamic_irq_cleanup(irq); + + spin_lock_irqsave(&vector_lock, flags); + vector = irq_vector[irq]; + vector_irq[vector] = -1; + irq_vector[irq] = 0; + spin_unlock_irqrestore(&vector_lock, flags); +} +#endif /* CONFIG_PCI_MSI */ + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ -- GitLab From c4fa0bbf384496ae4acc0a150719d9d8fa8d11b3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:40 -0700 Subject: [PATCH 0544/1619] [PATCH] genirq: x86_64 irq: Dynamic irq support The current implementation of create_irq() is a hack but it is the current hack that msi.c uses, and unfortunately the ``generic'' apic msi ops depend on this hack. Thus we are this hack of assuming irq == vector until the depencencies in the generic irq code are removed. 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 --- arch/x86_64/kernel/io_apic.c | 51 ++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 12dd938f5d5..fd52fcb6fa1 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1254,11 +1254,6 @@ static int ioapic_retrigger_vector(unsigned int vector) * races. */ -static void ack_apic(unsigned int irq) -{ - ack_APIC_irq(); -} - static void ack_apic_edge(unsigned int irq) { move_native_irq(irq); @@ -1698,6 +1693,52 @@ static int __init ioapic_init_sysfs(void) device_initcall(ioapic_init_sysfs); +#ifdef CONFIG_PCI_MSI +/* + * Dynamic irq allocate and deallocation for MSI + */ +int create_irq(void) +{ + /* Hack of the day: irq == vector. + * + * Ultimately this will be be more general, + * and not depend on the irq to vector identity mapping. + * But this version is needed until msi.c can cope with + * the more general form. + */ + int irq, vector; + unsigned long flags; + vector = assign_irq_vector(AUTO_ASSIGN); + irq = vector; + + if (vector >= 0) { + spin_lock_irqsave(&vector_lock, flags); + vector_irq[vector] = irq; + irq_vector[irq] = vector; + spin_unlock_irqrestore(&vector_lock, flags); + + set_intr_gate(vector, interrupt[irq]); + + dynamic_irq_init(irq); + } + return irq; +} + +void destroy_irq(unsigned int irq) +{ + unsigned long flags; + unsigned int vector; + + dynamic_irq_cleanup(irq); + + spin_lock_irqsave(&vector_lock, flags); + vector = irq_vector[irq]; + vector_irq[vector] = -1; + irq_vector[irq] = 0; + spin_unlock_irqrestore(&vector_lock, flags); +} +#endif + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ -- GitLab From 1ce03373a7f4b5fa8ca5be02ff35229800a6e12b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:41 -0700 Subject: [PATCH 0545/1619] [PATCH] genirq: msi: make the msi code irq based and not vector based The msi currently 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. For ia64 this is fine. For x86 and x86_64 this is complete nonsense and makes an enourmous mess of the irq handling code and prevents some pretty significant cleanups in the code for handling large numbers of irqs. This patch refactors msi.c to work in terms of irqs and create_irq/destroy_irq for dynamically managing irqs. Hopefully this is finally a version of msi.c that is useful on more than just x86 derivatives. 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 | 425 ++++++++++++++++++---------------------------- drivers/pci/msi.h | 7 +- 2 files changed, 168 insertions(+), 264 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a32e75a4417..da2c6c2b6b1 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -6,6 +6,7 @@ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) */ +#include #include #include #include @@ -27,12 +28,6 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; static int pci_msi_enable = 1; -static int last_alloc_vector; -static int nr_released_vectors; - -#ifndef CONFIG_X86_IO_APIC -int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; -#endif static struct msi_ops *msi_ops; @@ -53,11 +48,11 @@ static int msi_cache_init(void) return 0; } -static void msi_set_mask_bit(unsigned int vector, int flag) +static void msi_set_mask_bit(unsigned int irq, int flag) { struct msi_desc *entry; - entry = (struct msi_desc *)msi_desc[vector]; + entry = msi_desc[irq]; if (!entry || !entry->dev || !entry->mask_base) return; switch (entry->msi_attrib.type) { @@ -181,23 +176,23 @@ static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask) #define set_msi_affinity NULL #endif /* CONFIG_SMP */ -static void mask_MSI_irq(unsigned int vector) +static void mask_MSI_irq(unsigned int irq) { - msi_set_mask_bit(vector, 1); + msi_set_mask_bit(irq, 1); } -static void unmask_MSI_irq(unsigned int vector) +static void unmask_MSI_irq(unsigned int irq) { - msi_set_mask_bit(vector, 0); + msi_set_mask_bit(irq, 0); } -static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector) +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[vector]; + entry = msi_desc[irq]; if (!entry || !entry->dev) { spin_unlock_irqrestore(&msi_lock, flags); return 0; @@ -208,39 +203,39 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector) return 0; /* never anything pending */ } -static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) +static unsigned int startup_msi_irq_w_maskbit(unsigned int irq) { - startup_msi_irq_wo_maskbit(vector); - unmask_MSI_irq(vector); + startup_msi_irq_wo_maskbit(irq); + unmask_MSI_irq(irq); return 0; /* never anything pending */ } -static void shutdown_msi_irq(unsigned int vector) +static void shutdown_msi_irq(unsigned int irq) { struct msi_desc *entry; unsigned long flags; spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[vector]; + 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 vector) +static void end_msi_irq_wo_maskbit(unsigned int irq) { - move_native_irq(vector); + move_native_irq(irq); ack_APIC_irq(); } -static void end_msi_irq_w_maskbit(unsigned int vector) +static void end_msi_irq_w_maskbit(unsigned int irq) { - move_native_irq(vector); - unmask_MSI_irq(vector); + move_native_irq(irq); + unmask_MSI_irq(irq); ack_APIC_irq(); } -static void do_nothing(unsigned int vector) +static void do_nothing(unsigned int irq) { } @@ -291,86 +286,7 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { .set_affinity = set_msi_affinity }; -static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); -static int assign_msi_vector(void) -{ - static int new_vector_avail = 1; - int vector; - unsigned long flags; - - /* - * msi_lock is provided to ensure that successful allocation of MSI - * vector is assigned unique among drivers. - */ - spin_lock_irqsave(&msi_lock, flags); - - if (!new_vector_avail) { - int free_vector = 0; - - /* - * vector_irq[] = -1 indicates that this specific vector is: - * - assigned for MSI (since MSI have no associated IRQ) or - * - assigned for legacy if less than 16, or - * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping - * vector_irq[] = 0 indicates that this vector, previously - * assigned for MSI, is freed by hotplug removed operations. - * This vector will be reused for any subsequent hotplug added - * operations. - * vector_irq[] > 0 indicates that this vector is assigned for - * IOxAPIC IRQs. This vector and its value provides a 1-to-1 - * vector-to-IOxAPIC IRQ mapping. - */ - for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) { - if (vector_irq[vector] != 0) - continue; - free_vector = vector; - if (!msi_desc[vector]) - break; - else - continue; - } - if (!free_vector) { - spin_unlock_irqrestore(&msi_lock, flags); - return -EBUSY; - } - vector_irq[free_vector] = -1; - nr_released_vectors--; - spin_unlock_irqrestore(&msi_lock, flags); - if (msi_desc[free_vector] != NULL) { - struct pci_dev *dev; - int tail; - - /* free all linked vectors before re-assign */ - do { - spin_lock_irqsave(&msi_lock, flags); - dev = msi_desc[free_vector]->dev; - tail = msi_desc[free_vector]->link.tail; - spin_unlock_irqrestore(&msi_lock, flags); - msi_free_vector(dev, tail, 1); - } while (free_vector != tail); - } - - return free_vector; - } - vector = assign_irq_vector(AUTO_ASSIGN); - last_alloc_vector = vector; - if (vector == LAST_DEVICE_VECTOR) - new_vector_avail = 0; - - spin_unlock_irqrestore(&msi_lock, flags); - return vector; -} - -static int get_new_vector(void) -{ - int vector = assign_msi_vector(); - - if (vector > 0) - set_intr_gate(vector, interrupt[vector]); - - return vector; -} - +static int msi_free_irq(struct pci_dev* dev, int irq); static int msi_init(void) { static int status = -ENOMEM; @@ -394,13 +310,13 @@ static int msi_init(void) } if (! msi_ops) { + pci_msi_enable = 0; printk(KERN_WARNING "PCI: MSI ops not registered. MSI disabled.\n"); status = -EINVAL; return status; } - last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); status = msi_cache_init(); if (status < 0) { pci_msi_enable = 0; @@ -408,23 +324,9 @@ static int msi_init(void) return status; } - if (last_alloc_vector < 0) { - pci_msi_enable = 0; - printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); - status = -EBUSY; - return status; - } - vector_irq[last_alloc_vector] = 0; - nr_released_vectors++; - return status; } -static int get_msi_vector(struct pci_dev *dev) -{ - return get_new_vector(); -} - static struct msi_desc* alloc_msi_entry(void) { struct msi_desc *entry; @@ -439,29 +341,45 @@ static struct msi_desc* alloc_msi_entry(void) return entry; } -static void attach_msi_entry(struct msi_desc *entry, int vector) +static void attach_msi_entry(struct msi_desc *entry, int irq) { unsigned long flags; spin_lock_irqsave(&msi_lock, flags); - msi_desc[vector] = entry; + msi_desc[irq] = entry; spin_unlock_irqrestore(&msi_lock, flags); } -static void irq_handler_init(int cap_id, int pos, int mask) +static int create_msi_irq(struct hw_interrupt_type *handler) { - unsigned long flags; + struct msi_desc *entry; + int irq; + + entry = alloc_msi_entry(); + if (!entry) + return -ENOMEM; - spin_lock_irqsave(&irq_desc[pos].lock, flags); - if (cap_id == PCI_CAP_ID_MSIX) - irq_desc[pos].chip = &msix_irq_type; - else { - if (!mask) - irq_desc[pos].chip = &msi_irq_wo_maskbit_type; - else - irq_desc[pos].chip = &msi_irq_w_maskbit_type; + irq = create_irq(); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + return -EBUSY; } - spin_unlock_irqrestore(&irq_desc[pos].lock, flags); + + set_irq_chip(irq, handler); + set_irq_data(irq, entry); + + return irq; +} + +static void destroy_msi_irq(unsigned int irq) +{ + struct msi_desc *entry; + + entry = get_irq_data(irq); + set_irq_chip(irq, NULL); + set_irq_data(irq, NULL); + destroy_irq(irq); + kmem_cache_free(msi_cachep, entry); } static void enable_msi_mode(struct pci_dev *dev, int pos, int type) @@ -506,21 +424,21 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) } } -static int msi_lookup_vector(struct pci_dev *dev, int type) +static int msi_lookup_irq(struct pci_dev *dev, int type) { - int vector; + int irq; unsigned long flags; spin_lock_irqsave(&msi_lock, flags); - for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) { - if (!msi_desc[vector] || msi_desc[vector]->dev != dev || - msi_desc[vector]->msi_attrib.type != type || - msi_desc[vector]->msi_attrib.default_vector != dev->irq) + for (irq = 0; irq < NR_IRQS; irq++) { + if (!msi_desc[irq] || msi_desc[irq]->dev != dev || + msi_desc[irq]->msi_attrib.type != type || + msi_desc[irq]->msi_attrib.default_irq != dev->irq) continue; spin_unlock_irqrestore(&msi_lock, flags); - /* This pre-assigned MSI vector for this device - already exits. Override dev->irq with this vector */ - dev->irq = vector; + /* This pre-assigned MSI irq for this device + already exits. Override dev->irq with this irq */ + dev->irq = irq; return 0; } spin_unlock_irqrestore(&msi_lock, flags); @@ -605,7 +523,7 @@ int pci_save_msix_state(struct pci_dev *dev) { int pos; int temp; - int vector, head, tail = 0; + int irq, head, tail = 0; u16 control; struct pci_cap_saved_state *save_state; @@ -627,20 +545,20 @@ int pci_save_msix_state(struct pci_dev *dev) /* save the table */ temp = dev->irq; - if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { + if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { kfree(save_state); return -EINVAL; } - vector = head = dev->irq; + irq = head = dev->irq; while (head != tail) { struct msi_desc *entry; - entry = msi_desc[vector]; + entry = msi_desc[irq]; read_msi_msg(entry, &entry->msg_save); - tail = msi_desc[vector]->link.tail; - vector = tail; + tail = msi_desc[irq]->link.tail; + irq = tail; } dev->irq = temp; @@ -653,7 +571,7 @@ void pci_restore_msix_state(struct pci_dev *dev) { u16 save; int pos; - int vector, head, tail = 0; + int irq, head, tail = 0; struct msi_desc *entry; int temp; struct pci_cap_saved_state *save_state; @@ -671,15 +589,15 @@ void pci_restore_msix_state(struct pci_dev *dev) /* route the table */ temp = dev->irq; - if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) + if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) return; - vector = head = dev->irq; + irq = head = dev->irq; while (head != tail) { - entry = msi_desc[vector]; + entry = msi_desc[irq]; write_msi_msg(entry, &entry->msg_save); - tail = msi_desc[vector]->link.tail; - vector = tail; + tail = msi_desc[irq]->link.tail; + irq = tail; } dev->irq = temp; @@ -726,55 +644,54 @@ static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) * @dev: pointer to the pci_dev data structure of MSI device function * * Setup the MSI capability structure of device function with a single - * MSI vector, regardless of device function is capable of handling + * MSI irq, regardless of device function is capable of handling * multiple messages. A return of zero indicates the successful setup - * of an entry zero with the new MSI vector or non-zero for otherwise. + * of an entry zero with the new MSI irq or non-zero for otherwise. **/ static int msi_capability_init(struct pci_dev *dev) { int status; struct msi_desc *entry; - int pos, vector; + int pos, irq; u16 control; + struct hw_interrupt_type *handler; pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ - entry = alloc_msi_entry(); - if (!entry) - return -ENOMEM; + handler = &msi_irq_wo_maskbit_type; + if (is_mask_bit_support(control)) + handler = &msi_irq_w_maskbit_type; - vector = get_msi_vector(dev); - if (vector < 0) { - kmem_cache_free(msi_cachep, entry); - return -EBUSY; - } - entry->link.head = vector; - entry->link.tail = vector; + irq = create_msi_irq(handler); + if (irq < 0) + return irq; + + entry = get_irq_data(irq); + 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); - entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */ + entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.pos = pos; - dev->irq = vector; + 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)); } - /* Replace with MSI handler */ - irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); /* Configure MSI capability structure */ status = msi_register_init(dev, entry); if (status != 0) { - dev->irq = entry->msi_attrib.default_vector; - kmem_cache_free(msi_cachep, entry); + dev->irq = entry->msi_attrib.default_irq; + destroy_msi_irq(irq); return status; } - attach_msi_entry(entry, vector); + attach_msi_entry(entry, irq); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -788,8 +705,8 @@ static int msi_capability_init(struct pci_dev *dev) * @nvec: number of @entries * * Setup the MSI-X capability structure of device function with a - * single MSI-X vector. A return of zero indicates the successful setup of - * requested MSI-X entries with allocated vectors or non-zero for otherwise. + * single MSI-X irq. A return of zero indicates the successful setup of + * requested MSI-X entries with allocated irqs or non-zero for otherwise. **/ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) @@ -797,7 +714,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; struct msi_msg msg; int status; - int vector, pos, i, j, nr_entries, temp = 0; + int irq, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; u32 table_offset; u16 control; @@ -819,54 +736,50 @@ static int msix_capability_init(struct pci_dev *dev, /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { - entry = alloc_msi_entry(); - if (!entry) + irq = create_msi_irq(&msix_irq_type); + if (irq < 0) break; - vector = get_msi_vector(dev); - if (vector < 0) { - kmem_cache_free(msi_cachep, entry); - break; - } + entry = get_irq_data(irq); j = entries[i].entry; - entries[i].vector = vector; + 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; - entry->msi_attrib.default_vector = dev->irq; + entry->msi_attrib.default_irq = dev->irq; entry->msi_attrib.pos = pos; entry->dev = dev; entry->mask_base = base; if (!head) { - entry->link.head = vector; - entry->link.tail = vector; + entry->link.head = irq; + entry->link.tail = irq; head = entry; } else { entry->link.head = temp; entry->link.tail = tail->link.tail; - tail->link.tail = vector; - head->link.head = vector; + tail->link.tail = irq; + head->link.head = irq; } - temp = vector; + temp = irq; tail = entry; - /* 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); - if (status < 0) + status = msi_ops->setup(dev, irq, &msg); + if (status < 0) { + destroy_msi_irq(irq); break; + } write_msi_msg(entry, &msg); - attach_msi_entry(entry, vector); + attach_msi_entry(entry, irq); } if (i != nvec) { int avail = i - 1; i--; for (; i >= 0; i--) { - vector = (entries + i)->vector; - msi_free_vector(dev, vector, 0); + irq = (entries + i)->vector; + msi_free_irq(dev, irq); (entries + i)->vector = 0; } /* If we had some success report the number of irqs @@ -914,10 +827,10 @@ int pci_msi_supported(struct pci_dev * dev) * @dev: pointer to the pci_dev data structure of MSI device function * * Setup the MSI capability structure of device function with - * a single MSI vector upon its software driver call to request for + * a single MSI irq upon its software driver call to request for * MSI mode enabled on its hardware device function. A return of zero * indicates the successful setup of an entry zero with the new MSI - * vector or non-zero for otherwise. + * irq or non-zero for otherwise. **/ int pci_enable_msi(struct pci_dev* dev) { @@ -941,13 +854,13 @@ int pci_enable_msi(struct pci_dev* dev) if (!is_64bit_address(control) && msi_ops->needs_64bit_address) return -EINVAL; - WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI)); + WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); - /* Check whether driver already requested for MSI-X vectors */ + /* Check whether driver already requested for MSI-X irqs */ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { + if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { printk(KERN_INFO "PCI: %s: Can't enable MSI. " - "Device already has MSI-X vectors assigned\n", + "Device already has MSI-X irq assigned\n", pci_name(dev)); dev->irq = temp; return -EINVAL; @@ -959,7 +872,7 @@ int pci_enable_msi(struct pci_dev* dev) void pci_disable_msi(struct pci_dev* dev) { struct msi_desc *entry; - int pos, default_vector; + int pos, default_irq; u16 control; unsigned long flags; @@ -987,30 +900,30 @@ void pci_disable_msi(struct pci_dev* dev) if (entry->msi_attrib.state) { spin_unlock_irqrestore(&msi_lock, flags); printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " - "free_irq() on MSI vector %d\n", + "free_irq() on MSI irq %d\n", pci_name(dev), dev->irq); BUG_ON(entry->msi_attrib.state > 0); } else { - default_vector = entry->msi_attrib.default_vector; + default_irq = entry->msi_attrib.default_irq; spin_unlock_irqrestore(&msi_lock, flags); - msi_free_vector(dev, dev->irq, 0); + msi_free_irq(dev, dev->irq); - /* Restore dev->irq to its default pin-assertion vector */ - dev->irq = default_vector; + /* Restore dev->irq to its default pin-assertion irq */ + dev->irq = default_irq; } } -static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) +static int msi_free_irq(struct pci_dev* dev, int irq) { struct msi_desc *entry; int head, entry_nr, type; void __iomem *base; unsigned long flags; - msi_ops->teardown(vector); + msi_ops->teardown(irq); spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[vector]; + entry = msi_desc[irq]; if (!entry || entry->dev != dev) { spin_unlock_irqrestore(&msi_lock, flags); return -EINVAL; @@ -1022,22 +935,16 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) msi_desc[entry->link.head]->link.tail = entry->link.tail; msi_desc[entry->link.tail]->link.head = entry->link.head; entry->dev = NULL; - if (!reassign) { - vector_irq[vector] = 0; - nr_released_vectors++; - } - msi_desc[vector] = NULL; + msi_desc[irq] = NULL; spin_unlock_irqrestore(&msi_lock, flags); - kmem_cache_free(msi_cachep, entry); + destroy_msi_irq(irq); if (type == PCI_CAP_ID_MSIX) { - if (!reassign) - writel(1, base + - entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - if (head == vector) + if (head == irq) iounmap(base); } @@ -1048,15 +955,15 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function * @entries: pointer to an array of MSI-X entries - * @nvec: number of MSI-X vectors requested for allocation by device driver + * @nvec: number of MSI-X irqs requested for allocation by device driver * * Setup the MSI-X capability structure of device function with the number - * of requested vectors upon its software driver call to request for + * of requested irqs upon its software driver call to request for * MSI-X mode enabled on its hardware device function. A return of zero * indicates the successful configuration of MSI-X capability structure - * with new allocated MSI-X vectors. A return of < 0 indicates a failure. + * with new allocated MSI-X irqs. A return of < 0 indicates a failure. * Or a return of > 0 indicates that driver request is exceeding the number - * of vectors available. Driver should use the returned value to re-send + * of irqs available. Driver should use the returned value to re-send * its request. **/ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) @@ -1091,13 +998,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) } } temp = dev->irq; - WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)); + WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)); - /* Check whether driver already requested for MSI vector */ + /* Check whether driver already requested for MSI irq */ if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && - !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { + !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " - "Device already has an MSI vector assigned\n", + "Device already has an MSI irq assigned\n", pci_name(dev)); dev->irq = temp; return -EINVAL; @@ -1127,27 +1034,27 @@ void pci_disable_msix(struct pci_dev* dev) disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); temp = dev->irq; - if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { - int state, vector, head, tail = 0, warning = 0; + if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { + int state, irq, head, tail = 0, warning = 0; unsigned long flags; - vector = head = dev->irq; + irq = head = dev->irq; dev->irq = temp; /* Restore pin IRQ */ while (head != tail) { spin_lock_irqsave(&msi_lock, flags); - state = msi_desc[vector]->msi_attrib.state; - tail = msi_desc[vector]->link.tail; + state = msi_desc[irq]->msi_attrib.state; + tail = msi_desc[irq]->link.tail; spin_unlock_irqrestore(&msi_lock, flags); if (state) warning = 1; - else if (vector != head) /* Release MSI-X vector */ - msi_free_vector(dev, vector, 0); - vector = tail; + else if (irq != head) /* Release MSI-X irq */ + msi_free_irq(dev, irq); + irq = tail; } - msi_free_vector(dev, vector, 0); + msi_free_irq(dev, irq); if (warning) { printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " - "free_irq() on all MSI-X vectors\n", + "free_irq() on all MSI-X irqs\n", pci_name(dev)); BUG_ON(warning > 0); } @@ -1155,11 +1062,11 @@ void pci_disable_msix(struct pci_dev* dev) } /** - * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state + * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state * @dev: pointer to the pci_dev data structure of MSI(X) device function * * Being called during hotplug remove, from which the device function - * is hot-removed. All previous assigned MSI/MSI-X vectors, if + * is hot-removed. All previous assigned MSI/MSI-X irqs, if * allocated for this device function, are reclaimed to unused state, * which may be used later on. **/ @@ -1173,42 +1080,42 @@ 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_vector(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) { printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " - "called without free_irq() on MSI vector %d\n", + "called without free_irq() on MSI irq %d\n", pci_name(dev), dev->irq); BUG_ON(state > 0); - } else /* Release MSI vector assigned to this device */ - msi_free_vector(dev, dev->irq, 0); + } else /* Release MSI irq assigned to this device */ + msi_free_irq(dev, dev->irq); dev->irq = temp; /* Restore IOAPIC IRQ */ } pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { - int vector, head, tail = 0, warning = 0; + if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { + int irq, head, tail = 0, warning = 0; void __iomem *base = NULL; - vector = head = dev->irq; + irq = head = dev->irq; while (head != tail) { spin_lock_irqsave(&msi_lock, flags); - state = msi_desc[vector]->msi_attrib.state; - tail = msi_desc[vector]->link.tail; - base = msi_desc[vector]->mask_base; + 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) warning = 1; - else if (vector != head) /* Release MSI-X vector */ - msi_free_vector(dev, vector, 0); - vector = tail; + else if (irq != head) /* Release MSI-X irq */ + msi_free_irq(dev, irq); + irq = tail; } - msi_free_vector(dev, vector, 0); + msi_free_irq(dev, irq); if (warning) { iounmap(base); printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " - "called without free_irq() on all MSI-X vectors\n", + "called without free_irq() on all MSI-X irqs\n", pci_name(dev)); BUG_ON(warning > 0); } diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 6793241f388..435d05aae4b 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -8,9 +8,6 @@ #include -extern int vector_irq[NR_VECTORS]; -extern void (*interrupt[NR_IRQS])(void); - /* * MSI-X Address Register */ @@ -58,9 +55,9 @@ struct msi_desc { __u8 maskbit : 1; /* mask-pending bit supported ? */ __u8 state : 1; /* {0: free, 1: busy} */ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ - __u8 entry_nr; /* specific enabled entry */ - __u8 default_vector; /* default pre-assigned vector */ __u8 pos; /* Location of the msi capability */ + __u16 entry_nr; /* specific enabled entry */ + unsigned default_irq; /* default pre-assigned irq */ }msi_attrib; struct { -- GitLab From 589e367f9b9117b3412da0d4e10ea6882db8da84 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:42 -0700 Subject: [PATCH 0546/1619] [PATCH] genirq: x86_64 irq: Move msi message composition into io_apic.c This removes the hardcoded assumption that irq == vector in the msi composition code, and it allows the msi message composition to setup logical mode, or lowest priorirty delivery mode as we do for other apic interrupts, and with the same selection criteria. Basically this moves the problem of what is in the msi message into the architecture irq management code where it belongs. Not in a generic layer that doesn't have enough information to compose msi messages properly. 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 --- arch/x86_64/kernel/io_apic.c | 74 ++++++++++++++++++++++++++++++++++++ include/asm-x86_64/msi.h | 7 +--- include/asm-x86_64/msidef.h | 47 +++++++++++++++++++++++ 3 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 include/asm-x86_64/msidef.h diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index fd52fcb6fa1..437b6f96cc8 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #define __apicdebuginit __init @@ -1739,6 +1741,78 @@ void destroy_irq(unsigned int irq) } #endif +/* + * MSI mesage composition + */ +#ifdef CONFIG_PCI_MSI +static int msi_msg_setup(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; + + vector = assign_irq_vector(irq); + if (vector >= 0) { + cpumask_t tmp; + + cpus_clear(tmp); + cpu_set(first_cpu(cpu_online_map), tmp); + dest = cpu_mask_to_apicid(tmp); + + msg->address_hi = MSI_ADDR_BASE_HI; + msg->address_lo = + MSI_ADDR_BASE_LO | + ((INT_DEST_MODE == 0) ? + MSI_ADDR_DEST_MODE_PHYSICAL: + MSI_ADDR_DEST_MODE_LOGICAL) | + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + MSI_ADDR_REDIRECTION_CPU: + MSI_ADDR_REDIRECTION_LOWPRI) | + MSI_ADDR_DEST_ID(dest); + + msg->data = + MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + MSI_DATA_DELIVERY_FIXED: + MSI_DATA_DELIVERY_LOWPRI) | + MSI_DATA_VECTOR(vector); + } + 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) +{ + int vector; + unsigned dest; + + vector = assign_irq_vector(irq); + if (vector > 0) { + dest = cpu_mask_to_apicid(mask); + + 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); + } +} + +struct msi_ops arch_msi_ops = { + .needs_64bit_address = 0, + .setup = msi_msg_setup, + .teardown = msi_msg_teardown, + .target = msi_msg_set_affinity, +}; + +#endif + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h index 3ad2346624b..1876fda52ae 100644 --- a/include/asm-x86_64/msi.h +++ b/include/asm-x86_64/msi.h @@ -10,14 +10,11 @@ #include #include -#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) -#define MSI_TARGET_CPU_SHIFT 12 - -extern struct msi_ops msi_apic_ops; +extern struct msi_ops arch_msi_ops; static inline int msi_arch_init(void) { - msi_register(&msi_apic_ops); + msi_register(&arch_msi_ops); return 0; } diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h new file mode 100644 index 00000000000..5b8acddb70f --- /dev/null +++ b/include/asm-x86_64/msidef.h @@ -0,0 +1,47 @@ +#ifndef ASM_MSIDEF_H +#define ASM_MSIDEF_H + +/* + * Constants for Intel APIC based MSI messages. + */ + +/* + * Shifts for MSI data + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR_MASK 0x000000ff +#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK) + +#define MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT) +#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT) + +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) +#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) + +#define MSI_DATA_TRIGGER_SHIFT 15 +#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) + +/* + * Shift/mask fields for msi address + */ + +#define MSI_ADDR_BASE_HI 0 +#define MSI_ADDR_BASE_LO 0xfee00000 + +#define MSI_ADDR_DEST_MODE_SHIFT 2 +#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT) +#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT) + +#define MSI_ADDR_REDIRECTION_SHIFT 3 +#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */ +#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */ + +#define MSI_ADDR_DEST_ID_SHIFT 12 +#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 +#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK) + +#endif /* ASM_MSIDEF_H */ -- GitLab From 2d3fcc1c54df2f49674e1f7c99d4800ed1d51902 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:43 -0700 Subject: [PATCH 0547/1619] [PATCH] genirq: i386 irq: Move msi message composition into io_apic.c This removes the hardcoded assumption that irq == vector in the msi composition code, and it allows the msi message composition to setup logical mode, or lowest priorirty delivery mode as we do for other apic interrupts, and with the same selection criteria. Basically this moves the problem of what is in the msi message into the architecture irq management code where it belongs. Not in a generic layer that doesn't have enough information to compose msi messages properly. 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 --- arch/i386/kernel/io_apic.c | 70 ++++++++++++++++++++++++++++++++++++++ include/asm-i386/msi.h | 7 ++-- include/asm-i386/msidef.h | 47 +++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 include/asm-i386/msidef.h diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index fca689cfb0c..85e7d5d465a 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -2531,6 +2533,74 @@ void destroy_irq(unsigned int irq) } #endif /* CONFIG_PCI_MSI */ +/* + * MSI mesage composition + */ +#ifdef CONFIG_PCI_MSI +static int msi_msg_setup(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; + + vector = assign_irq_vector(irq); + if (vector >= 0) { + dest = cpu_mask_to_apicid(TARGET_CPUS); + + msg->address_hi = MSI_ADDR_BASE_HI; + msg->address_lo = + MSI_ADDR_BASE_LO | + ((INT_DEST_MODE == 0) ? + MSI_ADDR_DEST_MODE_PHYSICAL: + MSI_ADDR_DEST_MODE_LOGICAL) | + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + MSI_ADDR_REDIRECTION_CPU: + MSI_ADDR_REDIRECTION_LOWPRI) | + MSI_ADDR_DEST_ID(dest); + + msg->data = + MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + MSI_DATA_DELIVERY_FIXED: + MSI_DATA_DELIVERY_LOWPRI) | + MSI_DATA_VECTOR(vector); + } + 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) +{ + int vector; + unsigned dest; + + vector = assign_irq_vector(irq); + if (vector > 0) { + dest = cpu_mask_to_apicid(mask); + + 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); + } +} + +struct msi_ops arch_msi_ops = { + .needs_64bit_address = 0, + .setup = msi_msg_setup, + .teardown = msi_msg_teardown, + .target = msi_msg_set_affinity, +}; + +#endif /* CONFIG_PCI_MSI */ + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h index b11c4b7dfae..7368a89a0f4 100644 --- a/include/asm-i386/msi.h +++ b/include/asm-i386/msi.h @@ -9,14 +9,11 @@ #include #include -#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) -#define MSI_TARGET_CPU_SHIFT 12 - -extern struct msi_ops msi_apic_ops; +extern struct msi_ops arch_msi_ops; static inline int msi_arch_init(void) { - msi_register(&msi_apic_ops); + msi_register(&arch_msi_ops); return 0; } diff --git a/include/asm-i386/msidef.h b/include/asm-i386/msidef.h new file mode 100644 index 00000000000..5b8acddb70f --- /dev/null +++ b/include/asm-i386/msidef.h @@ -0,0 +1,47 @@ +#ifndef ASM_MSIDEF_H +#define ASM_MSIDEF_H + +/* + * Constants for Intel APIC based MSI messages. + */ + +/* + * Shifts for MSI data + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR_MASK 0x000000ff +#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK) + +#define MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT) +#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT) + +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) +#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) + +#define MSI_DATA_TRIGGER_SHIFT 15 +#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) + +/* + * Shift/mask fields for msi address + */ + +#define MSI_ADDR_BASE_HI 0 +#define MSI_ADDR_BASE_LO 0xfee00000 + +#define MSI_ADDR_DEST_MODE_SHIFT 2 +#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT) +#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT) + +#define MSI_ADDR_REDIRECTION_SHIFT 3 +#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */ +#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */ + +#define MSI_ADDR_DEST_ID_SHIFT 12 +#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 +#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK) + +#endif /* ASM_MSIDEF_H */ -- GitLab From 4b2fabb9ec9b3b1cf5cf848a678058fb20c4d552 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:45 -0700 Subject: [PATCH 0548/1619] [PATCH] genirq: msi: only build msi-apic.c on ia64 After the previous changes ia64 is the only architecture useing msi-apic.c [akpm@osdl.org: unbreak MSI on ia64] 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/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index f2d152b818f..983d0f86aa3 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -27,7 +27,8 @@ obj-$(CONFIG_PPC64) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o -msiobj-y := msi.o msi-apic.o +msiobj-y := msi.o +msiobj-$(CONFIG_IA64) += msi-apic.o msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o obj-$(CONFIG_PCI_MSI) += $(msiobj-y) -- GitLab From 04b9267b15206fc902a18de1f78de6c82ca47716 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:46 -0700 Subject: [PATCH 0549/1619] [PATCH] genirq: x86_64 irq: Remove the msi assumption that irq == vector This patch removes the change in behavior of the irq allocation code when CONFIG_PCI_MSI is defined. Removing all instances of the assumption that irq == vector. create_irq is rewritten to first allocate a free irq and then to assign that irq a vector. assign_irq_vector is made static and the AUTO_ASSIGN case which allocates an vector not bound to an irq is removed. The ioapic vector methods are removed, and everything now works with irqs. The definition of NR_IRQS no longer depends on CONFIG_PCI_MSI 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 --- arch/x86_64/kernel/io_apic.c | 147 +++++++++++------------------------ include/asm-x86_64/hw_irq.h | 1 - include/asm-x86_64/io_apic.h | 40 ---------- include/asm-x86_64/irq.h | 5 -- 4 files changed, 47 insertions(+), 146 deletions(-) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 437b6f96cc8..bb16f3790f0 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -44,6 +44,8 @@ #include #include +static int assign_irq_vector(int irq); + #define __apicdebuginit __init int sis_apic_bug; /* not actually supported, dummy for compile */ @@ -83,14 +85,6 @@ static struct irq_pin_list { short apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; -int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; -#ifdef CONFIG_PCI_MSI -#define vector_to_irq(vector) \ - (platform_legacy_irq(vector) ? vector : vector_irq[vector]) -#else -#define vector_to_irq(vector) (vector) -#endif - #define __DO_ACTION(R, ACTION, FINAL) \ \ { \ @@ -162,7 +156,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) spin_lock_irqsave(&ioapic_lock, flags); __DO_ACTION(1, = dest, ) - set_irq_info(irq, mask); + set_native_irq_info(irq, mask); spin_unlock_irqrestore(&ioapic_lock, flags); } #endif @@ -599,18 +593,14 @@ static inline int IO_APIC_irq_trigger(int irq) /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; -int assign_irq_vector(int irq) +static int __assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - unsigned long flags; int vector; - BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); - - spin_lock_irqsave(&vector_lock, flags); + BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); - if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { - spin_unlock_irqrestore(&vector_lock, flags); + if (IO_APIC_VECTOR(irq) > 0) { return IO_APIC_VECTOR(irq); } next: @@ -625,10 +615,18 @@ next: } vector = current_vector; - vector_irq[vector] = irq; - if (irq != AUTO_ASSIGN) - IO_APIC_VECTOR(irq) = vector; + IO_APIC_VECTOR(irq) = vector; + + return vector; +} + +static int assign_irq_vector(int irq) +{ + int vector; + unsigned long flags; + spin_lock_irqsave(&vector_lock, flags); + vector = __assign_irq_vector(irq); spin_unlock_irqrestore(&vector_lock, flags); return vector; @@ -644,18 +642,14 @@ static struct irq_chip ioapic_chip; static void ioapic_register_intr(int irq, int vector, unsigned long trigger) { - unsigned idx; - - idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; - if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || trigger == IOAPIC_LEVEL) - set_irq_chip_and_handler(idx, &ioapic_chip, + set_irq_chip_and_handler(irq, &ioapic_chip, handle_fasteoi_irq); else - set_irq_chip_and_handler(idx, &ioapic_chip, + set_irq_chip_and_handler(irq, &ioapic_chip, handle_edge_irq); - set_intr_gate(vector, interrupt[idx]); + set_intr_gate(vector, interrupt[irq]); } static void __init setup_IO_APIC_irqs(void) @@ -872,17 +866,12 @@ void __apicdebuginit print_IO_APIC(void) ); } } - if (use_pci_vector()) - printk(KERN_INFO "Using vector-based indexing\n"); printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; if (entry->pin < 0) continue; - if (use_pci_vector() && !platform_legacy_irq(i)) - printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); - else - printk(KERN_DEBUG "IRQ%d ", i); + printk(KERN_DEBUG "IRQ%d ", i); for (;;) { printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) @@ -1206,42 +1195,8 @@ static unsigned int startup_ioapic_irq(unsigned int irq) return was_pending; } -static unsigned int startup_ioapic_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - - return startup_ioapic_irq(irq); -} - -static void mask_ioapic_vector (unsigned int vector) -{ - int irq = vector_to_irq(vector); - - mask_IO_APIC_irq(irq); -} - -static void unmask_ioapic_vector (unsigned int vector) -{ - int irq = vector_to_irq(vector); - - unmask_IO_APIC_irq(irq); -} - -#ifdef CONFIG_SMP -static void set_ioapic_affinity_vector (unsigned int vector, - cpumask_t cpu_mask) -{ - int irq = vector_to_irq(vector); - - set_native_irq_info(vector, cpu_mask); - set_ioapic_affinity_irq(irq, cpu_mask); -} -#endif // CONFIG_SMP - -static int ioapic_retrigger_vector(unsigned int vector) +static int ioapic_retrigger_irq(unsigned int irq) { - int irq = vector_to_irq(vector); - send_IPI_self(IO_APIC_VECTOR(irq)); return 1; @@ -1288,15 +1243,15 @@ static void ack_apic_level(unsigned int irq) static struct irq_chip ioapic_chip __read_mostly = { .name = "IO-APIC", - .startup = startup_ioapic_vector, - .mask = mask_ioapic_vector, - .unmask = unmask_ioapic_vector, + .startup = startup_ioapic_irq, + .mask = mask_IO_APIC_irq, + .unmask = unmask_IO_APIC_irq, .ack = ack_apic_edge, .eoi = ack_apic_level, #ifdef CONFIG_SMP - .set_affinity = set_ioapic_affinity_vector, + .set_affinity = set_ioapic_affinity_irq, #endif - .retrigger = ioapic_retrigger_vector, + .retrigger = ioapic_retrigger_irq, }; static inline void init_IO_APIC_traps(void) @@ -1316,11 +1271,6 @@ static inline void init_IO_APIC_traps(void) */ for (irq = 0; irq < NR_IRQS ; irq++) { int tmp = irq; - if (use_pci_vector()) { - if (!platform_legacy_irq(tmp)) - if ((tmp = vector_to_irq(tmp)) == -1) - continue; - } if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { /* * Hmm.. We don't have an entry for this, @@ -1695,32 +1645,33 @@ 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) { - /* Hack of the day: irq == vector. - * - * Ultimately this will be be more general, - * and not depend on the irq to vector identity mapping. - * But this version is needed until msi.c can cope with - * the more general form. - */ - int irq, vector; + /* Allocate an unused irq */ + int irq; + int new; + int vector = 0; unsigned long flags; - vector = assign_irq_vector(AUTO_ASSIGN); - irq = vector; - if (vector >= 0) { - spin_lock_irqsave(&vector_lock, flags); - vector_irq[vector] = irq; - irq_vector[irq] = vector; - spin_unlock_irqrestore(&vector_lock, flags); + irq = -ENOSPC; + spin_lock_irqsave(&vector_lock, flags); + for (new = (NR_IRQS - 1); new >= 0; new--) { + if (platform_legacy_irq(new)) + continue; + if (irq_vector[new] != 0) + continue; + vector = __assign_irq_vector(new); + if (likely(vector > 0)) + irq = new; + break; + } + spin_unlock_irqrestore(&vector_lock, flags); + if (irq >= 0) { set_intr_gate(vector, interrupt[irq]); - dynamic_irq_init(irq); } return irq; @@ -1729,17 +1680,13 @@ int create_irq(void) void destroy_irq(unsigned int irq) { unsigned long flags; - unsigned int vector; dynamic_irq_cleanup(irq); spin_lock_irqsave(&vector_lock, flags); - vector = irq_vector[irq]; - vector_irq[vector] = -1; irq_vector[irq] = 0; spin_unlock_irqrestore(&vector_lock, flags); } -#endif /* * MSI mesage composition @@ -1882,7 +1829,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p ioapic_write_entry(ioapic, pin, entry); spin_lock_irqsave(&ioapic_lock, flags); - set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); + set_native_irq_info(irq, TARGET_CPUS); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index f5da94af9c4..1a8dc185a79 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -75,7 +75,6 @@ #ifndef __ASSEMBLY__ extern u8 irq_vector[NR_IRQ_VECTORS]; #define IO_APIC_VECTOR(irq) (irq_vector[irq]) -#define AUTO_ASSIGN -1 /* * Various low-level irq details needed by irq.c, process.c, diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index 5d1b5c68e36..df579ac29a1 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -10,45 +10,7 @@ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar */ -#ifdef CONFIG_PCI_MSI -static inline int use_pci_vector(void) {return 1;} -static inline void disable_edge_ioapic_vector(unsigned int vector) { } -static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } -static inline void end_edge_ioapic_vector (unsigned int vector) { } -#define startup_level_ioapic startup_level_ioapic_vector -#define shutdown_level_ioapic mask_IO_APIC_vector -#define enable_level_ioapic unmask_IO_APIC_vector -#define disable_level_ioapic mask_IO_APIC_vector -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector -#define end_level_ioapic end_level_ioapic_vector -#define set_ioapic_affinity set_ioapic_affinity_vector - -#define startup_edge_ioapic startup_edge_ioapic_vector -#define shutdown_edge_ioapic disable_edge_ioapic_vector -#define enable_edge_ioapic unmask_IO_APIC_vector -#define disable_edge_ioapic disable_edge_ioapic_vector -#define ack_edge_ioapic ack_edge_ioapic_vector -#define end_edge_ioapic end_edge_ioapic_vector -#else static inline int use_pci_vector(void) {return 0;} -static inline void disable_edge_ioapic_irq(unsigned int irq) { } -static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } -static inline void end_edge_ioapic_irq (unsigned int irq) { } -#define startup_level_ioapic startup_level_ioapic_irq -#define shutdown_level_ioapic mask_IO_APIC_irq -#define enable_level_ioapic unmask_IO_APIC_irq -#define disable_level_ioapic mask_IO_APIC_irq -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq -#define end_level_ioapic end_level_ioapic_irq -#define set_ioapic_affinity set_ioapic_affinity_irq - -#define startup_edge_ioapic startup_edge_ioapic_irq -#define shutdown_edge_ioapic disable_edge_ioapic_irq -#define enable_edge_ioapic unmask_IO_APIC_irq -#define disable_edge_ioapic disable_edge_ioapic_irq -#define ack_edge_ioapic ack_edge_ioapic_irq -#define end_edge_ioapic end_edge_ioapic_irq -#endif #define APIC_MISMATCH_DEBUG @@ -207,8 +169,6 @@ extern int timer_uses_ioapic_pin_0; extern int sis_apic_bug; /* dummy */ -extern int assign_irq_vector(int irq); - void enable_NMI_through_LVT0 (void * dummy); extern spinlock_t i8259A_lock; diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h index 43469d8ab71..b8f87287847 100644 --- a/include/asm-x86_64/irq.h +++ b/include/asm-x86_64/irq.h @@ -31,13 +31,8 @@ #define FIRST_SYSTEM_VECTOR 0xef /* duplicated in hw_irq.h */ -#ifdef CONFIG_PCI_MSI -#define NR_IRQS FIRST_SYSTEM_VECTOR -#define NR_IRQ_VECTORS NR_IRQS -#else #define NR_IRQS 224 #define NR_IRQ_VECTORS (32 * NR_CPUS) -#endif static __inline__ int irq_canonicalize(int irq) { -- GitLab From ace80ab796ae30d2c9ee8a84ab6f608a61f8b87b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:47 -0700 Subject: [PATCH 0550/1619] [PATCH] genirq: i386 irq: Remove the msi assumption that irq == vector This patch removes the change in behavior of the irq allocation code when CONFIG_PCI_MSI is defined. Removing all instances of the assumption that irq == vector. create_irq is rewritten to first allocate a free irq and then to assign that irq a vector. assign_irq_vector is made static and the AUTO_ASSIGN case which allocates an vector not bound to an irq is removed. The ioapic vector methods are removed, and everything now works with irqs. The definition of NR_IRQS no longer depends on CONFIG_PCI_MSI [akpm@osdl.org: cleanup] 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 --- arch/i386/kernel/acpi/boot.c | 7 +- arch/i386/kernel/io_apic.c | 181 +++++------------- arch/i386/pci/irq.c | 4 - include/asm-i386/hw_irq.h | 1 - include/asm-i386/io_apic.h | 42 ---- .../mach-default/irq_vectors_limits.h | 5 - include/asm-x86_64/io_apic.h | 2 - 7 files changed, 50 insertions(+), 192 deletions(-) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 1aaea6ab8c4..256fb532321 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -468,12 +468,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { -#ifdef CONFIG_X86_IO_APIC - if (use_pci_vector() && !platform_legacy_irq(gsi)) - *irq = IO_APIC_VECTOR(gsi); - else -#endif - *irq = gsi_irq_sharing(gsi); + *irq = gsi_irq_sharing(gsi); return 0; } diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 85e7d5d465a..03e7606be6e 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -88,15 +88,6 @@ static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; -int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; -#ifdef CONFIG_PCI_MSI -#define vector_to_irq(vector) \ - (platform_legacy_irq(vector) ? vector : vector_irq[vector]) -#else -#define vector_to_irq(vector) (vector) -#endif - - union entry_union { struct { u32 w1, w2; }; struct IO_APIC_route_entry entry; @@ -282,7 +273,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) break; entry = irq_2_pin + entry->next; } - set_irq_info(irq, cpumask); + set_native_irq_info(irq, cpumask); spin_unlock_irqrestore(&ioapic_lock, flags); } @@ -1183,44 +1174,44 @@ static inline int IO_APIC_irq_trigger(int irq) /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; -int assign_irq_vector(int irq) +static int __assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - unsigned long flags; int vector; - BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); - - spin_lock_irqsave(&vector_lock, flags); + BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); - if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { - spin_unlock_irqrestore(&vector_lock, flags); + if (IO_APIC_VECTOR(irq) > 0) return IO_APIC_VECTOR(irq); - } -next: + current_vector += 8; if (current_vector == SYSCALL_VECTOR) - goto next; + current_vector += 8; if (current_vector >= FIRST_SYSTEM_VECTOR) { offset++; - if (!(offset%8)) { - spin_unlock_irqrestore(&vector_lock, flags); + if (!(offset % 8)) return -ENOSPC; - } current_vector = FIRST_DEVICE_VECTOR + offset; } vector = current_vector; - vector_irq[vector] = irq; - if (irq != AUTO_ASSIGN) - IO_APIC_VECTOR(irq) = vector; + IO_APIC_VECTOR(irq) = vector; + + return vector; +} +static int assign_irq_vector(int irq) +{ + unsigned long flags; + int vector; + + spin_lock_irqsave(&vector_lock, flags); + vector = __assign_irq_vector(irq); spin_unlock_irqrestore(&vector_lock, flags); return vector; } - static struct irq_chip ioapic_chip; #define IOAPIC_AUTO -1 @@ -1229,18 +1220,14 @@ static struct irq_chip ioapic_chip; static void ioapic_register_intr(int irq, int vector, unsigned long trigger) { - unsigned idx; - - idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; - if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || trigger == IOAPIC_LEVEL) - set_irq_chip_and_handler(idx, &ioapic_chip, + set_irq_chip_and_handler(irq, &ioapic_chip, handle_fasteoi_irq); else - set_irq_chip_and_handler(idx, &ioapic_chip, + set_irq_chip_and_handler(irq, &ioapic_chip, handle_edge_irq); - set_intr_gate(vector, interrupt[idx]); + set_intr_gate(vector, interrupt[irq]); } static void __init setup_IO_APIC_irqs(void) @@ -1485,17 +1472,12 @@ void __init print_IO_APIC(void) ); } } - if (use_pci_vector()) - printk(KERN_INFO "Using vector-based indexing\n"); printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; if (entry->pin < 0) continue; - if (use_pci_vector() && !platform_legacy_irq(i)) - printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); - else - printk(KERN_DEBUG "IRQ%d ", i); + printk(KERN_DEBUG "IRQ%d ", i); for (;;) { printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) @@ -1953,7 +1935,7 @@ static unsigned int startup_ioapic_irq(unsigned int irq) static void ack_ioapic_irq(unsigned int irq) { - move_irq(irq); + move_native_irq(irq); ack_APIC_irq(); } @@ -1962,7 +1944,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq) unsigned long v; int i; - move_irq(irq); + move_native_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1997,63 +1979,8 @@ static void ack_ioapic_quirk_irq(unsigned int irq) } } -static unsigned int startup_ioapic_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - - return startup_ioapic_irq(irq); -} - -static void ack_ioapic_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - - move_native_irq(vector); - ack_ioapic_irq(irq); -} - -static void ack_ioapic_quirk_vector(unsigned int vector) +static int ioapic_retrigger_irq(unsigned int irq) { - int irq = vector_to_irq(vector); - - move_native_irq(vector); - ack_ioapic_quirk_irq(irq); -} - -static void mask_IO_APIC_vector (unsigned int vector) -{ - int irq = vector_to_irq(vector); - - mask_IO_APIC_irq(irq); -} - -static void unmask_IO_APIC_vector (unsigned int vector) -{ - int irq = vector_to_irq(vector); - - unmask_IO_APIC_irq(irq); -} - -/* - * Oh just glorious. If CONFIG_PCI_MSI we've done - * #define set_ioapic_affinity set_ioapic_affinity_vector - */ -#if defined (CONFIG_SMP) && defined(CONFIG_X86_IO_APIC) && \ - defined(CONFIG_PCI_MSI) -static void set_ioapic_affinity_vector (unsigned int vector, - cpumask_t cpu_mask) -{ - int irq = vector_to_irq(vector); - - set_native_irq_info(vector, cpu_mask); - set_ioapic_affinity_irq(irq, cpu_mask); -} -#endif - -static int ioapic_retrigger_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - send_IPI_self(IO_APIC_VECTOR(irq)); return 1; @@ -2061,15 +1988,15 @@ static int ioapic_retrigger_vector(unsigned int vector) static struct irq_chip ioapic_chip __read_mostly = { .name = "IO-APIC", - .startup = startup_ioapic_vector, - .mask = mask_IO_APIC_vector, - .unmask = unmask_IO_APIC_vector, - .ack = ack_ioapic_vector, - .eoi = ack_ioapic_quirk_vector, + .startup = startup_ioapic_irq, + .mask = mask_IO_APIC_irq, + .unmask = unmask_IO_APIC_irq, + .ack = ack_ioapic_irq, + .eoi = ack_ioapic_quirk_irq, #ifdef CONFIG_SMP - .set_affinity = set_ioapic_affinity, + .set_affinity = set_ioapic_affinity_irq, #endif - .retrigger = ioapic_retrigger_vector, + .retrigger = ioapic_retrigger_irq, }; @@ -2090,11 +2017,6 @@ static inline void init_IO_APIC_traps(void) */ for (irq = 0; irq < NR_IRQS ; irq++) { int tmp = irq; - if (use_pci_vector()) { - if (!platform_legacy_irq(tmp)) - if ((tmp = vector_to_irq(tmp)) == -1) - continue; - } if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { /* * Hmm.. We don't have an entry for this, @@ -2491,28 +2413,26 @@ device_initcall(ioapic_init_sysfs); */ int create_irq(void) { - /* Hack of the day: irq == vector. - * - * Ultimately this will be be more general, - * and not depend on the irq to vector identity mapping. - * But this version is needed until msi.c can cope with - * the more general form. - */ - int irq, vector; + /* Allocate an unused irq */ + int irq, new, vector; unsigned long flags; - vector = assign_irq_vector(AUTO_ASSIGN); - irq = vector; - if (vector >= 0) { - struct irq_desc *desc; - - spin_lock_irqsave(&vector_lock, flags); - vector_irq[vector] = irq; - irq_vector[irq] = vector; - spin_unlock_irqrestore(&vector_lock, flags); + irq = -ENOSPC; + spin_lock_irqsave(&vector_lock, flags); + for (new = (NR_IRQS - 1); new >= 0; new--) { + if (platform_legacy_irq(new)) + continue; + if (irq_vector[new] != 0) + continue; + vector = __assign_irq_vector(new); + if (likely(vector > 0)) + irq = new; + break; + } + spin_unlock_irqrestore(&vector_lock, flags); + if (irq >= 0) { set_intr_gate(vector, interrupt[irq]); - dynamic_irq_init(irq); } return irq; @@ -2521,13 +2441,10 @@ int create_irq(void) void destroy_irq(unsigned int irq) { unsigned long flags; - unsigned int vector; dynamic_irq_cleanup(irq); spin_lock_irqsave(&vector_lock, flags); - vector = irq_vector[irq]; - vector_irq[vector] = -1; irq_vector[irq] = 0; spin_unlock_irqrestore(&vector_lock, flags); } @@ -2754,7 +2671,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a ioapic_write_entry(ioapic, pin, entry); spin_lock_irqsave(&ioapic_lock, flags); - set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); + set_native_irq_info(irq, TARGET_CPUS); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 960f364cab6..47f02af74be 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -981,10 +981,6 @@ static void __init pcibios_fixup_irqs(void) pci_name(bridge), 'A' + pin, irq); } if (irq >= 0) { - if (use_pci_vector() && - !platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); - printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", pci_name(dev), 'A' + pin, irq); dev->irq = irq; diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 8e8fbfaa252..88f02a07356 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -28,7 +28,6 @@ extern u8 irq_vector[NR_IRQ_VECTORS]; #define IO_APIC_VECTOR(irq) (irq_vector[irq]) -#define AUTO_ASSIGN -1 extern void (*interrupt[NR_IRQS])(void); diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h index 5d309275a1d..276ea7e8144 100644 --- a/include/asm-i386/io_apic.h +++ b/include/asm-i386/io_apic.h @@ -12,46 +12,6 @@ #ifdef CONFIG_X86_IO_APIC -#ifdef CONFIG_PCI_MSI -static inline int use_pci_vector(void) {return 1;} -static inline void disable_edge_ioapic_vector(unsigned int vector) { } -static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } -static inline void end_edge_ioapic_vector (unsigned int vector) { } -#define startup_level_ioapic startup_level_ioapic_vector -#define shutdown_level_ioapic mask_IO_APIC_vector -#define enable_level_ioapic unmask_IO_APIC_vector -#define disable_level_ioapic mask_IO_APIC_vector -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector -#define end_level_ioapic end_level_ioapic_vector -#define set_ioapic_affinity set_ioapic_affinity_vector - -#define startup_edge_ioapic startup_edge_ioapic_vector -#define shutdown_edge_ioapic disable_edge_ioapic_vector -#define enable_edge_ioapic unmask_IO_APIC_vector -#define disable_edge_ioapic disable_edge_ioapic_vector -#define ack_edge_ioapic ack_edge_ioapic_vector -#define end_edge_ioapic end_edge_ioapic_vector -#else -static inline int use_pci_vector(void) {return 0;} -static inline void disable_edge_ioapic_irq(unsigned int irq) { } -static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } -static inline void end_edge_ioapic_irq (unsigned int irq) { } -#define startup_level_ioapic startup_level_ioapic_irq -#define shutdown_level_ioapic mask_IO_APIC_irq -#define enable_level_ioapic unmask_IO_APIC_irq -#define disable_level_ioapic mask_IO_APIC_irq -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq -#define end_level_ioapic end_level_ioapic_irq -#define set_ioapic_affinity set_ioapic_affinity_irq - -#define startup_edge_ioapic startup_edge_ioapic_irq -#define shutdown_edge_ioapic disable_edge_ioapic_irq -#define enable_edge_ioapic unmask_IO_APIC_irq -#define disable_edge_ioapic disable_edge_ioapic_irq -#define ack_edge_ioapic ack_edge_ioapic_irq -#define end_edge_ioapic end_edge_ioapic_irq -#endif - #define IO_APIC_BASE(idx) \ ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK))) @@ -219,6 +179,4 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq); static inline void disable_ioapic_setup(void) { } #endif -extern int assign_irq_vector(int irq); - #endif diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h index b330026e6f7..7f161e760be 100644 --- a/include/asm-i386/mach-default/irq_vectors_limits.h +++ b/include/asm-i386/mach-default/irq_vectors_limits.h @@ -1,10 +1,6 @@ #ifndef _ASM_IRQ_VECTORS_LIMITS_H #define _ASM_IRQ_VECTORS_LIMITS_H -#ifdef CONFIG_PCI_MSI -#define NR_IRQS FIRST_SYSTEM_VECTOR -#define NR_IRQ_VECTORS NR_IRQS -#else #ifdef CONFIG_X86_IO_APIC #define NR_IRQS 224 # if (224 >= 32 * NR_CPUS) @@ -16,6 +12,5 @@ #define NR_IRQS 16 #define NR_IRQ_VECTORS NR_IRQS #endif -#endif #endif /* _ASM_IRQ_VECTORS_LIMITS_H */ diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index df579ac29a1..b26248b0e37 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -10,8 +10,6 @@ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar */ -static inline int use_pci_vector(void) {return 0;} - #define APIC_MISMATCH_DEBUG #define IO_APIC_BASE(idx) \ -- GitLab From 323a01c50832749d23664954f91df6fc43e73975 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:48 -0700 Subject: [PATCH 0551/1619] [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(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 82dbb0e8f40..69855b23dff 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) -- GitLab From 23d0b8b053391afe15c9667d80de77ca88e18b8b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:49 -0700 Subject: [PATCH 0552/1619] [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(-) diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h index 64a65ce2f41..95d5e090ed8 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 50d8b5744cf..612472aaa79 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 -- GitLab From e500f57436b9056a245216c53113613928155eba Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:50 -0700 Subject: [PATCH 0553/1619] [PATCH] genirq: x86_64 irq: Make the external irq handlers report their vector, not the irq number This is a small pessimization but it paves the way for making this information per cpu. Which allows the the maximum number of IRQS to become NR_CPUS*224. 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 --- arch/x86_64/kernel/i8259.c | 58 ++++++++++++++++-------------------- arch/x86_64/kernel/io_apic.c | 4 +-- arch/x86_64/kernel/irq.c | 9 ++++-- include/asm-x86_64/hw_irq.h | 1 + 4 files changed, 33 insertions(+), 39 deletions(-) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index ae1101cd525..bddde431871 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -43,17 +43,10 @@ BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ BI(x,c) BI(x,d) BI(x,e) BI(x,f) -#define BUILD_15_IRQS(x) \ - BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ - BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ - BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ - BI(x,c) BI(x,d) BI(x,e) - /* * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: * (these are usually mapped to vectors 0x20-0x2f) */ -BUILD_16_IRQS(0x0) /* * The IO-APIC gives us many more interrupt sources. Most of these @@ -65,17 +58,12 @@ BUILD_16_IRQS(0x0) * * (these are usually mapped into the 0x30-0xff vector range) */ - BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) + BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) -BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) - -#ifdef CONFIG_PCI_MSI - BUILD_15_IRQS(0xe) -#endif +BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf) #undef BUILD_16_IRQS -#undef BUILD_15_IRQS #undef BI @@ -88,29 +76,15 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) -#define IRQLIST_15(x) \ - IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ - IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ - IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ - IRQ(x,c), IRQ(x,d), IRQ(x,e) - void (*interrupt[NR_IRQS])(void) = { - IRQLIST_16(0x0), - - IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3), + IRQLIST_16(0x2), IRQLIST_16(0x3), IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), - IRQLIST_16(0xc), IRQLIST_16(0xd) - -#ifdef CONFIG_PCI_MSI - , IRQLIST_15(0xe) -#endif - + IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf) }; #undef IRQ #undef IRQLIST_16 -#undef IRQLIST_14 /* * This is the 'legacy' 8259A Programmable Interrupt Controller, @@ -420,6 +394,26 @@ device_initcall(i8259A_init_sysfs); */ static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL}; +int vector_irq[NR_VECTORS] __read_mostly = { + [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1, + [FIRST_EXTERNAL_VECTOR + 0] = 0, + [FIRST_EXTERNAL_VECTOR + 1] = 1, + [FIRST_EXTERNAL_VECTOR + 2] = 2, + [FIRST_EXTERNAL_VECTOR + 3] = 3, + [FIRST_EXTERNAL_VECTOR + 4] = 4, + [FIRST_EXTERNAL_VECTOR + 5] = 5, + [FIRST_EXTERNAL_VECTOR + 6] = 6, + [FIRST_EXTERNAL_VECTOR + 7] = 7, + [FIRST_EXTERNAL_VECTOR + 8] = 8, + [FIRST_EXTERNAL_VECTOR + 9] = 9, + [FIRST_EXTERNAL_VECTOR + 10] = 10, + [FIRST_EXTERNAL_VECTOR + 11] = 11, + [FIRST_EXTERNAL_VECTOR + 12] = 12, + [FIRST_EXTERNAL_VECTOR + 13] = 13, + [FIRST_EXTERNAL_VECTOR + 14] = 14, + [FIRST_EXTERNAL_VECTOR + 15] = 15, + [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1 +}; void __init init_ISA_irqs (void) { @@ -517,8 +511,6 @@ void __init init_IRQ(void) */ for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { int vector = FIRST_EXTERNAL_VECTOR + i; - if (i >= NR_IRQS) - break; if (vector != IA32_SYSCALL_VECTOR) set_intr_gate(vector, interrupt[i]); } @@ -528,7 +520,7 @@ void __init init_IRQ(void) * IRQ0 must be given a fixed assignment and initialized, * because it's used before the IO-APIC is set up. */ - set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); + vector_irq[FIRST_DEVICE_VECTOR] = 0; /* * The reschedule interrupt is a CPU-to-CPU reschedule-helper diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index bb16f3790f0..9f849492c29 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -615,6 +615,7 @@ next: } vector = current_vector; + vector_irq[vector] = irq; IO_APIC_VECTOR(irq) = vector; return vector; @@ -649,7 +650,6 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger) else set_irq_chip_and_handler(irq, &ioapic_chip, handle_edge_irq); - set_intr_gate(vector, interrupt[irq]); } static void __init setup_IO_APIC_irqs(void) @@ -1420,7 +1420,6 @@ static inline void check_timer(void) */ disable_8259A_irq(0); vector = assign_irq_vector(0); - set_intr_gate(vector, interrupt[0]); /* * Subtle, code in do_timer_interrupt() expects an AEOI @@ -1671,7 +1670,6 @@ int create_irq(void) spin_unlock_irqrestore(&vector_lock, flags); if (irq >= 0) { - set_intr_gate(vector, interrupt[irq]); dynamic_irq_init(irq); } return irq; diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 609f97153b8..4542fb03199 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -105,7 +105,12 @@ skip: asmlinkage unsigned int do_IRQ(struct pt_regs *regs) { /* high bit used in ret_from_ code */ - unsigned irq = ~regs->orig_rax; + unsigned vector = ~regs->orig_rax; + unsigned irq; + + exit_idle(); + irq_enter(); + irq = vector_irq[vector]; if (unlikely(irq >= NR_IRQS)) { printk(KERN_EMERG "%s: cannot handle IRQ %d\n", @@ -113,8 +118,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) BUG(); } - exit_idle(); - irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW stack_overflow_check(regs); #endif diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 1a8dc185a79..9f6a0bfed72 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -74,6 +74,7 @@ #ifndef __ASSEMBLY__ extern u8 irq_vector[NR_IRQ_VECTORS]; +extern int vector_irq[NR_VECTORS]; #define IO_APIC_VECTOR(irq) (irq_vector[irq]) /* -- GitLab From 550f2299ac8ffaba943cf211380d3a8d3fa75301 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:51 -0700 Subject: [PATCH 0554/1619] [PATCH] genirq: x86_64 irq: make vector_irq per cpu This refactors the irq handling code to make the vectors a per cpu resource so the same vector number can be simultaneously used on multiple cpus for different irqs. This should make systems that were hitting limits on the total number of irqs much more livable. [akpm@osdl.org: build fix] [akpm@osdl.org: __target_IO_APIC_irq is unneeded on UP] 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 --- arch/x86_64/kernel/i8259.c | 4 +- arch/x86_64/kernel/io_apic.c | 181 ++++++++++++++++++++++++++--------- arch/x86_64/kernel/irq.c | 2 +- include/asm-x86_64/hw_irq.h | 6 +- include/asm-x86_64/irq.h | 4 +- 5 files changed, 144 insertions(+), 53 deletions(-) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index bddde431871..0612a33bb89 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -394,7 +394,7 @@ device_initcall(i8259A_init_sysfs); */ static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL}; -int vector_irq[NR_VECTORS] __read_mostly = { +DEFINE_PER_CPU(vector_irq_t, vector_irq) = { [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1, [FIRST_EXTERNAL_VECTOR + 0] = 0, [FIRST_EXTERNAL_VECTOR + 1] = 1, @@ -520,7 +520,7 @@ void __init init_IRQ(void) * IRQ0 must be given a fixed assignment and initialized, * because it's used before the IO-APIC is set up. */ - vector_irq[FIRST_DEVICE_VECTOR] = 0; + __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0; /* * The reschedule interrupt is a CPU-to-CPU reschedule-helper diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 9f849492c29..7d53f66394a 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -44,7 +44,7 @@ #include #include -static int assign_irq_vector(int irq); +static int assign_irq_vector(int irq, cpumask_t mask); #define __apicdebuginit __init @@ -135,11 +135,35 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) } #ifdef CONFIG_SMP +static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) +{ + int apic, pin; + struct irq_pin_list *entry = irq_2_pin + irq; + + BUG_ON(irq >= NR_IRQS); + for (;;) { + unsigned int reg; + apic = entry->apic; + pin = entry->pin; + if (pin == -1) + break; + io_apic_write(apic, 0x11 + pin*2, dest); + reg = io_apic_read(apic, 0x10 + pin*2); + reg &= ~0x000000ff; + reg |= vector; + io_apic_modify(apic, reg); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } +} + static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) { unsigned long flags; unsigned int dest; cpumask_t tmp; + int vector; cpus_and(tmp, mask, cpu_online_map); if (cpus_empty(tmp)) @@ -147,7 +171,13 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) cpus_and(mask, tmp, CPU_MASK_ALL); - dest = cpu_mask_to_apicid(mask); + vector = assign_irq_vector(irq, mask); + if (vector < 0) + return; + + cpus_clear(tmp); + cpu_set(vector >> 8, tmp); + dest = cpu_mask_to_apicid(tmp); /* * Only the high 8 bits are valid. @@ -155,7 +185,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) dest = SET_APIC_LOGICAL_ID(dest); spin_lock_irqsave(&ioapic_lock, flags); - __DO_ACTION(1, = dest, ) + __target_IO_APIC_irq(irq, dest, vector & 0xff); set_native_irq_info(irq, mask); spin_unlock_irqrestore(&ioapic_lock, flags); } @@ -512,7 +542,7 @@ int gsi_irq_sharing(int gsi) tries = NR_IRQS; try_again: - vector = assign_irq_vector(gsi); + vector = assign_irq_vector(gsi, TARGET_CPUS); /* * Sharing vectors means sharing IRQs, so scan irq_vectors for previous @@ -591,45 +621,77 @@ static inline int IO_APIC_irq_trigger(int irq) } /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ -u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; +unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 }; -static int __assign_irq_vector(int irq) +static int __assign_irq_vector(int irq, cpumask_t mask) { - static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - int vector; + /* + * NOTE! The local APIC isn't very good at handling + * multiple interrupts at the same interrupt level. + * As the interrupt level is determined by taking the + * vector number and shifting that right by 4, we + * want to spread these out a bit so that they don't + * all fall in the same interrupt level. + * + * Also, we've got to be careful not to trash gate + * 0x80, because int 0x80 is hm, kind of importantish. ;) + */ + static struct { + int vector; + int offset; + } pos[NR_CPUS] = { [ 0 ... NR_CPUS - 1] = {FIRST_DEVICE_VECTOR, 0} }; + int old_vector = -1; + int cpu; BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); - if (IO_APIC_VECTOR(irq) > 0) { - return IO_APIC_VECTOR(irq); + if (IO_APIC_VECTOR(irq) > 0) + old_vector = IO_APIC_VECTOR(irq); + if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) { + return old_vector; } + + for_each_cpu_mask(cpu, mask) { + int vector, offset; + vector = pos[cpu].vector; + offset = pos[cpu].offset; next: - current_vector += 8; - if (current_vector == IA32_SYSCALL_VECTOR) - goto next; - - if (current_vector >= FIRST_SYSTEM_VECTOR) { - /* If we run out of vectors on large boxen, must share them. */ - offset = (offset + 1) % 8; - current_vector = FIRST_DEVICE_VECTOR + offset; + vector += 8; + if (vector >= FIRST_SYSTEM_VECTOR) { + /* If we run out of vectors on large boxen, must share them. */ + offset = (offset + 1) % 8; + vector = FIRST_DEVICE_VECTOR + offset; + } + if (unlikely(pos[cpu].vector == vector)) + continue; + if (vector == IA32_SYSCALL_VECTOR) + goto next; + if (per_cpu(vector_irq, cpu)[vector] != -1) + goto next; + /* Found one! */ + pos[cpu].vector = vector; + pos[cpu].offset = offset; + if (old_vector >= 0) { + int old_cpu = old_vector >> 8; + old_vector &= 0xff; + per_cpu(vector_irq, old_cpu)[old_vector] = -1; + } + per_cpu(vector_irq, cpu)[vector] = irq; + vector |= cpu << 8; + IO_APIC_VECTOR(irq) = vector; + return vector; } - - vector = current_vector; - vector_irq[vector] = irq; - IO_APIC_VECTOR(irq) = vector; - - return vector; + return -ENOSPC; } -static int assign_irq_vector(int irq) +static int assign_irq_vector(int irq, cpumask_t mask) { int vector; unsigned long flags; spin_lock_irqsave(&vector_lock, flags); - vector = __assign_irq_vector(irq); + vector = __assign_irq_vector(irq, mask); spin_unlock_irqrestore(&vector_lock, flags); - return vector; } @@ -699,8 +761,15 @@ static void __init setup_IO_APIC_irqs(void) continue; if (IO_APIC_IRQ(irq)) { - vector = assign_irq_vector(irq); - entry.vector = vector; + cpumask_t mask; + vector = assign_irq_vector(irq, TARGET_CPUS); + if (vector < 0) + continue; + + cpus_clear(mask); + cpu_set(vector >> 8, mask); + entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); + entry.vector = vector & 0xff; ioapic_register_intr(irq, vector, IOAPIC_AUTO); if (!apic && (irq < 16)) @@ -1197,7 +1266,14 @@ static unsigned int startup_ioapic_irq(unsigned int irq) static int ioapic_retrigger_irq(unsigned int irq) { - send_IPI_self(IO_APIC_VECTOR(irq)); + cpumask_t mask; + unsigned vector; + + vector = irq_vector[irq]; + cpus_clear(mask); + cpu_set(vector >> 8, mask); + + send_IPI_mask(mask, vector & 0xff); return 1; } @@ -1419,7 +1495,7 @@ static inline void check_timer(void) * get/set the timer IRQ vector: */ disable_8259A_irq(0); - vector = assign_irq_vector(0); + vector = assign_irq_vector(0, TARGET_CPUS); /* * Subtle, code in do_timer_interrupt() expects an AEOI @@ -1662,7 +1738,7 @@ int create_irq(void) continue; if (irq_vector[new] != 0) continue; - vector = __assign_irq_vector(new); + vector = __assign_irq_vector(new, TARGET_CPUS); if (likely(vector > 0)) irq = new; break; @@ -1698,12 +1774,12 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg int vector; unsigned dest; - vector = assign_irq_vector(irq); + vector = assign_irq_vector(irq, TARGET_CPUS); if (vector >= 0) { cpumask_t tmp; cpus_clear(tmp); - cpu_set(first_cpu(cpu_online_map), tmp); + cpu_set(vector >> 8, tmp); dest = cpu_mask_to_apicid(tmp); msg->address_hi = MSI_ADDR_BASE_HI; @@ -1738,9 +1814,13 @@ static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_ms int vector; unsigned dest; - vector = assign_irq_vector(irq); + vector = assign_irq_vector(irq, mask); if (vector > 0) { - dest = cpu_mask_to_apicid(mask); + cpumask_t 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); @@ -1783,6 +1863,8 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p { struct IO_APIC_route_entry entry; unsigned long flags; + int vector; + cpumask_t mask; if (!IO_APIC_IRQ(irq)) { apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", @@ -1790,6 +1872,21 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p return -EINVAL; } + irq = gsi_irq_sharing(irq); + /* + * IRQs < 16 are already in the irq_2_pin[] map + */ + if (irq >= 16) + add_pin_to_irq(irq, ioapic, pin); + + + vector = assign_irq_vector(irq, TARGET_CPUS); + if (vector < 0) + return vector; + + cpus_clear(mask); + cpu_set(vector >> 8, mask); + /* * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. * Note that we mask (disable) IRQs now -- these get enabled when the @@ -1800,19 +1897,11 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p entry.delivery_mode = INT_DELIVERY_MODE; entry.dest_mode = INT_DEST_MODE; - entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); + entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); entry.trigger = triggering; entry.polarity = polarity; entry.mask = 1; /* Disabled (masked) */ - - irq = gsi_irq_sharing(irq); - /* - * IRQs < 16 are already in the irq_2_pin[] map - */ - if (irq >= 16) - add_pin_to_irq(irq, ioapic, pin); - - entry.vector = assign_irq_vector(irq); + entry.vector = vector & 0xff; apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " "IRQ %d Mode:%i Active:%i)\n", ioapic, diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 4542fb03199..506f27c85ca 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -110,7 +110,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) exit_idle(); irq_enter(); - irq = vector_irq[vector]; + irq = __get_cpu_var(vector_irq)[vector]; if (unlikely(irq >= NR_IRQS)) { printk(KERN_EMERG "%s: cannot handle IRQ %d\n", diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 9f6a0bfed72..53d0d9fd10d 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -19,6 +19,7 @@ #include #include #include +#include #endif #define NMI_VECTOR 0x02 @@ -73,8 +74,9 @@ #ifndef __ASSEMBLY__ -extern u8 irq_vector[NR_IRQ_VECTORS]; -extern int vector_irq[NR_VECTORS]; +extern unsigned int irq_vector[NR_IRQ_VECTORS]; +typedef int vector_irq_t[NR_VECTORS]; +DECLARE_PER_CPU(vector_irq_t, vector_irq); #define IO_APIC_VECTOR(irq) (irq_vector[irq]) /* diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h index b8f87287847..5006c6e7565 100644 --- a/include/asm-x86_64/irq.h +++ b/include/asm-x86_64/irq.h @@ -31,8 +31,8 @@ #define FIRST_SYSTEM_VECTOR 0xef /* duplicated in hw_irq.h */ -#define NR_IRQS 224 -#define NR_IRQ_VECTORS (32 * NR_CPUS) +#define NR_IRQS (NR_VECTORS + (32 *NR_CPUS)) +#define NR_IRQ_VECTORS NR_IRQS static __inline__ int irq_canonicalize(int irq) { -- GitLab From f023d764cc6165eb4f1cad6b2b0882ce0660764a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:52 -0700 Subject: [PATCH 0555/1619] [PATCH] genirq: x86_64 irq: Kill gsi_irq_sharing After raising the number of irqs the system supports this function is no longer necessary. 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 --- arch/i386/kernel/acpi/boot.c | 4 +-- arch/x86_64/kernel/io_apic.c | 62 ------------------------------------ 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 256fb532321..92f79cdd9a4 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -62,8 +62,6 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return #include #endif /* CONFIG_X86_LOCAL_APIC */ -static inline int gsi_irq_sharing(int gsi) { return gsi; } - #endif /* X86 */ #define BAD_MADT_ENTRY(entry, end) ( \ @@ -468,7 +466,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { - *irq = gsi_irq_sharing(gsi); + *irq = gsi; return 0; } diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 7d53f66394a..e076a8fa3ac 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -191,8 +191,6 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) } #endif -static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF }; - /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super @@ -518,64 +516,6 @@ static inline int irq_trigger(int idx) return MPBIOS_trigger(idx); } -static int next_irq = 16; - -/* - * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ - * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number - * from ACPI, which can reach 800 in large boxen. - * - * Compact the sparse GSI space into a sequential IRQ series and reuse - * vectors if possible. - */ -int gsi_irq_sharing(int gsi) -{ - int i, tries, vector; - - BUG_ON(gsi >= NR_IRQ_VECTORS); - - if (platform_legacy_irq(gsi)) - return gsi; - - if (gsi_2_irq[gsi] != 0xFF) - return (int)gsi_2_irq[gsi]; - - tries = NR_IRQS; - try_again: - vector = assign_irq_vector(gsi, TARGET_CPUS); - - /* - * Sharing vectors means sharing IRQs, so scan irq_vectors for previous - * use of vector and if found, return that IRQ. However, we never want - * to share legacy IRQs, which usually have a different trigger mode - * than PCI. - */ - for (i = 0; i < NR_IRQS; i++) - if (IO_APIC_VECTOR(i) == vector) - break; - if (platform_legacy_irq(i)) { - if (--tries >= 0) { - IO_APIC_VECTOR(i) = 0; - goto try_again; - } - panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi); - } - if (i < NR_IRQS) { - gsi_2_irq[gsi] = i; - printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n", - gsi, vector, i); - return i; - } - - i = next_irq++; - BUG_ON(i >= NR_IRQS); - gsi_2_irq[gsi] = i; - IO_APIC_VECTOR(i) = vector; - printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n", - gsi, vector, i); - return i; -} - static int pin_2_irq(int idx, int apic, int pin) { int irq, i; @@ -597,7 +537,6 @@ static int pin_2_irq(int idx, int apic, int pin) while (i < apic) irq += nr_ioapic_registers[i++]; irq += pin; - irq = gsi_irq_sharing(irq); } BUG_ON(irq >= NR_IRQS); return irq; @@ -1872,7 +1811,6 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p return -EINVAL; } - irq = gsi_irq_sharing(irq); /* * IRQs < 16 are already in the irq_2_pin[] map */ -- GitLab From cd1182f56a064d42d10e289ef4018f9c2230247d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:53 -0700 Subject: [PATCH 0556/1619] [PATCH] genirq: x86_64 irq: Kill irq compression With more irqs in the system we don't need this. 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 --- arch/x86_64/kernel/io_apic.c | 5 ----- arch/x86_64/kernel/mpparse.c | 42 +----------------------------------- include/asm-x86_64/io_apic.h | 1 - 3 files changed, 1 insertion(+), 47 deletions(-) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index e076a8fa3ac..7cc29b50b0c 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1415,8 +1415,6 @@ static inline void unlock_ExtINT_logic(void) spin_unlock_irqrestore(&ioapic_lock, flags); } -int timer_uses_ioapic_pin_0; - /* * This code may look a bit paranoid, but it's supposed to cooperate with * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ @@ -1453,9 +1451,6 @@ static inline void check_timer(void) pin2 = ioapic_i8259.pin; apic2 = ioapic_i8259.apic; - if (pin1 == 0) - timer_uses_ioapic_pin_0 = 1; - apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", vector, apic1, pin1, apic2, pin2); diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index b8d53dfa993..b147ab19fbd 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -790,20 +790,11 @@ void __init mp_config_acpi_legacy_irqs(void) } } -#define MAX_GSI_NUM 4096 - int mp_register_gsi(u32 gsi, int triggering, int polarity) { int ioapic = -1; int ioapic_pin = 0; int idx, bit = 0; - static int pci_irq = 16; - /* - * Mapping between Global System Interrupts, which - * represent all possible interrupts, to the IRQs - * assigned to actual devices. - */ - static int gsi_to_irq[MAX_GSI_NUM]; if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) return gsi; @@ -836,42 +827,11 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) if ((1< 15), but - * avoid a problem where the 8254 timer (IRQ0) is setup - * via an override (so it's not on pin 0 of the ioapic), - * and at the same time, the pin 0 interrupt is a PCI - * type. The gsi > 15 test could cause these two pins - * to be shared as IRQ0, and they are not shareable. - * So test for this condition, and if necessary, avoid - * the pin collision. - */ - if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0)) - gsi = pci_irq++; - /* - * Don't assign IRQ used by ACPI SCI - */ - if (gsi == acpi_fadt.sci_int) - gsi = pci_irq++; - gsi_to_irq[irq] = gsi; - } else { - printk(KERN_ERR "GSI %u is too high\n", gsi); - return gsi; - } - } - io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, polarity == ACPI_ACTIVE_HIGH ? 0 : 1); diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index b26248b0e37..171ec2dc8c0 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -162,7 +162,6 @@ extern int skip_ioapic_setup; extern int io_apic_get_version (int ioapic); extern int io_apic_get_redir_entries (int ioapic); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int); -extern int timer_uses_ioapic_pin_0; #endif extern int sis_apic_bug; /* dummy */ -- GitLab From e78d01693be38bf93dd6bb49b86e143da450de86 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:54 -0700 Subject: [PATCH 0557/1619] [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(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 723972bb5bd..3ee03a9a98f 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 7d0e26cba42..c312a12ad2d 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 */ -- GitLab From 8b955b0dddb35e398b07e217a81f8bd49400796f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:55 -0700 Subject: [PATCH 0558/1619] [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 diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 03e7606be6e..100406b453b 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 7cc29b50b0c..31c270fee33 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 c27e782e6df..0af6d728841 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 983d0f86aa3..2752c57ecf0 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 00000000000..4ba46359d36 --- /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 00000000000..c16c6ff4bdd --- /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 00000000000..c16c6ff4bdd --- /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 2aabe90f1cd..9b34bc8f34e 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); -- GitLab From 1f80025e624bb14fefadfef7e80fbfb9740d4714 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:56 -0700 Subject: [PATCH 0559/1619] [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(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index da2c6c2b6b1..e3ba3963988 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 435d05aae4b..77823bfed5c 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 69855b23dff..6f463606c31 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 0dc24386dd9..4cf65f5c6a7 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); -- GitLab From 277bc33bc2479707e88b0b2ae6fe56e8e4aabe81 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:57 -0700 Subject: [PATCH 0560/1619] [PATCH] msi: only use a single irq_chip for msi interrupts The logic works like this. Since we no longer track the state logic by hand in msi.c startup and shutdown are no longer needed. By updating msi_set_mask_bit to work on msi devices that do not implement a mask bit we can always call the mask/unmask functions. What we really have are mask and unmask so we use them to implement the .mask and .unmask functions instead of .enable and .disable. By switching to the handle_edge_irq handler we only need an ack function that moves the irq if necessary. Which removes the old end and ack functions and their peculiar logic of sometimes disabling an irq. This removes the reliance on pre genirq irq handling methods. 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 | 115 ++++++++++------------------------------------ 1 file changed, 24 insertions(+), 91 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index e3ba3963988..fc7dd2a239d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -53,21 +53,20 @@ static void msi_set_mask_bit(unsigned int irq, int flag) struct msi_desc *entry; entry = msi_desc[irq]; - if (!entry || !entry->dev || !entry->mask_base) - return; + BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: - { - int pos; - u32 mask_bits; - - pos = (long)entry->mask_base; - pci_read_config_dword(entry->dev, pos, &mask_bits); - mask_bits &= ~(1); - mask_bits |= flag; - pci_write_config_dword(entry->dev, pos, mask_bits); + if (entry->msi_attrib.maskbit) { + int pos; + u32 mask_bits; + + pos = (long)entry->mask_base; + pci_read_config_dword(entry->dev, pos, &mask_bits); + mask_bits &= ~(1); + mask_bits |= flag; + pci_write_config_dword(entry->dev, pos, mask_bits); + } break; - } case PCI_CAP_ID_MSIX: { int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + @@ -76,6 +75,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag) break; } default: + BUG(); break; } } @@ -186,83 +186,21 @@ static void unmask_MSI_irq(unsigned int irq) msi_set_mask_bit(irq, 0); } -static unsigned int startup_msi_irq_wo_maskbit(unsigned int irq) -{ - return 0; /* never anything pending */ -} - -static unsigned int startup_msi_irq_w_maskbit(unsigned int irq) -{ - startup_msi_irq_wo_maskbit(irq); - unmask_MSI_irq(irq); - return 0; /* never anything pending */ -} - -static void shutdown_msi_irq(unsigned int irq) -{ -} - -static void end_msi_irq_wo_maskbit(unsigned int irq) +static void ack_msi_irq(unsigned int irq) { move_native_irq(irq); ack_APIC_irq(); } -static void end_msi_irq_w_maskbit(unsigned int irq) -{ - move_native_irq(irq); - unmask_MSI_irq(irq); - ack_APIC_irq(); -} - -static void do_nothing(unsigned int irq) -{ -} - -/* - * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices, - * which implement the MSI-X Capability Structure. - */ -static struct hw_interrupt_type msix_irq_type = { - .typename = "PCI-MSI-X", - .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq, - .enable = unmask_MSI_irq, - .disable = mask_MSI_irq, - .ack = mask_MSI_irq, - .end = end_msi_irq_w_maskbit, - .set_affinity = set_msi_affinity -}; - -/* - * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices, - * which implement the MSI Capability Structure with - * Mask-and-Pending Bits. - */ -static struct hw_interrupt_type msi_irq_w_maskbit_type = { - .typename = "PCI-MSI", - .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq, - .enable = unmask_MSI_irq, - .disable = mask_MSI_irq, - .ack = mask_MSI_irq, - .end = end_msi_irq_w_maskbit, - .set_affinity = set_msi_affinity -}; - /* - * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices, - * which implement the MSI Capability Structure without - * Mask-and-Pending Bits. + * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, + * which implement the MSI or MSI-X Capability Structure. */ -static struct hw_interrupt_type msi_irq_wo_maskbit_type = { - .typename = "PCI-MSI", - .startup = startup_msi_irq_wo_maskbit, - .shutdown = shutdown_msi_irq, - .enable = do_nothing, - .disable = do_nothing, - .ack = do_nothing, - .end = end_msi_irq_wo_maskbit, +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 }; @@ -330,7 +268,7 @@ static void attach_msi_entry(struct msi_desc *entry, int irq) spin_unlock_irqrestore(&msi_lock, flags); } -static int create_msi_irq(struct hw_interrupt_type *handler) +static int create_msi_irq(struct irq_chip *chip) { struct msi_desc *entry; int irq; @@ -345,7 +283,7 @@ static int create_msi_irq(struct hw_interrupt_type *handler) return -EBUSY; } - set_irq_chip(irq, handler); + set_irq_chip_and_handler(irq, chip, handle_edge_irq); set_irq_data(irq, entry); return irq; @@ -634,16 +572,11 @@ static int msi_capability_init(struct pci_dev *dev) struct msi_desc *entry; int pos, irq; u16 control; - struct hw_interrupt_type *handler; pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ - handler = &msi_irq_wo_maskbit_type; - if (is_mask_bit_support(control)) - handler = &msi_irq_w_maskbit_type; - - irq = create_msi_irq(handler); + irq = create_msi_irq(&msi_chip); if (irq < 0) return irq; @@ -715,7 +648,7 @@ static int msix_capability_init(struct pci_dev *dev, /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { - irq = create_msi_irq(&msix_irq_type); + irq = create_msi_irq(&msi_chip); if (irq < 0) break; -- GitLab From 3b7d1921f4cdd6d6ddb7899ae7a8d413991c5cf4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:59 -0700 Subject: [PATCH 0561/1619] [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 diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 100406b453b..5a1252753db 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 31c270fee33..e55028fba94 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 7aedc2ac8c2..6ffd1f850d4 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 afc0ed13aa8..822e59a1b82 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 fc7dd2a239d..f9fdc54473c 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 77823bfed5c..f0cca1772f9 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 7368a89a0f4..00000000000 --- 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 15b545a897a..90cba967df3 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 cf724dc79d8..c54b165b1c1 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 bb92b0dbde2..00000000000 --- 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 1876fda52ae..00000000000 --- 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 00000000000..c7ef9434367 --- /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 9b34bc8f34e..0da5a4a8940 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 -- GitLab From 03571e11c4a6d08230657f80970f0a5cc7820471 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:17:00 -0700 Subject: [PATCH 0562/1619] [PATCH] msi: move the ia64 code into arch/ia64 This is just a few makefile tweaks and some file renames. 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/ia64/kernel/Makefile | 1 + drivers/pci/msi-apic.c => arch/ia64/kernel/msi_ia64.c | 0 arch/ia64/sn/kernel/Makefile | 1 + drivers/pci/msi-altix.c => arch/ia64/sn/kernel/msi_sn.c | 0 drivers/pci/Makefile | 9 +++------ 5 files changed, 5 insertions(+), 6 deletions(-) rename drivers/pci/msi-apic.c => arch/ia64/kernel/msi_ia64.c (100%) rename drivers/pci/msi-altix.c => arch/ia64/sn/kernel/msi_sn.c (100%) diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 31497496eb4..cfa099b04cd 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o obj-$(CONFIG_AUDIT) += audit.o +obj-$(CONFIG_PCI_MSI) += msi_ia64.o mca_recovery-y += mca_drv.o mca_drv_asm.o obj-$(CONFIG_IA64_ESI) += esi.o diff --git a/drivers/pci/msi-apic.c b/arch/ia64/kernel/msi_ia64.c similarity index 100% rename from drivers/pci/msi-apic.c rename to arch/ia64/kernel/msi_ia64.c diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index ab9c48c8801..2d78f34dd76 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile @@ -19,3 +19,4 @@ xp-y := xp_main.o xp_nofault.o obj-$(CONFIG_IA64_SGI_SN_XP) += xpc.o xpc-y := xpc_main.o xpc_channel.o xpc_partition.o obj-$(CONFIG_IA64_SGI_SN_XP) += xpnet.o +obj-$(CONFIG_PCI_MSI) += msi_sn.o diff --git a/drivers/pci/msi-altix.c b/arch/ia64/sn/kernel/msi_sn.c similarity index 100% rename from drivers/pci/msi-altix.c rename to arch/ia64/sn/kernel/msi_sn.c diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 2752c57ecf0..04694ec7224 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -14,6 +14,9 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o # Build the PCI Hotplug drivers if we were asked to obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ +# Build the PCI MSI interrupt support +obj-$(CONFIG_PCI_MSI) += msi.o + # # Some architectures use the generic PCI setup functions # @@ -28,12 +31,6 @@ 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 -msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o -msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o -obj-$(CONFIG_PCI_MSI) += $(msiobj-y) - # # ACPI Related PCI FW Functions # -- GitLab From 95d77884c77beed676036d2f74d10b470a483c63 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:17:01 -0700 Subject: [PATCH 0563/1619] [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 diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5a1252753db..b7287fb499f 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 e55028fba94..91728d9d347 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 0af6d728841..30294127a0a 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 04694ec7224..e3beb784406 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 4ba46359d36..0e27f2404a8 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 00000000000..1f15ce279a2 --- /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 0da5a4a8940..5c604f5fad6 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); -- GitLab From 621934ee7ed5b073c7fd638b347e632c53572761 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 4 Oct 2006 02:17:02 -0700 Subject: [PATCH 0564/1619] [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 diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 1d50cf0c905..f4dffadbcb0 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 02e27bf1d36..f84407cba81 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 820fee23696..e0d6d99b8f9 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 00000000000..947fdab2ddb --- /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 d948ca12acf..5e3f3b75563 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 00000000000..7e1979f624b --- /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); -- GitLab From b2896d2e75c87ea6a842c088db730b03c91db737 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 4 Oct 2006 02:17:03 -0700 Subject: [PATCH 0565/1619] [PATCH] srcu-3: add SRCU operations to rcutorture Adds SRCU operations to rcutorture and updates rcutorture documentation. Also increases the stress imposed by the rcutorture test. [bunk@stusta.de: make needlessly global code static] Signed-off-by: Paul E. McKenney Cc: Paul E. McKenney Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/torture.txt | 15 ++++ kernel/rcutorture.c | 133 +++++++++++++++++++++++++++++++--- 2 files changed, 138 insertions(+), 10 deletions(-) diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index a4948591607..2174badd31e 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -118,6 +118,21 @@ o "Free-Block Circulation": Shows the number of torture structures as it is only incremented if a torture structure's counter somehow gets incremented farther than it should. +Different implementations of RCU can provide implementation-specific +additional information. For example, SRCU provides the following: + + srcu-torture: rtc: f8cf46a8 ver: 355 tfle: 0 rta: 356 rtaf: 0 rtf: 346 rtmbe: 0 + srcu-torture: Reader Pipe: 559738 939 0 0 0 0 0 0 0 0 0 + srcu-torture: Reader Batch: 560434 243 0 0 0 0 0 0 0 0 + srcu-torture: Free-Block Circulation: 355 354 353 352 351 350 349 348 347 346 0 + srcu-torture: per-CPU(idx=1): 0(0,1) 1(0,1) 2(0,0) 3(0,1) + +The first four lines are similar to those for RCU. The last line shows +the per-CPU counter state. The numbers in parentheses are the values +of the "old" and "current" counters for the corresponding CPU. The +"idx" value maps the "old" and "current" values to the underlying array, +and is useful for debugging. + USAGE diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 23446e91cde..e34d22bf229 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -44,6 +44,7 @@ #include #include #include +#include MODULE_LICENSE("GPL"); @@ -53,7 +54,7 @@ static int stat_interval; /* Interval between stats, in seconds. */ static int verbose; /* Print more debug info. */ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ -static char *torture_type = "rcu"; /* What to torture. */ +static char *torture_type = "rcu"; /* What to torture: rcu, srcu. */ module_param(nreaders, int, 0); MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); @@ -66,7 +67,7 @@ MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); module_param(shuffle_interval, int, 0); MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); module_param(torture_type, charp, 0); -MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)"); +MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); #define TORTURE_FLAG "-torture:" #define PRINTK_STRING(s) \ @@ -104,11 +105,11 @@ static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) = { 0 }; static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1]; -atomic_t n_rcu_torture_alloc; -atomic_t n_rcu_torture_alloc_fail; -atomic_t n_rcu_torture_free; -atomic_t n_rcu_torture_mberror; -atomic_t n_rcu_torture_error; +static atomic_t n_rcu_torture_alloc; +static atomic_t n_rcu_torture_alloc_fail; +static atomic_t n_rcu_torture_free; +static atomic_t n_rcu_torture_mberror; +static atomic_t n_rcu_torture_error; /* * Allocate an element from the rcu_tortures pool. @@ -180,6 +181,7 @@ struct rcu_torture_ops { void (*init)(void); void (*cleanup)(void); int (*readlock)(void); + void (*readdelay)(struct rcu_random_state *rrsp); void (*readunlock)(int idx); int (*completed)(void); void (*deferredfree)(struct rcu_torture *p); @@ -198,6 +200,18 @@ static int rcu_torture_read_lock(void) __acquires(RCU) return 0; } +static void rcu_read_delay(struct rcu_random_state *rrsp) +{ + long delay; + const long longdelay = 200; + + /* We want there to be long-running readers, but not all the time. */ + + delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay); + if (!delay) + udelay(longdelay); +} + static void rcu_torture_read_unlock(int idx) __releases(RCU) { rcu_read_unlock(); @@ -239,6 +253,7 @@ static struct rcu_torture_ops rcu_ops = { .init = NULL, .cleanup = NULL, .readlock = rcu_torture_read_lock, + .readdelay = rcu_read_delay, .readunlock = rcu_torture_read_unlock, .completed = rcu_torture_completed, .deferredfree = rcu_torture_deferred_free, @@ -275,6 +290,7 @@ static struct rcu_torture_ops rcu_bh_ops = { .init = NULL, .cleanup = NULL, .readlock = rcu_bh_torture_read_lock, + .readdelay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = rcu_bh_torture_read_unlock, .completed = rcu_bh_torture_completed, .deferredfree = rcu_bh_torture_deferred_free, @@ -282,8 +298,105 @@ static struct rcu_torture_ops rcu_bh_ops = { .name = "rcu_bh" }; +/* + * Definitions for srcu torture testing. + */ + +static struct srcu_struct srcu_ctl; +static struct list_head srcu_removed; + +static void srcu_torture_init(void) +{ + init_srcu_struct(&srcu_ctl); + INIT_LIST_HEAD(&srcu_removed); +} + +static void srcu_torture_cleanup(void) +{ + synchronize_srcu(&srcu_ctl); + cleanup_srcu_struct(&srcu_ctl); +} + +static int srcu_torture_read_lock(void) +{ + return srcu_read_lock(&srcu_ctl); +} + +static void srcu_read_delay(struct rcu_random_state *rrsp) +{ + long delay; + const long uspertick = 1000000 / HZ; + const long longdelay = 10; + + /* We want there to be long-running readers, but not all the time. */ + + delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick); + if (!delay) + schedule_timeout_interruptible(longdelay); +} + +static void srcu_torture_read_unlock(int idx) +{ + srcu_read_unlock(&srcu_ctl, idx); +} + +static int srcu_torture_completed(void) +{ + return srcu_batches_completed(&srcu_ctl); +} + +static void srcu_torture_deferred_free(struct rcu_torture *p) +{ + int i; + struct rcu_torture *rp; + struct rcu_torture *rp1; + + synchronize_srcu(&srcu_ctl); + list_add(&p->rtort_free, &srcu_removed); + list_for_each_entry_safe(rp, rp1, &srcu_removed, rtort_free) { + i = rp->rtort_pipe_count; + if (i > RCU_TORTURE_PIPE_LEN) + i = RCU_TORTURE_PIPE_LEN; + atomic_inc(&rcu_torture_wcount[i]); + if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { + rp->rtort_mbtest = 0; + list_del(&rp->rtort_free); + rcu_torture_free(rp); + } + } +} + +static int srcu_torture_stats(char *page) +{ + int cnt = 0; + int cpu; + int idx = srcu_ctl.completed & 0x1; + + cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):", + torture_type, TORTURE_FLAG, idx); + for_each_possible_cpu(cpu) { + cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu, + per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx], + per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]); + } + cnt += sprintf(&page[cnt], "\n"); + return cnt; +} + +static struct rcu_torture_ops srcu_ops = { + .init = srcu_torture_init, + .cleanup = srcu_torture_cleanup, + .readlock = srcu_torture_read_lock, + .readdelay = srcu_read_delay, + .readunlock = srcu_torture_read_unlock, + .completed = srcu_torture_completed, + .deferredfree = srcu_torture_deferred_free, + .stats = srcu_torture_stats, + .name = "srcu" +}; + static struct rcu_torture_ops *torture_ops[] = - { &rcu_ops, &rcu_bh_ops, NULL }; + { &rcu_ops, &rcu_bh_ops, &srcu_ops, NULL }; /* * RCU torture writer kthread. Repeatedly substitutes a new structure @@ -359,7 +472,7 @@ rcu_torture_reader(void *arg) } if (p->rtort_mbtest == 0) atomic_inc(&n_rcu_torture_mberror); - udelay(rcu_random(&rand) & 0x7f); + cur_ops->readdelay(&rand); preempt_disable(); pipe_count = p->rtort_pipe_count; if (pipe_count > RCU_TORTURE_PIPE_LEN) { @@ -483,7 +596,7 @@ static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ /* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs. */ -void rcu_torture_shuffle_tasks(void) +static void rcu_torture_shuffle_tasks(void) { cpumask_t tmp_mask = CPU_MASK_ALL; int i; -- GitLab From eabc069401bcf45bcc3f19e643017bf761780aa8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Oct 2006 02:17:04 -0700 Subject: [PATCH 0566/1619] [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(-) diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 7ff386a6ae8..10a43ed0527 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 947fdab2ddb..8a45367b5f3 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 2314867ae34..fd5c7100677 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 -- GitLab From e6a92013ba458804161c0c5b6d134d82204dc233 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Oct 2006 02:17:05 -0700 Subject: [PATCH 0567/1619] [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(-) diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 8a45367b5f3..aca0eee5393 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 7e1979f624b..3507cabe963 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 fd5c7100677..98489d82801 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; } -- GitLab From b4dfdbb3c707474a2254c5b4d7e62be31a4b7da9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Oct 2006 02:17:06 -0700 Subject: [PATCH 0568/1619] [PATCH] cpufreq: make the transition_notifier chain use SRCU This patch (as762) changes the cpufreq_transition_notifier_list from a blocking_notifier_head to an srcu_notifier_head. This will prevent errors caused attempting to call down_read() to access the notifier chain at a time when interrupts must remain disabled, during system suspend. It's not clear to me whether this is really necessary; perhaps the chain could be made into an atomic_notifier. However a couple of the callout routines do use blocking operations, so this approach seems safer. The head of the notifier chain needs to be initialized before use; this is done by an __init routine at core_initcall time. If this turns out not to be a good choice, it can easily be changed. Signed-off-by: Alan Stern Cc: "Paul E. McKenney" Cc: Jesse Brandeburg Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2caaf71d80c..86e69b7f912 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -52,8 +52,14 @@ static void handle_update(void *data); * The mutex locks both lists. */ static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); -static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list); +static struct srcu_notifier_head cpufreq_transition_notifier_list; +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); static LIST_HEAD(cpufreq_governor_list); static DEFINE_MUTEX (cpufreq_governor_mutex); @@ -262,14 +268,14 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) freqs->old = policy->cur; } } - blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); adjust_jiffies(CPUFREQ_PRECHANGE, freqs); break; case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) policy->cur = freqs->new; @@ -1049,7 +1055,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) freqs.old = cpu_policy->cur; freqs.new = cur_freq; - blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_SUSPENDCHANGE, &freqs); adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); @@ -1130,7 +1136,7 @@ static int cpufreq_resume(struct sys_device * sysdev) freqs.old = cpu_policy->cur; freqs.new = cur_freq; - blocking_notifier_call_chain( + srcu_notifier_call_chain( &cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); @@ -1176,7 +1182,7 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: - ret = blocking_notifier_chain_register( + ret = srcu_notifier_chain_register( &cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: @@ -1208,7 +1214,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: - ret = blocking_notifier_chain_unregister( + ret = srcu_notifier_chain_unregister( &cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: -- GitLab From ff2c93a5373f12f86f3281705d11278a9f2334e2 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:09 -0700 Subject: [PATCH 0569/1619] [PATCH] rcu: Add MODULE_AUTHOR to rcutorture module Signed-off-by: Josh Triplett Acked-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index e34d22bf229..7b965341b1d 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -47,6 +47,7 @@ #include MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul E. McKenney "); static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */ static int stat_interval; /* Interval between stats, in seconds. */ -- GitLab From 3c29e03d9121e07714fb9e5303d9b026800ffd5a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:10 -0700 Subject: [PATCH 0570/1619] [PATCH] rcu: Mention rcu_bh in description of rcutorture's torture_type parameter The comment for rcutorture's torture_type parameter only lists the RCU variants rcu and srcu, but not rcu_bh; add rcu_bh to the list. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 7b965341b1d..021d3108bb6 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -55,7 +55,7 @@ static int stat_interval; /* Interval between stats, in seconds. */ static int verbose; /* Print more debug info. */ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ -static char *torture_type = "rcu"; /* What to torture: rcu, srcu. */ +static char *torture_type = "rcu"; /* What to torture: rcu, rcu_bh, srcu. */ module_param(nreaders, int, 0); MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); -- GitLab From 2860aaba4dc87fa43c08724434b87a8650f3bff5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:11 -0700 Subject: [PATCH 0571/1619] [PATCH] rcu: Avoid kthread_stop on invalid pointer if rcutorture reader startup fails rcu_torture_init kmallocs the array of reader threads, then creates each one with kthread_run, cleaning up with rcu_torture_cleanup if this fails. rcu_torture_cleanup calls kthread_stop on any non-NULL pointer in the array; however, any readers after the one that failed to start up will have invalid pointers, not null pointers. Avoid this by using kzalloc instead. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 021d3108bb6..42e7f01e800 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -780,7 +780,7 @@ rcu_torture_init(void) writer_task = NULL; goto unwind; } - reader_tasks = kmalloc(nrealreaders * sizeof(reader_tasks[0]), + reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), GFP_KERNEL); if (reader_tasks == NULL) { VERBOSE_PRINTK_ERRSTRING("out of memory"); -- GitLab From 75cfef32f26d03f5d0a0833572d52f94ad858a36 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:12 -0700 Subject: [PATCH 0572/1619] [PATCH] rcu: Fix sign bug making rcu_random always return the same sequence rcu_random uses a counter rrs_count to occasionally mix data from get_random_bytes into the state of its pseudorandom generator. However, the rrs_counter gets declared as an unsigned long, and rcu_random checks for --rrs_count < 0, so this code will never mix any real random data into the state, and will thus always return the same sequence of random numbers. Also, change the return value of rcu_random from long to unsigned long, to avoid potential issues caused by the use of the % operator, which can return negative values for negative left operands. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 42e7f01e800..43d6d4f9ef0 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -147,7 +147,7 @@ rcu_torture_free(struct rcu_torture *p) struct rcu_random_state { unsigned long rrs_state; - unsigned long rrs_count; + long rrs_count; }; #define RCU_RANDOM_MULT 39916801 /* prime */ @@ -160,7 +160,7 @@ struct rcu_random_state { * Crude but fast random-number generator. Uses a linear congruential * generator, with occasional help from get_random_bytes(). */ -static long +static unsigned long rcu_random(struct rcu_random_state *rrsp) { long refresh; -- GitLab From b772e1dd4b1e60a7a160f7bd4ea08e28394ceb54 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:13 -0700 Subject: [PATCH 0573/1619] [PATCH] RCU: add fake writers to rcutorture rcutorture currently has one writer and an arbitrary number of readers. To better exercise some of the code paths in RCU implementations, add fake writer threads which call the synchronize function for the RCU variant in a loop, with a delay between calls to arrange for different numbers of writers running in parallel. [bunk@stusta.de: cleanup] Acked-by: Paul McKenney Cc: Dipkanar Sarma Signed-off-by: Josh Triplett Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/torture.txt | 9 +++ kernel/rcutorture.c | 109 ++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 5 deletions(-) diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 2174badd31e..2180ef93acc 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -28,6 +28,15 @@ nreaders This is the number of RCU reading threads supported. To properly exercise RCU implementations with preemptible read-side critical sections. +nfakewriters This is the number of RCU fake writer threads to run. Fake + writer threads repeatedly use the synchronous "wait for + current readers" function of the interface selected by + torture_type, with a delay between calls to allow for various + different numbers of writers running in parallel. + nfakewriters defaults to 4, which provides enough parallelism + to trigger special cases caused by multiple writers, such as + the synchronize_srcu() early return optimization. + stat_interval The number of seconds between output of torture statistics (via printk()). Regardless of the interval, statistics are printed when the module is unloaded. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 43d6d4f9ef0..e0450210ce4 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -15,9 +15,10 @@ * 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, 2005 + * Copyright (C) IBM Corporation, 2005, 2006 * * Authors: Paul E. McKenney + * Josh Triplett * * See also: Documentation/RCU/torture.txt */ @@ -47,9 +48,11 @@ #include MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Paul E. McKenney "); +MODULE_AUTHOR("Paul E. McKenney and " + "Josh Triplett "); static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */ +static int nfakewriters = 4; /* # fake writer threads */ static int stat_interval; /* Interval between stats, in seconds. */ /* Defaults to "only at end of test". */ static int verbose; /* Print more debug info. */ @@ -59,6 +62,8 @@ static char *torture_type = "rcu"; /* What to torture: rcu, rcu_bh, srcu. */ module_param(nreaders, int, 0); MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); +module_param(nfakewriters, int, 0); +MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads"); module_param(stat_interval, int, 0); MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s"); module_param(verbose, bool, 0); @@ -82,6 +87,7 @@ static char printk_buf[4096]; static int nrealreaders; static struct task_struct *writer_task; +static struct task_struct **fakewriter_tasks; static struct task_struct **reader_tasks; static struct task_struct *stats_task; static struct task_struct *shuffler_task; @@ -186,6 +192,7 @@ struct rcu_torture_ops { void (*readunlock)(int idx); int (*completed)(void); void (*deferredfree)(struct rcu_torture *p); + void (*sync)(void); int (*stats)(char *page); char *name; }; @@ -258,6 +265,7 @@ static struct rcu_torture_ops rcu_ops = { .readunlock = rcu_torture_read_unlock, .completed = rcu_torture_completed, .deferredfree = rcu_torture_deferred_free, + .sync = synchronize_rcu, .stats = NULL, .name = "rcu" }; @@ -287,6 +295,28 @@ static void rcu_bh_torture_deferred_free(struct rcu_torture *p) call_rcu_bh(&p->rtort_rcu, rcu_torture_cb); } +struct rcu_bh_torture_synchronize { + struct rcu_head head; + struct completion completion; +}; + +static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head) +{ + struct rcu_bh_torture_synchronize *rcu; + + rcu = container_of(head, struct rcu_bh_torture_synchronize, head); + complete(&rcu->completion); +} + +static void rcu_bh_torture_synchronize(void) +{ + struct rcu_bh_torture_synchronize rcu; + + init_completion(&rcu.completion); + call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb); + wait_for_completion(&rcu.completion); +} + static struct rcu_torture_ops rcu_bh_ops = { .init = NULL, .cleanup = NULL, @@ -295,6 +325,7 @@ static struct rcu_torture_ops rcu_bh_ops = { .readunlock = rcu_bh_torture_read_unlock, .completed = rcu_bh_torture_completed, .deferredfree = rcu_bh_torture_deferred_free, + .sync = rcu_bh_torture_synchronize, .stats = NULL, .name = "rcu_bh" }; @@ -367,6 +398,11 @@ static void srcu_torture_deferred_free(struct rcu_torture *p) } } +static void srcu_torture_synchronize(void) +{ + synchronize_srcu(&srcu_ctl); +} + static int srcu_torture_stats(char *page) { int cnt = 0; @@ -392,6 +428,7 @@ static struct rcu_torture_ops srcu_ops = { .readunlock = srcu_torture_read_unlock, .completed = srcu_torture_completed, .deferredfree = srcu_torture_deferred_free, + .sync = srcu_torture_synchronize, .stats = srcu_torture_stats, .name = "srcu" }; @@ -443,6 +480,30 @@ rcu_torture_writer(void *arg) return 0; } +/* + * RCU torture fake writer kthread. Repeatedly calls sync, with a random + * delay between calls. + */ +static int +rcu_torture_fakewriter(void *arg) +{ + DEFINE_RCU_RANDOM(rand); + + VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); + set_user_nice(current, 19); + + do { + schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); + udelay(rcu_random(&rand) & 0x3ff); + cur_ops->sync(); + } while (!kthread_should_stop() && !fullstop); + + VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); + while (!kthread_should_stop()) + schedule_timeout_uninterruptible(1); + return 0; +} + /* * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current, * incrementing the corresponding element of the pipeline array. The @@ -621,6 +682,12 @@ static void rcu_torture_shuffle_tasks(void) set_cpus_allowed(reader_tasks[i], tmp_mask); } + if (fakewriter_tasks != NULL) { + for (i = 0; i < nfakewriters; i++) + if (fakewriter_tasks[i]) + set_cpus_allowed(fakewriter_tasks[i], tmp_mask); + } + if (writer_task) set_cpus_allowed(writer_task, tmp_mask); @@ -654,11 +721,12 @@ rcu_torture_shuffle(void *arg) static inline void rcu_torture_print_module_parms(char *tag) { - printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d " + printk(KERN_ALERT "%s" TORTURE_FLAG + "--- %s: nreaders=%d nfakewriters=%d " "stat_interval=%d verbose=%d test_no_idle_hz=%d " "shuffle_interval = %d\n", - torture_type, tag, nrealreaders, stat_interval, verbose, - test_no_idle_hz, shuffle_interval); + torture_type, tag, nrealreaders, nfakewriters, + stat_interval, verbose, test_no_idle_hz, shuffle_interval); } static void @@ -693,6 +761,19 @@ rcu_torture_cleanup(void) } rcu_torture_current = NULL; + if (fakewriter_tasks != NULL) { + for (i = 0; i < nfakewriters; i++) { + if (fakewriter_tasks[i] != NULL) { + VERBOSE_PRINTK_STRING( + "Stopping rcu_torture_fakewriter task"); + kthread_stop(fakewriter_tasks[i]); + } + fakewriter_tasks[i] = NULL; + } + kfree(fakewriter_tasks); + fakewriter_tasks = NULL; + } + if (stats_task != NULL) { VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task"); kthread_stop(stats_task); @@ -780,6 +861,24 @@ rcu_torture_init(void) writer_task = NULL; goto unwind; } + fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), + GFP_KERNEL); + if (fakewriter_tasks == NULL) { + VERBOSE_PRINTK_ERRSTRING("out of memory"); + firsterr = -ENOMEM; + goto unwind; + } + for (i = 0; i < nfakewriters; i++) { + VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task"); + fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, + "rcu_torture_fakewriter"); + if (IS_ERR(fakewriter_tasks[i])) { + firsterr = PTR_ERR(fakewriter_tasks[i]); + VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter"); + fakewriter_tasks[i] = NULL; + goto unwind; + } + } reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), GFP_KERNEL); if (reader_tasks == NULL) { -- GitLab From e3033736581f125ba5fd6c0760e0d430d54fb5c0 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:14 -0700 Subject: [PATCH 0574/1619] [PATCH] rcu: refactor srcu_torture_deferred_free to work for any implementation Make srcu_torture_deferred_free use cur_ops->sync() so it will work for any implementation. Move and rename it in preparation for use in the ops of other implementations. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 53 +++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index e0450210ce4..6e2f0a8344c 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -117,6 +117,7 @@ static atomic_t n_rcu_torture_alloc_fail; static atomic_t n_rcu_torture_free; static atomic_t n_rcu_torture_mberror; static atomic_t n_rcu_torture_error; +static struct list_head rcu_torture_removed; /* * Allocate an element from the rcu_tortures pool. @@ -270,6 +271,32 @@ static struct rcu_torture_ops rcu_ops = { .name = "rcu" }; +static void rcu_sync_torture_deferred_free(struct rcu_torture *p) +{ + int i; + struct rcu_torture *rp; + struct rcu_torture *rp1; + + cur_ops->sync(); + list_add(&p->rtort_free, &rcu_torture_removed); + list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) { + i = rp->rtort_pipe_count; + if (i > RCU_TORTURE_PIPE_LEN) + i = RCU_TORTURE_PIPE_LEN; + atomic_inc(&rcu_torture_wcount[i]); + if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { + rp->rtort_mbtest = 0; + list_del(&rp->rtort_free); + rcu_torture_free(rp); + } + } +} + +static void rcu_sync_torture_init(void) +{ + INIT_LIST_HEAD(&rcu_torture_removed); +} + /* * Definitions for rcu_bh torture testing. */ @@ -335,12 +362,11 @@ static struct rcu_torture_ops rcu_bh_ops = { */ static struct srcu_struct srcu_ctl; -static struct list_head srcu_removed; static void srcu_torture_init(void) { init_srcu_struct(&srcu_ctl); - INIT_LIST_HEAD(&srcu_removed); + rcu_sync_torture_init(); } static void srcu_torture_cleanup(void) @@ -377,27 +403,6 @@ static int srcu_torture_completed(void) return srcu_batches_completed(&srcu_ctl); } -static void srcu_torture_deferred_free(struct rcu_torture *p) -{ - int i; - struct rcu_torture *rp; - struct rcu_torture *rp1; - - synchronize_srcu(&srcu_ctl); - list_add(&p->rtort_free, &srcu_removed); - list_for_each_entry_safe(rp, rp1, &srcu_removed, rtort_free) { - i = rp->rtort_pipe_count; - if (i > RCU_TORTURE_PIPE_LEN) - i = RCU_TORTURE_PIPE_LEN; - atomic_inc(&rcu_torture_wcount[i]); - if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { - rp->rtort_mbtest = 0; - list_del(&rp->rtort_free); - rcu_torture_free(rp); - } - } -} - static void srcu_torture_synchronize(void) { synchronize_srcu(&srcu_ctl); @@ -427,7 +432,7 @@ static struct rcu_torture_ops srcu_ops = { .readdelay = srcu_read_delay, .readunlock = srcu_torture_read_unlock, .completed = srcu_torture_completed, - .deferredfree = srcu_torture_deferred_free, + .deferredfree = rcu_sync_torture_deferred_free, .sync = srcu_torture_synchronize, .stats = srcu_torture_stats, .name = "srcu" -- GitLab From 20d2e4283a97665a3db78c60dfa342a0c7c1b180 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:15 -0700 Subject: [PATCH 0575/1619] [PATCH] rcu: add rcu_sync torture type to rcutorture Use the newly-generic synchronous deferred free function to implement torture testing for RCU using synchronize_rcu rather than the asynchronous call_rcu. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/torture.txt | 7 ++++--- kernel/rcutorture.c | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 2180ef93acc..6714b536115 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -53,9 +53,10 @@ test_no_idle_hz Whether or not to test the ability of RCU to operate in a kernel that disables the scheduling-clock interrupt to idle CPUs. Boolean parameter, "1" to test, "0" otherwise. -torture_type The type of RCU to test: "rcu" for the rcu_read_lock() - API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu" - for the "srcu_read_lock()" API. +torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API, + "rcu_sync" for rcu_read_lock() with synchronous reclamation, + "rcu_bh" for the rcu_read_lock_bh() API, and "srcu" for the + "srcu_read_lock()" API. verbose Enable debug printk()s. Default is disabled. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 6e2f0a8344c..1c329df60bc 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -58,7 +58,7 @@ static int stat_interval; /* Interval between stats, in seconds. */ static int verbose; /* Print more debug info. */ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ -static char *torture_type = "rcu"; /* What to torture: rcu, rcu_bh, srcu. */ +static char *torture_type = "rcu"; /* What RCU implementation to torture. */ module_param(nreaders, int, 0); MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); @@ -297,6 +297,19 @@ static void rcu_sync_torture_init(void) INIT_LIST_HEAD(&rcu_torture_removed); } +static struct rcu_torture_ops rcu_sync_ops = { + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = rcu_torture_read_lock, + .readdelay = rcu_read_delay, + .readunlock = rcu_torture_read_unlock, + .completed = rcu_torture_completed, + .deferredfree = rcu_sync_torture_deferred_free, + .sync = synchronize_rcu, + .stats = NULL, + .name = "rcu_sync" +}; + /* * Definitions for rcu_bh torture testing. */ @@ -439,7 +452,7 @@ static struct rcu_torture_ops srcu_ops = { }; static struct rcu_torture_ops *torture_ops[] = - { &rcu_ops, &rcu_bh_ops, &srcu_ops, NULL }; + { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &srcu_ops, NULL }; /* * RCU torture writer kthread. Repeatedly substitutes a new structure -- GitLab From 11a147013e39ff4cb031395cb78a9d307c4799cd Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:16 -0700 Subject: [PATCH 0576/1619] [PATCH] rcu: add rcu_bh_sync torture type to rcutorture Use the newly-generic synchronous deferred free function to implement torture testing for rcu_bh using synchronize_rcu_bh rather than the asynchronous call_rcu_bh. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/torture.txt | 5 +++-- kernel/rcutorture.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 6714b536115..cc4b1efe5ea 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -55,8 +55,9 @@ test_no_idle_hz Whether or not to test the ability of RCU to operate in torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API, "rcu_sync" for rcu_read_lock() with synchronous reclamation, - "rcu_bh" for the rcu_read_lock_bh() API, and "srcu" for the - "srcu_read_lock()" API. + "rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for + rcu_read_lock_bh() with synchronous reclamation, and "srcu" + for the "srcu_read_lock()" API. verbose Enable debug printk()s. Default is disabled. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 1c329df60bc..0f0ff1556b5 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -370,6 +370,19 @@ static struct rcu_torture_ops rcu_bh_ops = { .name = "rcu_bh" }; +static struct rcu_torture_ops rcu_bh_sync_ops = { + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = rcu_bh_torture_read_lock, + .readdelay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_bh_torture_read_unlock, + .completed = rcu_bh_torture_completed, + .deferredfree = rcu_sync_torture_deferred_free, + .sync = rcu_bh_torture_synchronize, + .stats = NULL, + .name = "rcu_bh_sync" +}; + /* * Definitions for srcu torture testing. */ @@ -452,7 +465,8 @@ static struct rcu_torture_ops srcu_ops = { }; static struct rcu_torture_ops *torture_ops[] = - { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &srcu_ops, NULL }; + { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops, + NULL }; /* * RCU torture writer kthread. Repeatedly substitutes a new structure -- GitLab From 4b6c2cca6eef9cc4a15350bf1c61839e12e08b84 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:16 -0700 Subject: [PATCH 0577/1619] [PATCH] rcu: add sched torture type to rcutorture Implement torture testing for the "sched" variant of RCU, which uses preempt_disable, preempt_enable, and synchronize_sched. Signed-off-by: Josh Triplett Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/torture.txt | 5 +++-- kernel/rcutorture.c | 40 ++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index cc4b1efe5ea..25a3c3f7d37 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -56,8 +56,9 @@ test_no_idle_hz Whether or not to test the ability of RCU to operate in torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API, "rcu_sync" for rcu_read_lock() with synchronous reclamation, "rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for - rcu_read_lock_bh() with synchronous reclamation, and "srcu" - for the "srcu_read_lock()" API. + rcu_read_lock_bh() with synchronous reclamation, "srcu" for + the "srcu_read_lock()" API, and "sched" for the use of + preempt_disable() together with synchronize_sched(). verbose Enable debug printk()s. Default is disabled. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 0f0ff1556b5..e2bda18f6f4 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -464,9 +464,47 @@ static struct rcu_torture_ops srcu_ops = { .name = "srcu" }; +/* + * Definitions for sched torture testing. + */ + +static int sched_torture_read_lock(void) +{ + preempt_disable(); + return 0; +} + +static void sched_torture_read_unlock(int idx) +{ + preempt_enable(); +} + +static int sched_torture_completed(void) +{ + return 0; +} + +static void sched_torture_synchronize(void) +{ + synchronize_sched(); +} + +static struct rcu_torture_ops sched_ops = { + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = sched_torture_read_lock, + .readdelay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = sched_torture_read_unlock, + .completed = sched_torture_completed, + .deferredfree = rcu_sync_torture_deferred_free, + .sync = sched_torture_synchronize, + .stats = NULL, + .name = "sched" +}; + static struct rcu_torture_ops *torture_ops[] = { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops, - NULL }; + &sched_ops, NULL }; /* * RCU torture writer kthread. Repeatedly substitutes a new structure -- GitLab From 20e9751bd9dd6b832fd84ada27840360f7e877f1 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 4 Oct 2006 02:17:17 -0700 Subject: [PATCH 0578/1619] [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(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 12b3b24bfd2..e1543a32a55 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 b4ca73d6589..f6dd71bf8a4 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 523e46483b9..26bb5ffe1ef 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); -- GitLab From 595182bcdf64fbfd7ae22c67ea6081b7d387d246 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:21 -0700 Subject: [PATCH 0579/1619] [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(-) diff --git a/CREDITS b/CREDITS index dba3e633469..5d75254bcb8 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 129511c0c27..fb10f71b8b6 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 f6dd71bf8a4..c6b7485eac7 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 -- GitLab From d56b9b9c464a10ab1ee51a4c6190a2b57b8ef7a6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 4 Oct 2006 02:17:22 -0700 Subject: [PATCH 0580/1619] [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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 42b95e0ad55..24f3c63b301 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 e1543a32a55..ff571f9298e 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 b5908a66ff5..00000000000 --- 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 387d058c3f9..00000000000 --- 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 310f42ca1e8..00000000000 --- 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 865dbd84874..00000000000 --- 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 4a80eb3f8e0..00000000000 --- 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 a113718e803..00000000000 --- 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 a81e0ef72ae..00000000000 --- 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 66a91835d91..00000000000 --- 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 80054cd8fcd..00000000000 --- 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 16f57ea4305..00000000000 --- 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 7b38b1a096a..00000000000 --- 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 87d7b7b65fa..00000000000 --- 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 95c4c83422b..00000000000 --- 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 84dee2e0b37..00000000000 --- 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 fb10f71b8b6..8c35b3c503a 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 9e8bcb5fa99..7d564b6fc98 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 2ed2fd85513..22eb9367235 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 f63d8342ffa..9e2a94feed6 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 51ab3c933ac..00000000000 --- 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 86811792002..8313757b648 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 3ba6d91e891..72cf4ed7793 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 77d454ea320..01837a9d7d6 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 972327c9764..602db497929 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 24a9acd2816..00000000000 --- 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 f6b6b886c2a..257b7536fb1 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 d0573b02397..b95ebe28d42 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 70dcd703a66..00000000000 --- 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 e3796231452..00000000000 --- 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 5da217fcbed..3919e4d6b3f 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 ab00c3c67e4..00000000000 --- 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 01c592cee04..00000000000 --- 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 fe584810608..00000000000 --- 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 ea51aafaf40..00000000000 --- 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 6d527e8530d..00000000000 --- 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 701d595e33f..00000000000 --- 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 4559f02c996..00000000000 --- 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 0400a416dc9..00000000000 --- 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 90cbd767953..00000000000 --- 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 b44fdc9ce00..00000000000 --- 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 14a90593c44..00000000000 --- 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 6c1cf74b78c..6ff67f73cbb 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 13f48314973..00000000000 --- 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 82f40a0a5c9..00000000000 --- 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 ea1c0207aef..00000000000 --- 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 3d5271baf04..00000000000 --- 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 a3d6ae33fe8..00000000000 --- 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 f97a0b8670e..00000000000 --- 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 7ad0c30d4fd..00000000000 --- 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 d1997a417ad..00000000000 --- 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 6ae6924e164..00000000000 --- 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 597db7aee63..00000000000 --- 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 6601b284f03..00000000000 --- 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 45918df150b..00000000000 --- 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 48d333c7302..00000000000 --- 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 aa3c50db66c..00000000000 --- 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 1d98d100d73..00000000000 --- 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 023ec7f968f..00000000000 --- 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 5548e3cff7c..00000000000 --- 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 dde29862c57..00000000000 --- 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 317f22589a0..00000000000 --- 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 321f4c4b5a7..162d07cc489 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 bdc5bde641e..84c0e9522ef 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 2535ed0b5fb..00000000000 --- 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 f17d25b6f83..00000000000 --- 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 7a3c188ea0a..00000000000 --- 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 0ce4e4ef6fe..23922377250 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 5d008798c31..118525638bd 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 0bcff673531..00000000000 --- 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 8ea532d4019..00000000000 --- 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 1ae07509664..cd335ba8145 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 858e1fe6c61..a73e3dd39f9 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 1dec3958cc7..00000000000 --- 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 75c0c143a75..00000000000 --- 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 6e22472df95..00000000000 --- 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 ac1785f2b7e..00000000000 --- 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 112f2fff6c8..00000000000 --- 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 e700400576d..00000000000 --- 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 56d8b6b5e43..00000000000 --- 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 0b0a016ca6d..5322c50c961 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 */ -- GitLab From ece7f77b86e53bfe14699fdbcb0f03fdad0a01d6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 4 Oct 2006 02:17:31 -0700 Subject: [PATCH 0581/1619] [PATCH] kill sound/oss/*_syms.c Move all EXPORT_SYMBOL's from sound/oss/*_syms.c to the files with the actual functions. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/Makefile | 8 +++--- sound/oss/audio_syms.c | 14 ----------- sound/oss/dev_table.c | 44 ++++++++++++++++++++++++++++++++- sound/oss/dev_table.h | 17 +------------ sound/oss/dmabuf.c | 10 +++----- sound/oss/midi_syms.c | 29 ---------------------- sound/oss/midi_synth.c | 21 ++++++++++++++-- sound/oss/midibuf.c | 11 ++------- sound/oss/sequencer.c | 14 +++++------ sound/oss/sequencer_syms.c | 22 ----------------- sound/oss/sound_calls.h | 1 - sound/oss/sound_syms.c | 50 -------------------------------------- sound/oss/sound_timer.c | 4 +++ sound/oss/soundcard.c | 16 +++++++----- 14 files changed, 93 insertions(+), 168 deletions(-) delete mode 100644 sound/oss/audio_syms.c delete mode 100644 sound/oss/midi_syms.c delete mode 100644 sound/oss/sequencer_syms.c delete mode 100644 sound/oss/sound_syms.c diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 8313757b648..2489bd6bb08 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -63,10 +63,10 @@ obj-$(CONFIG_DMASOUND) += dmasound/ # Declare multi-part drivers. sound-objs := \ - dev_table.o soundcard.o sound_syms.o \ - audio.o audio_syms.o dmabuf.o \ - midi_syms.o midi_synth.o midibuf.o \ - sequencer.o sequencer_syms.o sound_timer.o sys_timer.o + dev_table.o soundcard.o \ + audio.o dmabuf.o \ + midi_synth.o midibuf.o \ + sequencer.o sound_timer.o sys_timer.o pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb-objs := sb_card.o diff --git a/sound/oss/audio_syms.c b/sound/oss/audio_syms.c deleted file mode 100644 index 3919e4d6b3f..00000000000 --- a/sound/oss/audio_syms.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Exported symbols for audio driver. - */ - -#include - -char audio_syms_symbol; - -#include "sound_config.h" -#include "sound_calls.h" - -EXPORT_SYMBOL(DMAbuf_start_dma); -EXPORT_SYMBOL(DMAbuf_inputintr); -EXPORT_SYMBOL(DMAbuf_outputintr); diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c index fb64279f393..08274c995d0 100644 --- a/sound/oss/dev_table.c +++ b/sound/oss/dev_table.c @@ -13,9 +13,39 @@ #include -#define _DEV_TABLE_C_ #include "sound_config.h" +struct audio_operations *audio_devs[MAX_AUDIO_DEV]; +EXPORT_SYMBOL(audio_devs); + +int num_audiodevs; +EXPORT_SYMBOL(num_audiodevs); + +struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; +EXPORT_SYMBOL(mixer_devs); + +int num_mixers; +EXPORT_SYMBOL(num_mixers); + +struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; +EXPORT_SYMBOL(synth_devs); + +int num_synths; + +struct midi_operations *midi_devs[MAX_MIDI_DEV]; +EXPORT_SYMBOL(midi_devs); + +int num_midis; +EXPORT_SYMBOL(num_midis); + +struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { + &default_sound_timer, NULL +}; +EXPORT_SYMBOL(sound_timer_devs); + +int num_sound_timers = 1; + + static int sound_alloc_audiodev(void); int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, @@ -75,6 +105,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, audio_init_devices(); return num; } +EXPORT_SYMBOL(sound_install_audiodrv); int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, int driver_size, void *devc) @@ -113,6 +144,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, mixer_devs[n] = op; return n; } +EXPORT_SYMBOL(sound_install_mixer); void sound_unload_audiodev(int dev) { @@ -122,6 +154,7 @@ void sound_unload_audiodev(int dev) unregister_sound_dsp((dev<<4)+3); } } +EXPORT_SYMBOL(sound_unload_audiodev); static int sound_alloc_audiodev(void) { @@ -144,6 +177,7 @@ int sound_alloc_mididev(void) num_midis = i + 1; return i; } +EXPORT_SYMBOL(sound_alloc_mididev); int sound_alloc_synthdev(void) { @@ -158,6 +192,7 @@ int sound_alloc_synthdev(void) } return -1; } +EXPORT_SYMBOL(sound_alloc_synthdev); int sound_alloc_mixerdev(void) { @@ -169,6 +204,7 @@ int sound_alloc_mixerdev(void) num_mixers = i + 1; return i; } +EXPORT_SYMBOL(sound_alloc_mixerdev); int sound_alloc_timerdev(void) { @@ -183,6 +219,7 @@ int sound_alloc_timerdev(void) } return -1; } +EXPORT_SYMBOL(sound_alloc_timerdev); void sound_unload_mixerdev(int dev) { @@ -192,6 +229,7 @@ void sound_unload_mixerdev(int dev) num_mixers--; } } +EXPORT_SYMBOL(sound_unload_mixerdev); void sound_unload_mididev(int dev) { @@ -200,15 +238,19 @@ void sound_unload_mididev(int dev) unregister_sound_midi((dev<<4)+2); } } +EXPORT_SYMBOL(sound_unload_mididev); void sound_unload_synthdev(int dev) { if (dev != -1) synth_devs[dev] = NULL; } +EXPORT_SYMBOL(sound_unload_synthdev); void sound_unload_timerdev(int dev) { if (dev != -1) sound_timer_devs[dev] = NULL; } +EXPORT_SYMBOL(sound_unload_timerdev); + diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h index adf1d625b57..b7617bee638 100644 --- a/sound/oss/dev_table.h +++ b/sound/oss/dev_table.h @@ -352,22 +352,8 @@ struct sound_timer_operations void (*arm_timer)(int dev, long time); }; -#ifdef _DEV_TABLE_C_ -struct audio_operations *audio_devs[MAX_AUDIO_DEV]; -int num_audiodevs; -struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; -int num_mixers; -struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; -int num_synths; -struct midi_operations *midi_devs[MAX_MIDI_DEV]; -int num_midis; - extern struct sound_timer_operations default_sound_timer; -struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { - &default_sound_timer, NULL -}; -int num_sound_timers = 1; -#else + extern struct audio_operations *audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs; extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; @@ -378,7 +364,6 @@ extern struct midi_operations *midi_devs[MAX_MIDI_DEV]; extern int num_midis; extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; extern int num_sound_timers; -#endif /* _DEV_TABLE_C_ */ extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); void sound_timer_init (struct sound_lowlev_timer *t, char *name); diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index 6ff67f73cbb..b256c040116 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c @@ -926,6 +926,7 @@ int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) sound_start_dma(dmap, physaddr, count, dma_mode); return count; } +EXPORT_SYMBOL(DMAbuf_start_dma); static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode) { @@ -1055,6 +1056,8 @@ void DMAbuf_outputintr(int dev, int notify_only) do_outputintr(dev, notify_only); spin_unlock_irqrestore(&dmap->lock,flags); } +EXPORT_SYMBOL(DMAbuf_outputintr); + /* called with dmap->lock held in irq context */ static void do_inputintr(int dev) { @@ -1154,6 +1157,7 @@ void DMAbuf_inputintr(int dev) do_inputintr(dev); spin_unlock_irqrestore(&dmap->lock,flags); } +EXPORT_SYMBOL(DMAbuf_inputintr); void DMAbuf_init(int dev, int dma1, int dma2) { @@ -1162,12 +1166,6 @@ void DMAbuf_init(int dev, int dma1, int dma2) * NOTE! This routine could be called several times. */ - /* drag in audio_syms.o */ - { - extern char audio_syms_symbol; - audio_syms_symbol = 0; - } - if (adev && adev->dmap_out == NULL) { if (adev->d == NULL) panic("OSS: audio_devs[%d]->d == NULL\n", dev); diff --git a/sound/oss/midi_syms.c b/sound/oss/midi_syms.c deleted file mode 100644 index 5b146ddf572..00000000000 --- a/sound/oss/midi_syms.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Exported symbols for midi driver. - */ - -#include - -char midi_syms_symbol; - -#include "sound_config.h" -#define _MIDI_SYNTH_C_ -#include "midi_synth.h" - -EXPORT_SYMBOL(do_midi_msg); -EXPORT_SYMBOL(midi_synth_open); -EXPORT_SYMBOL(midi_synth_close); -EXPORT_SYMBOL(midi_synth_ioctl); -EXPORT_SYMBOL(midi_synth_kill_note); -EXPORT_SYMBOL(midi_synth_start_note); -EXPORT_SYMBOL(midi_synth_set_instr); -EXPORT_SYMBOL(midi_synth_reset); -EXPORT_SYMBOL(midi_synth_hw_control); -EXPORT_SYMBOL(midi_synth_aftertouch); -EXPORT_SYMBOL(midi_synth_controller); -EXPORT_SYMBOL(midi_synth_panning); -EXPORT_SYMBOL(midi_synth_setup_voice); -EXPORT_SYMBOL(midi_synth_send_sysex); -EXPORT_SYMBOL(midi_synth_bender); -EXPORT_SYMBOL(midi_synth_load_patch); -EXPORT_SYMBOL(MIDIbuf_avail); diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index d2ab5c08b61..9e450988ed3 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c @@ -84,6 +84,7 @@ do_midi_msg(int synthno, unsigned char *msg, int mlen) ; } } +EXPORT_SYMBOL(do_midi_msg); static void midi_outc(int midi_dev, int data) @@ -276,6 +277,7 @@ int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg) return -EINVAL; } } +EXPORT_SYMBOL(midi_synth_ioctl); int midi_synth_kill_note(int dev, int channel, int note, int velocity) @@ -342,6 +344,7 @@ midi_synth_kill_note(int dev, int channel, int note, int velocity) return 0; } +EXPORT_SYMBOL(midi_synth_kill_note); int midi_synth_set_instr(int dev, int channel, int instr_no) @@ -364,6 +367,7 @@ midi_synth_set_instr(int dev, int channel, int instr_no) return 0; } +EXPORT_SYMBOL(midi_synth_set_instr); int midi_synth_start_note(int dev, int channel, int note, int velocity) @@ -405,6 +409,7 @@ midi_synth_start_note(int dev, int channel, int note, int velocity) } return 0; } +EXPORT_SYMBOL(midi_synth_start_note); void midi_synth_reset(int dev) @@ -412,6 +417,7 @@ midi_synth_reset(int dev) leave_sysex(dev); } +EXPORT_SYMBOL(midi_synth_reset); int midi_synth_open(int dev, int mode) @@ -444,6 +450,7 @@ midi_synth_open(int dev, int mode) return 1; } +EXPORT_SYMBOL(midi_synth_open); void midi_synth_close(int dev) @@ -459,11 +466,13 @@ midi_synth_close(int dev) midi_devs[orig_dev]->close(orig_dev); } +EXPORT_SYMBOL(midi_synth_close); void midi_synth_hw_control(int dev, unsigned char *event) { } +EXPORT_SYMBOL(midi_synth_hw_control); int midi_synth_load_patch(int dev, int format, const char __user *addr, @@ -542,11 +551,13 @@ midi_synth_load_patch(int dev, int format, const char __user *addr, midi_outc(orig_dev, 0xf7); return 0; } - +EXPORT_SYMBOL(midi_synth_load_patch); + void midi_synth_panning(int dev, int channel, int pressure) { } - +EXPORT_SYMBOL(midi_synth_panning); + void midi_synth_aftertouch(int dev, int channel, int pressure) { int orig_dev = synth_devs[dev]->midi_dev; @@ -576,6 +587,7 @@ void midi_synth_aftertouch(int dev, int channel, int pressure) midi_outc(orig_dev, pressure); } +EXPORT_SYMBOL(midi_synth_aftertouch); void midi_synth_controller(int dev, int channel, int ctrl_num, int value) @@ -604,6 +616,7 @@ midi_synth_controller(int dev, int channel, int ctrl_num, int value) midi_outc(orig_dev, ctrl_num); midi_outc(orig_dev, value & 0x7f); } +EXPORT_SYMBOL(midi_synth_controller); void midi_synth_bender(int dev, int channel, int value) @@ -635,11 +648,13 @@ midi_synth_bender(int dev, int channel, int value) midi_outc(orig_dev, value & 0x7f); midi_outc(orig_dev, (value >> 7) & 0x7f); } +EXPORT_SYMBOL(midi_synth_bender); void midi_synth_setup_voice(int dev, int voice, int channel) { } +EXPORT_SYMBOL(midi_synth_setup_voice); int midi_synth_send_sysex(int dev, unsigned char *bytes, int len) @@ -695,3 +710,5 @@ midi_synth_send_sysex(int dev, unsigned char *bytes, int len) return 0; } +EXPORT_SYMBOL(midi_synth_send_sysex); + diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index c0e4bbc22c8..a40be0cf1d9 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -414,18 +414,11 @@ unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait) } -void MIDIbuf_init(void) -{ - /* drag in midi_syms.o */ - { - extern char midi_syms_symbol; - midi_syms_symbol = 0; - } -} - int MIDIbuf_avail(int dev) { if (midi_in_buf[dev]) return DATA_AVAIL (midi_in_buf[dev]); return 0; } +EXPORT_SYMBOL(MIDIbuf_avail); + diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 23922377250..5c215f787ca 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -156,6 +156,7 @@ void seq_copy_to_input(unsigned char *event_rec, int len) wake_up(&midi_sleeper); spin_unlock_irqrestore(&lock,flags); } +EXPORT_SYMBOL(seq_copy_to_input); static void sequencer_midi_input(int dev, unsigned char data) { @@ -205,6 +206,7 @@ void seq_input_event(unsigned char *event_rec, int len) } seq_copy_to_input(event_rec, len); } +EXPORT_SYMBOL(seq_input_event); int sequencer_write(int dev, struct file *file, const char __user *buf, int count) { @@ -1553,6 +1555,7 @@ void sequencer_timer(unsigned long dummy) { seq_startplay(); } +EXPORT_SYMBOL(sequencer_timer); int note_to_freq(int note_num) { @@ -1586,6 +1589,7 @@ int note_to_freq(int note_num) return note_freq; } +EXPORT_SYMBOL(note_to_freq); unsigned long compute_finetune(unsigned long base_freq, int bend, int range, int vibrato_cents) @@ -1639,19 +1643,12 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range, else return (base_freq * amount) / 10000; /* Bend up */ } - +EXPORT_SYMBOL(compute_finetune); void sequencer_init(void) { - /* drag in sequencer_syms.o */ - { - extern char sequencer_syms_symbol; - sequencer_syms_symbol = 0; - } - if (sequencer_ok) return; - MIDIbuf_init(); queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); if (queue == NULL) { @@ -1667,6 +1664,7 @@ void sequencer_init(void) } sequencer_ok = 1; } +EXPORT_SYMBOL(sequencer_init); void sequencer_unload(void) { diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c deleted file mode 100644 index 118525638bd..00000000000 --- a/sound/oss/sequencer_syms.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Exported symbols for sequencer driver. - */ - -#include - -char sequencer_syms_symbol; - -#include "sound_config.h" -#include "sound_calls.h" - -EXPORT_SYMBOL(note_to_freq); -EXPORT_SYMBOL(compute_finetune); -EXPORT_SYMBOL(seq_copy_to_input); -EXPORT_SYMBOL(seq_input_event); -EXPORT_SYMBOL(sequencer_init); -EXPORT_SYMBOL(sequencer_timer); - -EXPORT_SYMBOL(sound_timer_init); -EXPORT_SYMBOL(sound_timer_interrupt); -EXPORT_SYMBOL(sound_timer_syncinterval); - diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h index cd335ba8145..87d8ad4a034 100644 --- a/sound/oss/sound_calls.h +++ b/sound/oss/sound_calls.h @@ -71,7 +71,6 @@ unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait); int MIDIbuf_avail(int dev); void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); -void MIDIbuf_init(void); /* From soundcard.c */ diff --git a/sound/oss/sound_syms.c b/sound/oss/sound_syms.c deleted file mode 100644 index cb7c33fe5b0..00000000000 --- a/sound/oss/sound_syms.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * The sound core exports the following symbols to the rest of - * modulespace. - * - * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL - * - * Thu May 27 1999 Andrew J. Kroll - * left out exported symbol... fixed - */ - -#include -#include "sound_config.h" -#include "sound_calls.h" - -char sound_syms_symbol; - -EXPORT_SYMBOL(mixer_devs); -EXPORT_SYMBOL(audio_devs); -EXPORT_SYMBOL(num_mixers); -EXPORT_SYMBOL(num_audiodevs); - -EXPORT_SYMBOL(midi_devs); -EXPORT_SYMBOL(num_midis); -EXPORT_SYMBOL(synth_devs); - -EXPORT_SYMBOL(sound_timer_devs); - -EXPORT_SYMBOL(sound_install_audiodrv); -EXPORT_SYMBOL(sound_install_mixer); -EXPORT_SYMBOL(sound_alloc_dma); -EXPORT_SYMBOL(sound_free_dma); -EXPORT_SYMBOL(sound_open_dma); -EXPORT_SYMBOL(sound_close_dma); -EXPORT_SYMBOL(sound_alloc_mididev); -EXPORT_SYMBOL(sound_alloc_mixerdev); -EXPORT_SYMBOL(sound_alloc_timerdev); -EXPORT_SYMBOL(sound_alloc_synthdev); -EXPORT_SYMBOL(sound_unload_audiodev); -EXPORT_SYMBOL(sound_unload_mididev); -EXPORT_SYMBOL(sound_unload_mixerdev); -EXPORT_SYMBOL(sound_unload_timerdev); -EXPORT_SYMBOL(sound_unload_synthdev); - -EXPORT_SYMBOL(load_mixer_volumes); - -EXPORT_SYMBOL(conf_printf); -EXPORT_SYMBOL(conf_printf2); - -MODULE_DESCRIPTION("OSS Sound subsystem"); -MODULE_AUTHOR("Hannu Savolainen, et al."); diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c index 146bf85de95..f0f0c19fbff 100644 --- a/sound/oss/sound_timer.c +++ b/sound/oss/sound_timer.c @@ -76,6 +76,7 @@ void sound_timer_syncinterval(unsigned int new_usecs) tmr_ctr = 0; usecs_per_tmr = new_usecs; } +EXPORT_SYMBOL(sound_timer_syncinterval); static void tmr_reset(void) { @@ -300,6 +301,7 @@ void sound_timer_interrupt(void) } spin_unlock_irqrestore(&lock,flags); } +EXPORT_SYMBOL(sound_timer_interrupt); void sound_timer_init(struct sound_lowlev_timer *t, char *name) { @@ -321,3 +323,5 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name) strcpy(sound_timer.info.name, name); sound_timer_devs[n] = &sound_timer; } +EXPORT_SYMBOL(sound_timer_init); + diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 683dc00a8d2..2344d09c711 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -107,6 +107,7 @@ int *load_mixer_volumes(char *name, int *levels, int present) mixer_vols[n].levels[i] = levels[i]; return mixer_vols[n].levels; } +EXPORT_SYMBOL(load_mixer_volumes); static int set_mixer_levels(void __user * arg) { @@ -541,12 +542,6 @@ static int __init oss_init(void) int err; int i, j; - /* drag in sound_syms.o */ - { - extern char sound_syms_symbol; - sound_syms_symbol = 0; - } - #ifdef CONFIG_PCI if(dmabug) isa_dma_bridge_buggy = dmabug; @@ -614,6 +609,8 @@ static void __exit oss_cleanup(void) module_init(oss_init); module_exit(oss_cleanup); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("OSS Sound subsystem"); +MODULE_AUTHOR("Hannu Savolainen, et al."); int sound_alloc_dma(int chn, char *deviceID) @@ -627,6 +624,7 @@ int sound_alloc_dma(int chn, char *deviceID) return 0; } +EXPORT_SYMBOL(sound_alloc_dma); int sound_open_dma(int chn, char *deviceID) { @@ -642,6 +640,7 @@ int sound_open_dma(int chn, char *deviceID) dma_alloc_map[chn] = DMA_MAP_BUSY; return 0; } +EXPORT_SYMBOL(sound_open_dma); void sound_free_dma(int chn) { @@ -652,6 +651,7 @@ void sound_free_dma(int chn) free_dma(chn); dma_alloc_map[chn] = DMA_MAP_UNAVAIL; } +EXPORT_SYMBOL(sound_free_dma); void sound_close_dma(int chn) { @@ -661,6 +661,7 @@ void sound_close_dma(int chn) } dma_alloc_map[chn] = DMA_MAP_FREE; } +EXPORT_SYMBOL(sound_close_dma); static void do_sequencer_timer(unsigned long dummy) { @@ -714,6 +715,7 @@ void conf_printf(char *name, struct address_info *hw_config) printk("\n"); #endif } +EXPORT_SYMBOL(conf_printf); void conf_printf2(char *name, int base, int irq, int dma, int dma2) { @@ -734,3 +736,5 @@ void conf_printf2(char *name, int base, int irq, int dma, int dma2) printk("\n"); #endif } +EXPORT_SYMBOL(conf_printf2); + -- GitLab From 5b9b5572c87b460cd91f7722ac233d1873cfb084 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 4 Oct 2006 02:17:32 -0700 Subject: [PATCH 0582/1619] [PATCH] git-powerpc: wrapper: don't require execute permissions If you lose the x bit (eg: by using patch(1)), powerpc won't build. Be defensive about it... Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index c383d56bbe1..003520b5630 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -113,7 +113,7 @@ endif endif quiet_cmd_wrap = WRAP $@ - cmd_wrap =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux + cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux quiet_cmd_wrap_initrd = WRAP $@ cmd_wrap_initrd =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \ -i $(obj)/ramdisk.image.gz vmlinux -- GitLab From 11966adc33fa1504c2d9a78e6fc129e5c87bdee1 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 04:41:53 -0400 Subject: [PATCH 0583/1619] [PATCH] RTC: build fixes Fix obvious build breakage revealed by 'make allyesconfig' in current -git. Signed-off-by: Jeff Garzik Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1307.c | 6 +++--- drivers/rtc/rtc-ds1672.c | 4 ++-- drivers/rtc/rtc-rs5c372.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index cc5032b6f42..3f0f7b8fa81 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -141,9 +141,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) dev_dbg(dev, "%s secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", - "write", dt->tm_sec, dt->tm_min, - dt->tm_hour, dt->tm_mday, - dt->tm_mon, dt->tm_year, dt->tm_wday); + "write", t->tm_sec, t->tm_min, + t->tm_hour, t->tm_mday, + t->tm_mon, t->tm_year, t->tm_wday); *buf++ = 0; /* first register addr */ buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec); diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 9c68ec99afa..67e816a9a39 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -55,7 +55,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) } dev_dbg(&client->dev, - "%s: raw read data - counters=%02x,%02x,%02x,%02x\n" + "%s: raw read data - counters=%02x,%02x,%02x,%02x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; @@ -96,7 +96,7 @@ static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm) unsigned long secs; dev_dbg(&client->dev, - "%s: secs=%d, mins=%d, hours=%d, ", + "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index bbdad099471..2a86632580f 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -91,7 +91,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) unsigned char buf[8] = { RS5C372_REG_BASE }; dev_dbg(&client->dev, - "%s: secs=%d, mins=%d, hours=%d ", + "%s: secs=%d, mins=%d, hours=%d " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -126,7 +126,7 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) return -EIO; } - dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim); + dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim); if (osc) *osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768; -- GitLab From a0a00cbf8ae5cea3d72e28982c06f3270420c657 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 4 Oct 2006 12:47:14 +0100 Subject: [PATCH 0584/1619] [PATCH] pata: teach ali about rev C8, keep pcmcia driver in sync This fixes support for rev c8 of the ALi/ULi PATA, and keeps pcmcia in sync so ide_cs and pata_pcmcia are interchangable, both are only changes to constants. Right now rev 0xC8 and higher don't work with libata but 0xc8 is in the field now. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/ata/pata_ali.c | 4 ++-- drivers/ata/pata_pcmcia.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 3f49e38217d..1d695df5860 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.6.5" +#define DRV_VERSION "0.6.6" /* * Cable special cases @@ -630,7 +630,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_read_config_byte(pdev, 0x53, &tmp); if (rev <= 0x20) tmp &= ~0x02; - if (rev == 0xc7) + if (rev >= 0xc7) tmp |= 0x03; else tmp |= 0x01; /* CD_ROM enable for DMA */ diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index cb501e145a4..e93ea2702c7 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -42,7 +42,7 @@ #define DRV_NAME "pata_pcmcia" -#define DRV_VERSION "0.2.9" +#define DRV_VERSION "0.2.11" /* * Private data structure to glue stuff together @@ -355,6 +355,8 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d), PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6), PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), + PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), -- GitLab From 7009af8cd37f7904939aec6bd2325c581abd7cac Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Wed, 4 Oct 2006 19:19:58 +0400 Subject: [PATCH 0585/1619] [MIPS] PNX8550 fixups This patch fixes the compilation errors on PNX8550 and hard-to-track bug in interrupt handling. It also corresponds to the latest changes in PNX8550 serial driver. Signed-off-by: Vitaly Wool Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 2 -- arch/mips/philips/pnx8550/common/int.c | 2 +- arch/mips/philips/pnx8550/common/platform.c | 16 ++++++---------- arch/mips/philips/pnx8550/common/prom.c | 4 ++-- arch/mips/philips/pnx8550/common/setup.c | 6 +++--- include/asm-mips/mach-pnx8550/uart.h | 14 ++++++++++++++ 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index bfab055ad7c..8a49884bd5e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -440,13 +440,11 @@ config MIPS_XXS1500 config PNX8550_V2PCI bool "Philips PNX8550 based Viper2-PCI board" - depends on BROKEN select PNX8550 select SYS_SUPPORTS_LITTLE_ENDIAN config PNX8550_JBS bool "Philips PNX8550 based JBS board" - depends on BROKEN select PNX8550 select SYS_SUPPORTS_LITTLE_ENDIAN diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c index 099679a9dfb..3c93512be1e 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/philips/pnx8550/common/int.c @@ -90,7 +90,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP2) - do_IRQ(2, regs); + hw0_irqdispatch(2, regs); else if (pending & STATUSF_IP7) { if (read_c0_config7() & 0x01c0) timer_irqdispatch(7, regs); diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/philips/pnx8550/common/platform.c index 5436b4b9745..d43f56e2cd7 100644 --- a/arch/mips/philips/pnx8550/common/platform.c +++ b/arch/mips/philips/pnx8550/common/platform.c @@ -17,15 +17,13 @@ #include #include #include -#include +#include #include #include #include #include -extern struct uart_ops ip3106_pops; - static struct resource pnx8550_usb_ohci_resources[] = { [0] = { .start = PNX8550_USB_OHCI_OP_BASE, @@ -63,31 +61,29 @@ static struct resource pnx8550_uart_resources[] = { }, }; -struct ip3106_port ip3106_ports[] = { +struct pnx8xxx_port pnx8xxx_ports[] = { [0] = { .port = { - .type = PORT_IP3106, + .type = PORT_PNX8XXX, .iotype = UPIO_MEM, .membase = (void __iomem *)PNX8550_UART_PORT0, .mapbase = PNX8550_UART_PORT0, .irq = PNX8550_UART_INT(0), .uartclk = 3692300, .fifosize = 16, - .ops = &ip3106_pops, .flags = UPF_BOOT_AUTOCONF, .line = 0, }, }, [1] = { .port = { - .type = PORT_IP3106, + .type = PORT_PNX8XXX, .iotype = UPIO_MEM, .membase = (void __iomem *)PNX8550_UART_PORT1, .mapbase = PNX8550_UART_PORT1, .irq = PNX8550_UART_INT(1), .uartclk = 3692300, .fifosize = 16, - .ops = &ip3106_pops, .flags = UPF_BOOT_AUTOCONF, .line = 1, }, @@ -111,12 +107,12 @@ static struct platform_device pnx8550_usb_ohci_device = { }; static struct platform_device pnx8550_uart_device = { - .name = "ip3106-uart", + .name = "pnx8xxx-uart", .id = -1, .dev = { .dma_mask = &uart_dmamask, .coherent_dma_mask = 0xffffffff, - .platform_data = ip3106_ports, + .platform_data = pnx8xxx_ports, }, .num_resources = ARRAY_SIZE(pnx8550_uart_resources), .resource = pnx8550_uart_resources, diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c index 70aac975941..f8952c1359c 100644 --- a/arch/mips/philips/pnx8550/common/prom.c +++ b/arch/mips/philips/pnx8550/common/prom.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -126,7 +126,7 @@ void prom_putchar(char c) { if (pnx8550_console_port != -1) { /* Wait until FIFO not full */ - while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & IP3106_UART_FIFO_TXFIFO) >> 16) >= 16) + while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & PNX8XXX_UART_FIFO_TXFIFO) >> 16) >= 16) ; /* Send one char */ ip3106_fifo(UART_BASE, pnx8550_console_port) = c; diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c index 36b0c8bc6c0..e62123ca9b6 100644 --- a/arch/mips/philips/pnx8550/common/setup.c +++ b/arch/mips/philips/pnx8550/common/setup.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -56,7 +56,7 @@ extern char *prom_getcmdline(void); struct resource standard_io_resources[] = { { - .start = .0x00, + .start = 0x00, .end = 0x1f, .name = "dma1", .flags = IORESOURCE_BUSY @@ -144,7 +144,7 @@ void __init plat_mem_setup(void) /* We must initialize the UART (console) before prom_printf */ /* Set LCR to 8-bit and BAUD to 38400 (no 5) */ ip3106_lcr(UART_BASE, pnx8550_console_port) = - IP3106_UART_LCR_8BIT; + PNX8XXX_UART_LCR_8BIT; ip3106_baud(UART_BASE, pnx8550_console_port) = 5; } diff --git a/include/asm-mips/mach-pnx8550/uart.h b/include/asm-mips/mach-pnx8550/uart.h index e32b9a23d70..814a7a15ab4 100644 --- a/include/asm-mips/mach-pnx8550/uart.h +++ b/include/asm-mips/mach-pnx8550/uart.h @@ -13,4 +13,18 @@ #define PNX8550_UART_INT(x) (PNX8550_INT_GIC_MIN+19+x) #define IRQ_TO_UART(x) (x-PNX8550_INT_GIC_MIN-19) +/* early macros needed for prom/kgdb */ + +#define ip3106_lcr(base,port) *(volatile u32 *)(base+(port*0x1000) + 0x000) +#define ip3106_mcr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x004) +#define ip3106_baud(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x008) +#define ip3106_cfg(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x00C) +#define ip3106_fifo(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x028) +#define ip3106_istat(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE0) +#define ip3106_ien(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE4) +#define ip3106_iclr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE8) +#define ip3106_iset(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFEC) +#define ip3106_pd(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFF4) +#define ip3106_mid(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFFC) + #endif -- GitLab From c4710e65c005339b5979fa258bf89940dc2a700b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 4 Oct 2006 17:32:21 +0100 Subject: [PATCH 0586/1619] [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(-) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index ea005c0a79f..5114ff18101 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 -- GitLab From 5b34821a601ea079184efba2f9c7c7af61241bde Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:00 +0200 Subject: [PATCH 0587/1619] [PATCH] at91_serial -> atmel_serial: at91rm9200_usart.h Move include/asm/arch/at91rm9200_usart.h into drivers/serial and rename it atmel_usart.h. Also delete AVR32's version of this file. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/at91_serial.c | 3 +- .../serial/atmel_serial.h | 2 +- .../asm-avr32/arch-at32ap/at91rm9200_usart.h | 123 ------------------ 3 files changed, 3 insertions(+), 125 deletions(-) rename include/asm-arm/arch-at91rm9200/at91rm9200_usart.h => drivers/serial/atmel_serial.h (99%) delete mode 100644 include/asm-avr32/arch-at32ap/at91rm9200_usart.h diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c index bf4bf103e5a..3b420aeafc2 100644 --- a/drivers/serial/at91_serial.c +++ b/drivers/serial/at91_serial.c @@ -36,13 +36,14 @@ #include -#include #include #include #include #include #include +#include "atmel_serial.h" + #if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h b/drivers/serial/atmel_serial.h similarity index 99% rename from include/asm-arm/arch-at91rm9200/at91rm9200_usart.h rename to drivers/serial/atmel_serial.h index 79f851e31b9..d38b24a5337 100644 --- a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h +++ b/drivers/serial/atmel_serial.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h + * drivers/serial/atmel_serial.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People diff --git a/include/asm-avr32/arch-at32ap/at91rm9200_usart.h b/include/asm-avr32/arch-at32ap/at91rm9200_usart.h deleted file mode 100644 index 79f851e31b9..00000000000 --- a/include/asm-avr32/arch-at32ap/at91rm9200_usart.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * USART registers. - * Based on AT91RM9200 datasheet revision E. - * - * 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 AT91RM9200_USART_H -#define AT91RM9200_USART_H - -#define AT91_US_CR 0x00 /* Control Register */ -#define AT91_US_RSTRX (1 << 2) /* Reset Receiver */ -#define AT91_US_RSTTX (1 << 3) /* Reset Transmitter */ -#define AT91_US_RXEN (1 << 4) /* Receiver Enable */ -#define AT91_US_RXDIS (1 << 5) /* Receiver Disable */ -#define AT91_US_TXEN (1 << 6) /* Transmitter Enable */ -#define AT91_US_TXDIS (1 << 7) /* Transmitter Disable */ -#define AT91_US_RSTSTA (1 << 8) /* Reset Status Bits */ -#define AT91_US_STTBRK (1 << 9) /* Start Break */ -#define AT91_US_STPBRK (1 << 10) /* Stop Break */ -#define AT91_US_STTTO (1 << 11) /* Start Time-out */ -#define AT91_US_SENDA (1 << 12) /* Send Address */ -#define AT91_US_RSTIT (1 << 13) /* Reset Iterations */ -#define AT91_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ -#define AT91_US_RETTO (1 << 15) /* Rearm Time-out */ -#define AT91_US_DTREN (1 << 16) /* Data Terminal Ready Enable */ -#define AT91_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */ -#define AT91_US_RTSEN (1 << 18) /* Request To Send Enable */ -#define AT91_US_RTSDIS (1 << 19) /* Request To Send Disable */ - -#define AT91_US_MR 0x04 /* Mode Register */ -#define AT91_US_USMODE (0xf << 0) /* Mode of the USART */ -#define AT91_US_USMODE_NORMAL 0 -#define AT91_US_USMODE_RS485 1 -#define AT91_US_USMODE_HWHS 2 -#define AT91_US_USMODE_MODEM 3 -#define AT91_US_USMODE_ISO7816_T0 4 -#define AT91_US_USMODE_ISO7816_T1 6 -#define AT91_US_USMODE_IRDA 8 -#define AT91_US_USCLKS (3 << 4) /* Clock Selection */ -#define AT91_US_CHRL (3 << 6) /* Character Length */ -#define AT91_US_CHRL_5 (0 << 6) -#define AT91_US_CHRL_6 (1 << 6) -#define AT91_US_CHRL_7 (2 << 6) -#define AT91_US_CHRL_8 (3 << 6) -#define AT91_US_SYNC (1 << 8) /* Synchronous Mode Select */ -#define AT91_US_PAR (7 << 9) /* Parity Type */ -#define AT91_US_PAR_EVEN (0 << 9) -#define AT91_US_PAR_ODD (1 << 9) -#define AT91_US_PAR_SPACE (2 << 9) -#define AT91_US_PAR_MARK (3 << 9) -#define AT91_US_PAR_NONE (4 << 9) -#define AT91_US_PAR_MULTI_DROP (6 << 9) -#define AT91_US_NBSTOP (3 << 12) /* Number of Stop Bits */ -#define AT91_US_NBSTOP_1 (0 << 12) -#define AT91_US_NBSTOP_1_5 (1 << 12) -#define AT91_US_NBSTOP_2 (2 << 12) -#define AT91_US_CHMODE (3 << 14) /* Channel Mode */ -#define AT91_US_CHMODE_NORMAL (0 << 14) -#define AT91_US_CHMODE_ECHO (1 << 14) -#define AT91_US_CHMODE_LOC_LOOP (2 << 14) -#define AT91_US_CHMODE_REM_LOOP (3 << 14) -#define AT91_US_MSBF (1 << 16) /* Bit Order */ -#define AT91_US_MODE9 (1 << 17) /* 9-bit Character Length */ -#define AT91_US_CLKO (1 << 18) /* Clock Output Select */ -#define AT91_US_OVER (1 << 19) /* Oversampling Mode */ -#define AT91_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ -#define AT91_US_DSNACK (1 << 21) /* Disable Successive NACK */ -#define AT91_US_MAX_ITER (7 << 24) /* Max Iterations */ -#define AT91_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ - -#define AT91_US_IER 0x08 /* Interrupt Enable Register */ -#define AT91_US_RXRDY (1 << 0) /* Receiver Ready */ -#define AT91_US_TXRDY (1 << 1) /* Transmitter Ready */ -#define AT91_US_RXBRK (1 << 2) /* Break Received / End of Break */ -#define AT91_US_ENDRX (1 << 3) /* End of Receiver Transfer */ -#define AT91_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ -#define AT91_US_OVRE (1 << 5) /* Overrun Error */ -#define AT91_US_FRAME (1 << 6) /* Framing Error */ -#define AT91_US_PARE (1 << 7) /* Parity Error */ -#define AT91_US_TIMEOUT (1 << 8) /* Receiver Time-out */ -#define AT91_US_TXEMPTY (1 << 9) /* Transmitter Empty */ -#define AT91_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ -#define AT91_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ -#define AT91_US_RXBUFF (1 << 12) /* Reception Buffer Full */ -#define AT91_US_NACK (1 << 13) /* Non Acknowledge */ -#define AT91_US_RIIC (1 << 16) /* Ring Indicator Input Change */ -#define AT91_US_DSRIC (1 << 17) /* Data Set Ready Input Change */ -#define AT91_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */ -#define AT91_US_CTSIC (1 << 19) /* Clear to Send Input Change */ -#define AT91_US_RI (1 << 20) /* RI */ -#define AT91_US_DSR (1 << 21) /* DSR */ -#define AT91_US_DCD (1 << 22) /* DCD */ -#define AT91_US_CTS (1 << 23) /* CTS */ - -#define AT91_US_IDR 0x0c /* Interrupt Disable Register */ -#define AT91_US_IMR 0x10 /* Interrupt Mask Register */ -#define AT91_US_CSR 0x14 /* Channel Status Register */ -#define AT91_US_RHR 0x18 /* Receiver Holding Register */ -#define AT91_US_THR 0x1c /* Transmitter Holding Register */ - -#define AT91_US_BRGR 0x20 /* Baud Rate Generator Register */ -#define AT91_US_CD (0xffff << 0) /* Clock Divider */ - -#define AT91_US_RTOR 0x24 /* Receiver Time-out Register */ -#define AT91_US_TO (0xffff << 0) /* Time-out Value */ - -#define AT91_US_TTGR 0x28 /* Transmitter Timeguard Register */ -#define AT91_US_TG (0xff << 0) /* Timeguard Value */ - -#define AT91_US_FIDI 0x40 /* FI DI Ratio Register */ -#define AT91_US_NER 0x44 /* Number of Errors Register */ -#define AT91_US_IF 0x4c /* IrDA Filter Register */ - -#endif -- GitLab From b6156b4e2e3b725ae3549882f59c82ab5b5048a5 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:01 +0200 Subject: [PATCH 0588/1619] [PATCH] at91_serial -> atmel_serial: at91_serial.c Rename at91_serial.c atmel_serial.c Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/Makefile | 2 +- drivers/serial/{at91_serial.c => atmel_serial.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/serial/{at91_serial.c => atmel_serial.c} (100%) diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 927faee0362..e49808ab4b0 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -54,5 +54,5 @@ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o 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_AT91) += at91_serial.o +obj-$(CONFIG_SERIAL_AT91) += atmel_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o diff --git a/drivers/serial/at91_serial.c b/drivers/serial/atmel_serial.c similarity index 100% rename from drivers/serial/at91_serial.c rename to drivers/serial/atmel_serial.c -- GitLab From 749c4e60334580ee0f1427eb90ad006fecbffd21 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:02 +0200 Subject: [PATCH 0589/1619] [PATCH] at91_serial -> atmel_serial: Kconfig symbols Rename the following Kconfig symbols: * CONFIG_SERIAL_AT91 -> CONFIG_SERIAL_ATMEL * CONFIG_SERIAL_AT91_CONSOLE -> CONFIG_SERIAL_ATMEL_CONSOLE * CONFIG_SERIAL_AT91_TTYAT -> CONFIG_SERIAL_ATMEL_TTYAT Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- arch/arm/configs/at91rm9200dk_defconfig | 6 +++--- arch/arm/configs/at91rm9200ek_defconfig | 6 +++--- arch/arm/configs/ateb9200_defconfig | 6 +++--- arch/arm/configs/carmeva_defconfig | 4 ++-- arch/arm/configs/csb337_defconfig | 6 +++--- arch/arm/configs/csb637_defconfig | 6 +++--- arch/arm/configs/kafa_defconfig | 6 +++--- arch/arm/configs/kb9202_defconfig | 4 ++-- arch/arm/configs/onearm_defconfig | 6 +++--- arch/arm/mach-at91rm9200/devices.c | 2 +- arch/avr32/configs/atstk1002_defconfig | 6 +++--- drivers/serial/Kconfig | 14 +++++++------- drivers/serial/Makefile | 2 +- drivers/serial/atmel_serial.c | 6 +++--- include/asm-arm/mach/serial_at91.h | 2 +- include/asm-avr32/mach/serial_at91.h | 2 +- 16 files changed, 42 insertions(+), 42 deletions(-) diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig index 4f3d8d37741..c82e4667f45 100644 --- a/arch/arm/configs/at91rm9200dk_defconfig +++ b/arch/arm/configs/at91rm9200dk_defconfig @@ -553,9 +553,9 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig index 08b5dc38876..b983fc59aa4 100644 --- a/arch/arm/configs/at91rm9200ek_defconfig +++ b/arch/arm/configs/at91rm9200ek_defconfig @@ -534,9 +534,9 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/ateb9200_defconfig b/arch/arm/configs/ateb9200_defconfig index bee7813d040..15e6b0bbbde 100644 --- a/arch/arm/configs/ateb9200_defconfig +++ b/arch/arm/configs/ateb9200_defconfig @@ -656,9 +656,9 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/carmeva_defconfig b/arch/arm/configs/carmeva_defconfig index 8a075c8ecc6..d24ae8777c3 100644 --- a/arch/arm/configs/carmeva_defconfig +++ b/arch/arm/configs/carmeva_defconfig @@ -455,8 +455,8 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig index cf3fa5cb26e..a2d6fd398f1 100644 --- a/arch/arm/configs/csb337_defconfig +++ b/arch/arm/configs/csb337_defconfig @@ -591,9 +591,9 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig index 640d70c1f06..2a1ac6c60ab 100644 --- a/arch/arm/configs/csb637_defconfig +++ b/arch/arm/configs/csb637_defconfig @@ -591,9 +591,9 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig index 1db633e2c94..54fcd75779d 100644 --- a/arch/arm/configs/kafa_defconfig +++ b/arch/arm/configs/kafa_defconfig @@ -536,9 +536,9 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/kb9202_defconfig b/arch/arm/configs/kb9202_defconfig index 45396e08719..b4cd4b41483 100644 --- a/arch/arm/configs/kb9202_defconfig +++ b/arch/arm/configs/kb9202_defconfig @@ -418,8 +418,8 @@ CONFIG_HW_CONSOLE=y # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig index 6a93e3aae10..cb1d94f9049 100644 --- a/arch/arm/configs/onearm_defconfig +++ b/arch/arm/configs/onearm_defconfig @@ -583,9 +583,9 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index 01525530c28..2d6b8b3a74a 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -544,7 +544,7 @@ void __init at91_init_leds(u8 cpu_led, u8 timer_led) {} * UART * -------------------------------------------------------------------- */ -#if defined(CONFIG_SERIAL_AT91) +#if defined(CONFIG_SERIAL_ATMEL) static struct resource dbgu_resources[] = { [0] = { .start = AT91_VA_BASE_SYS + AT91_DBGU, diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig index 1d22255009f..6c2c5e00dfc 100644 --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig @@ -385,9 +385,9 @@ CONFIG_PPP_DEFLATE=m # # Non-8250 serial port support # -CONFIG_SERIAL_AT91=y -CONFIG_SERIAL_AT91_CONSOLE=y -# CONFIG_SERIAL_AT91_TTYAT is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 8edee745888..ba19ab571f9 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -299,17 +299,17 @@ config SERIAL_AMBA_PL011_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_AT91 - bool "AT91RM9200 / AT91SAM9261 serial port support" +config SERIAL_ATMEL + bool "AT91 / AT32 on-chip serial port support" depends on ARM && (ARCH_AT91RM9200 || ARCH_AT91SAM9261) select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Atmel AT91RM9200 and AT91SAM926 processor. -config SERIAL_AT91_CONSOLE - bool "Support for console on AT91RM9200 / AT91SAM9261 serial port" - depends on SERIAL_AT91=y +config SERIAL_ATMEL_CONSOLE + bool "Support for console on AT91 / AT32 serial port" + depends on SERIAL_ATMEL=y select SERIAL_CORE_CONSOLE help Say Y here if you wish to use a UART on the Atmel AT91RM9200 or @@ -317,9 +317,9 @@ config SERIAL_AT91_CONSOLE which receives all kernel messages and warnings and which allows logins in single user mode). -config SERIAL_AT91_TTYAT +config SERIAL_ATMEL_TTYAT bool "Install as device ttyAT0-4 instead of ttyS0-4" - depends on SERIAL_AT91=y + depends on SERIAL_ATMEL=y help Say Y here if you wish to have the five internal AT91RM9200 UARTs appear as /dev/ttyAT0-4 (major 204, minor 154-158) instead of the diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index e49808ab4b0..b4d8a7c182e 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -54,5 +54,5 @@ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o 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_AT91) += atmel_serial.o +obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 3b420aeafc2..b96382da27e 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -44,13 +44,13 @@ #include "atmel_serial.h" -#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif #include -#ifdef CONFIG_SERIAL_AT91_TTYAT +#ifdef CONFIG_SERIAL_ATMEL_TTYAT /* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we * should coexist with the 8250 driver, such as if we have an external 16C550 @@ -726,7 +726,7 @@ void __init at91_register_uart_fns(struct at91_port_fns *fns) } -#ifdef CONFIG_SERIAL_AT91_CONSOLE +#ifdef CONFIG_SERIAL_ATMEL_CONSOLE static void at91_console_putchar(struct uart_port *port, int ch) { while (!(UART_GET_CSR(port) & AT91_US_TXRDY)) diff --git a/include/asm-arm/mach/serial_at91.h b/include/asm-arm/mach/serial_at91.h index 1290bb32802..239e1f65d67 100644 --- a/include/asm-arm/mach/serial_at91.h +++ b/include/asm-arm/mach/serial_at91.h @@ -24,7 +24,7 @@ struct at91_port_fns { void (*close)(struct uart_port *); }; -#if defined(CONFIG_SERIAL_AT91) +#if defined(CONFIG_SERIAL_ATMEL) void at91_register_uart_fns(struct at91_port_fns *fns); #else #define at91_register_uart_fns(fns) do { } while (0) diff --git a/include/asm-avr32/mach/serial_at91.h b/include/asm-avr32/mach/serial_at91.h index 1290bb32802..239e1f65d67 100644 --- a/include/asm-avr32/mach/serial_at91.h +++ b/include/asm-avr32/mach/serial_at91.h @@ -24,7 +24,7 @@ struct at91_port_fns { void (*close)(struct uart_port *); }; -#if defined(CONFIG_SERIAL_AT91) +#if defined(CONFIG_SERIAL_ATMEL) void at91_register_uart_fns(struct at91_port_fns *fns); #else #define at91_register_uart_fns(fns) do { } while (0) -- GitLab From 1e8ea80219564c3433dbca7afe075ced9eb8117c Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:03 +0200 Subject: [PATCH 0590/1619] [PATCH] at91_serial -> atmel_serial: Platform device name Rename the "at91_usart" platform driver "atmel_usart" and update platform devices accordingly. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- arch/arm/mach-at91rm9200/devices.c | 10 ++++---- arch/avr32/mach-at32ap/at32ap7000.c | 40 ++++++++++++++--------------- drivers/serial/atmel_serial.c | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index 2d6b8b3a74a..28fd4b8f474 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -564,7 +564,7 @@ static struct at91_uart_data dbgu_data = { }; static struct platform_device at91rm9200_dbgu_device = { - .name = "at91_usart", + .name = "atmel_usart", .id = 0, .dev = { .platform_data = &dbgu_data, @@ -599,7 +599,7 @@ static struct at91_uart_data uart0_data = { }; static struct platform_device at91rm9200_uart0_device = { - .name = "at91_usart", + .name = "atmel_usart", .id = 1, .dev = { .platform_data = &uart0_data, @@ -641,7 +641,7 @@ static struct at91_uart_data uart1_data = { }; static struct platform_device at91rm9200_uart1_device = { - .name = "at91_usart", + .name = "atmel_usart", .id = 2, .dev = { .platform_data = &uart1_data, @@ -682,7 +682,7 @@ static struct at91_uart_data uart2_data = { }; static struct platform_device at91rm9200_uart2_device = { - .name = "at91_usart", + .name = "atmel_usart", .id = 3, .dev = { .platform_data = &uart2_data, @@ -717,7 +717,7 @@ static struct at91_uart_data uart3_data = { }; static struct platform_device at91rm9200_uart3_device = { - .name = "at91_usart", + .name = "atmel_usart", .id = 4, .dev = { .platform_data = &uart3_data, diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 37982b60398..842e7be7fb5 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -523,33 +523,33 @@ void __init at32_add_system_devices(void) * USART * -------------------------------------------------------------------- */ -static struct resource usart0_resource[] = { +static struct resource atmel_usart0_resource[] = { PBMEM(0xffe00c00), IRQ(7), }; -DEFINE_DEV(usart, 0); -DEV_CLK(usart, usart0, pba, 4); +DEFINE_DEV(atmel_usart, 0); +DEV_CLK(usart, atmel_usart0, pba, 4); -static struct resource usart1_resource[] = { +static struct resource atmel_usart1_resource[] = { PBMEM(0xffe01000), IRQ(7), }; -DEFINE_DEV(usart, 1); -DEV_CLK(usart, usart1, pba, 4); +DEFINE_DEV(atmel_usart, 1); +DEV_CLK(usart, atmel_usart1, pba, 4); -static struct resource usart2_resource[] = { +static struct resource atmel_usart2_resource[] = { PBMEM(0xffe01400), IRQ(8), }; -DEFINE_DEV(usart, 2); -DEV_CLK(usart, usart2, pba, 5); +DEFINE_DEV(atmel_usart, 2); +DEV_CLK(usart, atmel_usart2, pba, 5); -static struct resource usart3_resource[] = { +static struct resource atmel_usart3_resource[] = { PBMEM(0xffe01800), IRQ(9), }; -DEFINE_DEV(usart, 3); -DEV_CLK(usart, usart3, pba, 6); +DEFINE_DEV(atmel_usart, 3); +DEV_CLK(usart, atmel_usart3, pba, 6); static inline void configure_usart0_pins(void) { @@ -581,19 +581,19 @@ static struct platform_device *setup_usart(unsigned int id) switch (id) { case 0: - pdev = &usart0_device; + pdev = &atmel_usart0_device; configure_usart0_pins(); break; case 1: - pdev = &usart1_device; + pdev = &atmel_usart1_device; configure_usart1_pins(); break; case 2: - pdev = &usart2_device; + pdev = &atmel_usart2_device; configure_usart2_pins(); break; case 3: - pdev = &usart3_device; + pdev = &atmel_usart3_device; configure_usart3_pins(); break; default: @@ -813,10 +813,10 @@ struct clk *at32_clock_list[] = { &pio1_mck, &pio2_mck, &pio3_mck, - &usart0_usart, - &usart1_usart, - &usart2_usart, - &usart3_usart, + &atmel_usart0_usart, + &atmel_usart1_usart, + &atmel_usart2_usart, + &atmel_usart3_usart, &macb0_hclk, &macb0_pclk, &spi0_mck, diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index b96382da27e..f14a07ed60b 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -947,7 +947,7 @@ static struct platform_driver at91_serial_driver = { .suspend = at91_serial_suspend, .resume = at91_serial_resume, .driver = { - .name = "at91_usart", + .name = "atmel_usart", .owner = THIS_MODULE, }, }; -- GitLab From 73e2798b0f3f4fa8ff7d3e8138027a8352359bb5 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:04 +0200 Subject: [PATCH 0591/1619] [PATCH] at91_serial -> atmel_serial: Public definitions Rename the following public definitions: * AT91_NR_UART -> ATMEL_MAX_UART * struct at91_uart_data -> struct atmel_uart_data * at91_default_console_device -> atmel_default_console_device Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- arch/arm/mach-at91rm9200/devices.c | 22 +++++++++++----------- arch/avr32/mach-at32ap/at32ap7000.c | 4 ++-- drivers/serial/atmel_serial.c | 14 +++++++------- include/asm-arm/arch-at91rm9200/board.h | 4 ++-- include/asm-arm/arch-at91rm9200/hardware.h | 2 +- include/asm-avr32/arch-at32ap/board.h | 4 ++-- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index 28fd4b8f474..5a3919f09d4 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -558,7 +558,7 @@ static struct resource dbgu_resources[] = { }, }; -static struct at91_uart_data dbgu_data = { +static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ }; @@ -593,7 +593,7 @@ static struct resource uart0_resources[] = { }, }; -static struct at91_uart_data uart0_data = { +static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, }; @@ -635,7 +635,7 @@ static struct resource uart1_resources[] = { }, }; -static struct at91_uart_data uart1_data = { +static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, }; @@ -676,7 +676,7 @@ static struct resource uart2_resources[] = { }, }; -static struct at91_uart_data uart2_data = { +static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, }; @@ -711,7 +711,7 @@ static struct resource uart3_resources[] = { }, }; -static struct at91_uart_data uart3_data = { +static struct atmel_uart_data uart3_data = { .use_dma_tx = 1, .use_dma_rx = 1, }; @@ -733,8 +733,8 @@ static inline void configure_usart3_pins(void) at91_set_B_periph(AT91_PIN_PA6, 0); /* RXD3 */ } -struct platform_device *at91_uarts[AT91_NR_UART]; /* the UARTs to use */ -struct platform_device *at91_default_console_device; /* the serial console device */ +struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ +struct platform_device *atmel_default_console_device; /* the serial console device */ void __init at91_init_serial(struct at91_uart_config *config) { @@ -775,9 +775,9 @@ void __init at91_init_serial(struct at91_uart_config *config) } /* Set serial console device */ - if (config->console_tty < AT91_NR_UART) - at91_default_console_device = at91_uarts[config->console_tty]; - if (!at91_default_console_device) + if (config->console_tty < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[config->console_tty]; + if (!atmel_default_console_device) printk(KERN_INFO "AT91: No default serial console defined.\n"); } @@ -785,7 +785,7 @@ void __init at91_add_device_serial(void) { int i; - for (i = 0; i < AT91_NR_UART; i++) { + for (i = 0; i < ATMEL_MAX_UART; i++) { if (at91_uarts[i]) platform_device_register(at91_uarts[i]); } diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 842e7be7fb5..05d1296bd7b 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -615,11 +615,11 @@ struct platform_device *__init at32_add_device_usart(unsigned int id) return pdev; } -struct platform_device *at91_default_console_device; +struct platform_device *atmel_default_console_device; void __init at32_setup_serial_console(unsigned int usart_id) { - at91_default_console_device = setup_usart(usart_id); + atmel_default_console_device = setup_usart(usart_id); } /* -------------------------------------------------------------------- diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index f14a07ed60b..65972ce63c7 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -113,7 +113,7 @@ struct at91_uart_port { unsigned short suspended; /* is port suspended? */ }; -static struct at91_uart_port at91_ports[AT91_NR_UART]; +static struct at91_uart_port at91_ports[ATMEL_MAX_UART]; #ifdef SUPPORT_SYSRQ static struct console at91_console; @@ -682,7 +682,7 @@ static struct uart_ops at91_pops = { static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct platform_device *pdev) { struct uart_port *port = &at91_port->uart; - struct at91_uart_data *data = pdev->dev.platform_data; + struct atmel_uart_data *data = pdev->dev.platform_data; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; @@ -834,9 +834,9 @@ static struct console at91_console = { */ static int __init at91_console_init(void) { - if (at91_default_console_device) { - add_preferred_console(AT91_DEVICENAME, at91_default_console_device->id, NULL); - at91_init_port(&(at91_ports[at91_default_console_device->id]), at91_default_console_device); + if (atmel_default_console_device) { + add_preferred_console(AT91_DEVICENAME, atmel_default_console_device->id, NULL); + at91_init_port(&(at91_ports[atmel_default_console_device->id]), atmel_default_console_device); register_console(&at91_console); } @@ -849,7 +849,7 @@ console_initcall(at91_console_init); */ static int __init at91_late_console_init(void) { - if (at91_default_console_device && !(at91_console.flags & CON_ENABLED)) + if (atmel_default_console_device && !(at91_console.flags & CON_ENABLED)) register_console(&at91_console); return 0; @@ -866,7 +866,7 @@ static struct uart_driver at91_uart = { .dev_name = AT91_DEVICENAME, .major = SERIAL_AT91_MAJOR, .minor = MINOR_START, - .nr = AT91_NR_UART, + .nr = ATMEL_MAX_UART, .cons = AT91_CONSOLE_DEVICE, }; diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h index c1ca9a4658e..d56527055c9 100644 --- a/include/asm-arm/arch-at91rm9200/board.h +++ b/include/asm-arm/arch-at91rm9200/board.h @@ -97,10 +97,10 @@ struct at91_uart_config { unsigned short nr_tty; /* number of serial tty's */ short tty_map[]; /* map UART to tty number */ }; -extern struct platform_device *at91_default_console_device; +extern struct platform_device *atmel_default_console_device; extern void __init at91_init_serial(struct at91_uart_config *config); -struct at91_uart_data { +struct atmel_uart_data { short use_dma_tx; /* use transmit DMA? */ short use_dma_rx; /* use receive DMA? */ }; diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h index 6551b4d1ff7..9ca4cc9c0b2 100644 --- a/include/asm-arm/arch-at91rm9200/hardware.h +++ b/include/asm-arm/arch-at91rm9200/hardware.h @@ -44,7 +44,7 @@ #define AT91_SRAM_VIRT_BASE (AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE) /* Serial ports */ -#define AT91_NR_UART 5 /* 4 USART3's and one DBGU port */ +#define ATMEL_MAX_UART 5 /* 4 USART3's and one DBGU port */ /* FLASH */ #define AT91_FLASH_BASE 0x10000000 /* NCS0: Flash physical base address */ diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index 39368e18ab2..82e5404d2f4 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -9,8 +9,8 @@ /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */ void at32_add_system_devices(void); -#define AT91_NR_UART 4 -extern struct platform_device *at91_default_console_device; +#define ATMEL_MAX_UART 4 +extern struct platform_device *atmel_default_console_device; struct platform_device *at32_add_device_usart(unsigned int id); -- GitLab From 7192f92c799e4bf4943e3e233d6e4d786ac4d8a4 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:05 +0200 Subject: [PATCH 0592/1619] [PATCH] at91_serial -> atmel_serial: Internal names Prefix all internal functions and variables with atmel_ instead of at91_. The at91_register_uart_fns() stuff is left as is since I can't find any actual users of it. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/atmel_serial.c | 496 +++++++++++++++++----------------- drivers/serial/atmel_serial.h | 196 +++++++------- 2 files changed, 346 insertions(+), 346 deletions(-) diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 65972ce63c7..7397d5df6d9 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/at91_serial.c * - * Driver for Atmel AT91RM9200 Serial ports + * Driver for Atmel AT91 / AT32 Serial ports * Copyright (C) 2003 Rick Bronson * * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. @@ -55,51 +55,51 @@ /* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we * should coexist with the 8250 driver, such as if we have an external 16C550 * UART. */ -#define SERIAL_AT91_MAJOR 204 +#define SERIAL_ATMEL_MAJOR 204 #define MINOR_START 154 -#define AT91_DEVICENAME "ttyAT" +#define ATMEL_DEVICENAME "ttyAT" #else /* Use device name ttyS, major 4, minor 64-68. This is the usual serial port * name, but it is legally reserved for the 8250 driver. */ -#define SERIAL_AT91_MAJOR TTY_MAJOR +#define SERIAL_ATMEL_MAJOR TTY_MAJOR #define MINOR_START 64 -#define AT91_DEVICENAME "ttyS" +#define ATMEL_DEVICENAME "ttyS" #endif -#define AT91_ISR_PASS_LIMIT 256 +#define ATMEL_ISR_PASS_LIMIT 256 -#define UART_PUT_CR(port,v) writel(v, (port)->membase + AT91_US_CR) -#define UART_GET_MR(port) readl((port)->membase + AT91_US_MR) -#define UART_PUT_MR(port,v) writel(v, (port)->membase + AT91_US_MR) -#define UART_PUT_IER(port,v) writel(v, (port)->membase + AT91_US_IER) -#define UART_PUT_IDR(port,v) writel(v, (port)->membase + AT91_US_IDR) -#define UART_GET_IMR(port) readl((port)->membase + AT91_US_IMR) -#define UART_GET_CSR(port) readl((port)->membase + AT91_US_CSR) -#define UART_GET_CHAR(port) readl((port)->membase + AT91_US_RHR) -#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + AT91_US_THR) -#define UART_GET_BRGR(port) readl((port)->membase + AT91_US_BRGR) -#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + AT91_US_BRGR) -#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + AT91_US_RTOR) +#define UART_PUT_CR(port,v) writel(v, (port)->membase + ATMEL_US_CR) +#define UART_GET_MR(port) readl((port)->membase + ATMEL_US_MR) +#define UART_PUT_MR(port,v) writel(v, (port)->membase + ATMEL_US_MR) +#define UART_PUT_IER(port,v) writel(v, (port)->membase + ATMEL_US_IER) +#define UART_PUT_IDR(port,v) writel(v, (port)->membase + ATMEL_US_IDR) +#define UART_GET_IMR(port) readl((port)->membase + ATMEL_US_IMR) +#define UART_GET_CSR(port) readl((port)->membase + ATMEL_US_CSR) +#define UART_GET_CHAR(port) readl((port)->membase + ATMEL_US_RHR) +#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + ATMEL_US_THR) +#define UART_GET_BRGR(port) readl((port)->membase + ATMEL_US_BRGR) +#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + ATMEL_US_BRGR) +#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + ATMEL_US_RTOR) -// #define UART_GET_CR(port) readl((port)->membase + AT91_US_CR) // is write-only +// #define UART_GET_CR(port) readl((port)->membase + ATMEL_US_CR) // is write-only /* PDC registers */ -#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + AT91_PDC_PTCR) -#define UART_GET_PTSR(port) readl((port)->membase + AT91_PDC_PTSR) +#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + ATMEL_PDC_PTCR) +#define UART_GET_PTSR(port) readl((port)->membase + ATMEL_PDC_PTSR) -#define UART_PUT_RPR(port,v) writel(v, (port)->membase + AT91_PDC_RPR) -#define UART_GET_RPR(port) readl((port)->membase + AT91_PDC_RPR) -#define UART_PUT_RCR(port,v) writel(v, (port)->membase + AT91_PDC_RCR) -#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + AT91_PDC_RNPR) -#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + AT91_PDC_RNCR) +#define UART_PUT_RPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RPR) +#define UART_GET_RPR(port) readl((port)->membase + ATMEL_PDC_RPR) +#define UART_PUT_RCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RCR) +#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNPR) +#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNCR) -#define UART_PUT_TPR(port,v) writel(v, (port)->membase + AT91_PDC_TPR) -#define UART_PUT_TCR(port,v) writel(v, (port)->membase + AT91_PDC_TCR) -//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + AT91_PDC_TNPR) -//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + AT91_PDC_TNCR) +#define UART_PUT_TPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TPR) +#define UART_PUT_TCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TCR) +//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNPR) +//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNCR) static int (*at91_open)(struct uart_port *); static void (*at91_close)(struct uart_port *); @@ -107,30 +107,30 @@ static void (*at91_close)(struct uart_port *); /* * We wrap our port structure around the generic uart_port. */ -struct at91_uart_port { +struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ unsigned short suspended; /* is port suspended? */ }; -static struct at91_uart_port at91_ports[ATMEL_MAX_UART]; +static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; #ifdef SUPPORT_SYSRQ -static struct console at91_console; +static struct console atmel_console; #endif /* * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. */ -static u_int at91_tx_empty(struct uart_port *port) +static u_int atmel_tx_empty(struct uart_port *port) { - return (UART_GET_CSR(port) & AT91_US_TXEMPTY) ? TIOCSER_TEMT : 0; + return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0; } /* * Set state of the modem control output lines */ -static void at91_set_mctrl(struct uart_port *port, u_int mctrl) +static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; unsigned int mode; @@ -149,30 +149,30 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl) } if (mctrl & TIOCM_RTS) - control |= AT91_US_RTSEN; + control |= ATMEL_US_RTSEN; else - control |= AT91_US_RTSDIS; + control |= ATMEL_US_RTSDIS; if (mctrl & TIOCM_DTR) - control |= AT91_US_DTREN; + control |= ATMEL_US_DTREN; else - control |= AT91_US_DTRDIS; + control |= ATMEL_US_DTRDIS; UART_PUT_CR(port, control); /* Local loopback mode? */ - mode = UART_GET_MR(port) & ~AT91_US_CHMODE; + mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE; if (mctrl & TIOCM_LOOP) - mode |= AT91_US_CHMODE_LOC_LOOP; + mode |= ATMEL_US_CHMODE_LOC_LOOP; else - mode |= AT91_US_CHMODE_NORMAL; + mode |= ATMEL_US_CHMODE_NORMAL; UART_PUT_MR(port, mode); } /* * Get state of the modem control input lines */ -static u_int at91_get_mctrl(struct uart_port *port) +static u_int atmel_get_mctrl(struct uart_port *port) { unsigned int status, ret = 0; @@ -181,13 +181,13 @@ static u_int at91_get_mctrl(struct uart_port *port) /* * The control signals are active low. */ - if (!(status & AT91_US_DCD)) + if (!(status & ATMEL_US_DCD)) ret |= TIOCM_CD; - if (!(status & AT91_US_CTS)) + if (!(status & ATMEL_US_CTS)) ret |= TIOCM_CTS; - if (!(status & AT91_US_DSR)) + if (!(status & ATMEL_US_DSR)) ret |= TIOCM_DSR; - if (!(status & AT91_US_RI)) + if (!(status & ATMEL_US_RI)) ret |= TIOCM_RI; return ret; @@ -196,62 +196,62 @@ static u_int at91_get_mctrl(struct uart_port *port) /* * Stop transmitting. */ -static void at91_stop_tx(struct uart_port *port) +static void atmel_stop_tx(struct uart_port *port) { - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - UART_PUT_IDR(port, AT91_US_TXRDY); + UART_PUT_IDR(port, ATMEL_US_TXRDY); } /* * Start transmitting. */ -static void at91_start_tx(struct uart_port *port) +static void atmel_start_tx(struct uart_port *port) { - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - UART_PUT_IER(port, AT91_US_TXRDY); + UART_PUT_IER(port, ATMEL_US_TXRDY); } /* * Stop receiving - port is in process of being closed. */ -static void at91_stop_rx(struct uart_port *port) +static void atmel_stop_rx(struct uart_port *port) { - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - UART_PUT_IDR(port, AT91_US_RXRDY); + UART_PUT_IDR(port, ATMEL_US_RXRDY); } /* * Enable modem status interrupts */ -static void at91_enable_ms(struct uart_port *port) +static void atmel_enable_ms(struct uart_port *port) { - UART_PUT_IER(port, AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC); + UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC); } /* * Control the transmission of a break signal */ -static void at91_break_ctl(struct uart_port *port, int break_state) +static void atmel_break_ctl(struct uart_port *port, int break_state) { if (break_state != 0) - UART_PUT_CR(port, AT91_US_STTBRK); /* start break */ + UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ else - UART_PUT_CR(port, AT91_US_STPBRK); /* stop break */ + UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ } /* * Characters received (called from interrupt handler) */ -static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) +static void atmel_rx_chars(struct uart_port *port, struct pt_regs *regs) { struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; status = UART_GET_CSR(port); - while (status & AT91_US_RXRDY) { + while (status & ATMEL_US_RXRDY) { ch = UART_GET_CHAR(port); port->icount.rx++; @@ -262,35 +262,35 @@ static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) * note that the error handling code is * out of the main execution path */ - if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE | AT91_US_RXBRK))) { - UART_PUT_CR(port, AT91_US_RSTSTA); /* clear error */ - if (status & AT91_US_RXBRK) { - status &= ~(AT91_US_PARE | AT91_US_FRAME); /* ignore side-effect */ + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { + UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ + if (status & ATMEL_US_RXBRK) { + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ port->icount.brk++; if (uart_handle_break(port)) goto ignore_char; } - if (status & AT91_US_PARE) + if (status & ATMEL_US_PARE) port->icount.parity++; - if (status & AT91_US_FRAME) + if (status & ATMEL_US_FRAME) port->icount.frame++; - if (status & AT91_US_OVRE) + if (status & ATMEL_US_OVRE) port->icount.overrun++; status &= port->read_status_mask; - if (status & AT91_US_RXBRK) + if (status & ATMEL_US_RXBRK) flg = TTY_BREAK; - else if (status & AT91_US_PARE) + else if (status & ATMEL_US_PARE) flg = TTY_PARITY; - else if (status & AT91_US_FRAME) + else if (status & ATMEL_US_FRAME) flg = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - uart_insert_char(port, status, AT91_US_OVRE, ch, flg); + uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg); ignore_char: status = UART_GET_CSR(port); @@ -302,7 +302,7 @@ static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) /* * Transmit characters (called from interrupt handler) */ -static void at91_tx_chars(struct uart_port *port) +static void atmel_tx_chars(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; @@ -313,11 +313,11 @@ static void at91_tx_chars(struct uart_port *port) return; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - at91_stop_tx(port); + atmel_stop_tx(port); return; } - while (UART_GET_CSR(port) & AT91_US_TXRDY) { + while (UART_GET_CSR(port) & ATMEL_US_TXRDY) { UART_PUT_CHAR(port, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; @@ -329,40 +329,40 @@ static void at91_tx_chars(struct uart_port *port) uart_write_wakeup(port); if (uart_circ_empty(xmit)) - at91_stop_tx(port); + atmel_stop_tx(port); } /* * Interrupt handler */ -static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t atmel_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct uart_port *port = dev_id; - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; unsigned int status, pending, pass_counter = 0; status = UART_GET_CSR(port); pending = status & UART_GET_IMR(port); while (pending) { /* Interrupt receive */ - if (pending & AT91_US_RXRDY) - at91_rx_chars(port, regs); + if (pending & ATMEL_US_RXRDY) + atmel_rx_chars(port, regs); // TODO: All reads to CSR will clear these interrupts! - if (pending & AT91_US_RIIC) port->icount.rng++; - if (pending & AT91_US_DSRIC) port->icount.dsr++; - if (pending & AT91_US_DCDIC) - uart_handle_dcd_change(port, !(status & AT91_US_DCD)); - if (pending & AT91_US_CTSIC) - uart_handle_cts_change(port, !(status & AT91_US_CTS)); - if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC)) + if (pending & ATMEL_US_RIIC) port->icount.rng++; + if (pending & ATMEL_US_DSRIC) port->icount.dsr++; + if (pending & ATMEL_US_DCDIC) + uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); + if (pending & ATMEL_US_CTSIC) + uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); + if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) wake_up_interruptible(&port->info->delta_msr_wait); /* Interrupt transmit */ - if (pending & AT91_US_TXRDY) - at91_tx_chars(port); + if (pending & ATMEL_US_TXRDY) + atmel_tx_chars(port); - if (pass_counter++ > AT91_ISR_PASS_LIMIT) + if (pass_counter++ > ATMEL_ISR_PASS_LIMIT) break; status = UART_GET_CSR(port); @@ -374,9 +374,9 @@ static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* * Perform initialization and enable port for reception */ -static int at91_startup(struct uart_port *port) +static int atmel_startup(struct uart_port *port) { - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; int retval; /* @@ -389,9 +389,9 @@ static int at91_startup(struct uart_port *port) /* * Allocate the IRQ */ - retval = request_irq(port->irq, at91_interrupt, IRQF_SHARED, "at91_serial", port); + retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port); if (retval) { - printk("at91_serial: at91_startup - Can't get irq\n"); + printk("atmel_serial: atmel_startup - Can't get irq\n"); return retval; } @@ -410,10 +410,10 @@ static int at91_startup(struct uart_port *port) /* * Finally, enable the serial port */ - UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); - UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); /* enable xmit & rcvr */ + UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */ - UART_PUT_IER(port, AT91_US_RXRDY); /* enable receive only */ + UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */ return 0; } @@ -421,14 +421,14 @@ static int at91_startup(struct uart_port *port) /* * Disable the port */ -static void at91_shutdown(struct uart_port *port) +static void atmel_shutdown(struct uart_port *port) { - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; /* * Disable all interrupts, port and break condition. */ - UART_PUT_CR(port, AT91_US_RSTSTA); + UART_PUT_CR(port, ATMEL_US_RSTSTA); UART_PUT_IDR(port, -1); /* @@ -447,9 +447,9 @@ static void at91_shutdown(struct uart_port *port) /* * Power / Clock management. */ -static void at91_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; switch (state) { case 0: @@ -457,24 +457,24 @@ static void at91_serial_pm(struct uart_port *port, unsigned int state, unsigned * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. */ - clk_enable(at91_port->clk); + clk_enable(atmel_port->clk); break; case 3: /* * Disable the peripheral clock for this serial port. * This is called on uart_close() or a suspend event. */ - clk_disable(at91_port->clk); + clk_disable(atmel_port->clk); break; default: - printk(KERN_ERR "at91_serial: unknown pm %d\n", state); + printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); } } /* * Change the port parameters */ -static void at91_set_termios(struct uart_port *port, struct termios * termios, struct termios * old) +static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old) { unsigned long flags; unsigned int mode, imr, quot, baud; @@ -483,66 +483,66 @@ static void at91_set_termios(struct uart_port *port, struct termios * termios, s quot = uart_get_divisor(port, baud); /* Get current mode register */ - mode = UART_GET_MR(port) & ~(AT91_US_CHRL | AT91_US_NBSTOP | AT91_US_PAR); + mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); /* byte size */ switch (termios->c_cflag & CSIZE) { case CS5: - mode |= AT91_US_CHRL_5; + mode |= ATMEL_US_CHRL_5; break; case CS6: - mode |= AT91_US_CHRL_6; + mode |= ATMEL_US_CHRL_6; break; case CS7: - mode |= AT91_US_CHRL_7; + mode |= ATMEL_US_CHRL_7; break; default: - mode |= AT91_US_CHRL_8; + mode |= ATMEL_US_CHRL_8; break; } /* stop bits */ if (termios->c_cflag & CSTOPB) - mode |= AT91_US_NBSTOP_2; + mode |= ATMEL_US_NBSTOP_2; /* parity */ if (termios->c_cflag & PARENB) { if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ if (termios->c_cflag & PARODD) - mode |= AT91_US_PAR_MARK; + mode |= ATMEL_US_PAR_MARK; else - mode |= AT91_US_PAR_SPACE; + mode |= ATMEL_US_PAR_SPACE; } else if (termios->c_cflag & PARODD) - mode |= AT91_US_PAR_ODD; + mode |= ATMEL_US_PAR_ODD; else - mode |= AT91_US_PAR_EVEN; + mode |= ATMEL_US_PAR_EVEN; } else - mode |= AT91_US_PAR_NONE; + mode |= ATMEL_US_PAR_NONE; spin_lock_irqsave(&port->lock, flags); - port->read_status_mask = AT91_US_OVRE; + port->read_status_mask = ATMEL_US_OVRE; if (termios->c_iflag & INPCK) - port->read_status_mask |= (AT91_US_FRAME | AT91_US_PARE); + port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= AT91_US_RXBRK; + port->read_status_mask |= ATMEL_US_RXBRK; /* * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= (AT91_US_FRAME | AT91_US_PARE); + port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= AT91_US_RXBRK; + port->ignore_status_mask |= ATMEL_US_RXBRK; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= AT91_US_OVRE; + port->ignore_status_mask |= ATMEL_US_OVRE; } // TODO: Ignore all characters if CREAD is set. @@ -553,18 +553,18 @@ static void at91_set_termios(struct uart_port *port, struct termios * termios, s /* disable interrupts and drain transmitter */ imr = UART_GET_IMR(port); /* get interrupt mask */ UART_PUT_IDR(port, -1); /* disable all interrupts */ - while (!(UART_GET_CSR(port) & AT91_US_TXEMPTY)) { barrier(); } + while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); } /* disable receiver and transmitter */ - UART_PUT_CR(port, AT91_US_TXDIS | AT91_US_RXDIS); + UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); /* set the parity, stop bits and data size */ UART_PUT_MR(port, mode); /* set the baud rate */ UART_PUT_BRGR(port, quot); - UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); - UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); + UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* restore interrupts */ UART_PUT_IER(port, imr); @@ -579,15 +579,15 @@ static void at91_set_termios(struct uart_port *port, struct termios * termios, s /* * Return string describing the specified port */ -static const char *at91_type(struct uart_port *port) +static const char *atmel_type(struct uart_port *port) { - return (port->type == PORT_AT91) ? "AT91_SERIAL" : NULL; + return (port->type == PORT_AT91) ? "ATMEL_SERIAL" : NULL; } /* * Release the memory region(s) being used by 'port'. */ -static void at91_release_port(struct uart_port *port) +static void atmel_release_port(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); int size = pdev->resource[0].end - pdev->resource[0].start + 1; @@ -603,12 +603,12 @@ static void at91_release_port(struct uart_port *port) /* * Request the memory region(s) being used by 'port'. */ -static int at91_request_port(struct uart_port *port) +static int atmel_request_port(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); int size = pdev->resource[0].end - pdev->resource[0].start + 1; - if (!request_mem_region(port->mapbase, size, "at91_serial")) + if (!request_mem_region(port->mapbase, size, "atmel_serial")) return -EBUSY; if (port->flags & UPF_IOREMAP) { @@ -625,18 +625,18 @@ static int at91_request_port(struct uart_port *port) /* * Configure/autoconfigure the port. */ -static void at91_config_port(struct uart_port *port, int flags) +static void atmel_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { port->type = PORT_AT91; - at91_request_port(port); + atmel_request_port(port); } } /* * Verify the new serial_struct (for TIOCSSERIAL). */ -static int at91_verify_port(struct uart_port *port, struct serial_struct *ser) +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) @@ -656,37 +656,37 @@ static int at91_verify_port(struct uart_port *port, struct serial_struct *ser) return ret; } -static struct uart_ops at91_pops = { - .tx_empty = at91_tx_empty, - .set_mctrl = at91_set_mctrl, - .get_mctrl = at91_get_mctrl, - .stop_tx = at91_stop_tx, - .start_tx = at91_start_tx, - .stop_rx = at91_stop_rx, - .enable_ms = at91_enable_ms, - .break_ctl = at91_break_ctl, - .startup = at91_startup, - .shutdown = at91_shutdown, - .set_termios = at91_set_termios, - .type = at91_type, - .release_port = at91_release_port, - .request_port = at91_request_port, - .config_port = at91_config_port, - .verify_port = at91_verify_port, - .pm = at91_serial_pm, +static struct uart_ops atmel_pops = { + .tx_empty = atmel_tx_empty, + .set_mctrl = atmel_set_mctrl, + .get_mctrl = atmel_get_mctrl, + .stop_tx = atmel_stop_tx, + .start_tx = atmel_start_tx, + .stop_rx = atmel_stop_rx, + .enable_ms = atmel_enable_ms, + .break_ctl = atmel_break_ctl, + .startup = atmel_startup, + .shutdown = atmel_shutdown, + .set_termios = atmel_set_termios, + .type = atmel_type, + .release_port = atmel_release_port, + .request_port = atmel_request_port, + .config_port = atmel_config_port, + .verify_port = atmel_verify_port, + .pm = atmel_serial_pm, }; /* * Configure the port from the platform device resource info. */ -static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct platform_device *pdev) +static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { - struct uart_port *port = &at91_port->uart; + struct uart_port *port = &atmel_port->uart; struct atmel_uart_data *data = pdev->dev.platform_data; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; - port->ops = &at91_pops; + port->ops = &atmel_pops; port->fifosize = 1; port->line = pdev->id; port->dev = &pdev->dev; @@ -701,10 +701,10 @@ static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct pl port->membase = NULL; } - if (!at91_port->clk) { /* for console, the clock could already be configured */ - at91_port->clk = clk_get(&pdev->dev, "usart"); - clk_enable(at91_port->clk); - port->uartclk = clk_get_rate(at91_port->clk); + if (!atmel_port->clk) { /* for console, the clock could already be configured */ + atmel_port->clk = clk_get(&pdev->dev, "usart"); + clk_enable(atmel_port->clk); + port->uartclk = clk_get_rate(atmel_port->clk); } } @@ -714,22 +714,22 @@ static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct pl void __init at91_register_uart_fns(struct at91_port_fns *fns) { if (fns->enable_ms) - at91_pops.enable_ms = fns->enable_ms; + atmel_pops.enable_ms = fns->enable_ms; if (fns->get_mctrl) - at91_pops.get_mctrl = fns->get_mctrl; + atmel_pops.get_mctrl = fns->get_mctrl; if (fns->set_mctrl) - at91_pops.set_mctrl = fns->set_mctrl; - at91_open = fns->open; - at91_close = fns->close; - at91_pops.pm = fns->pm; - at91_pops.set_wake = fns->set_wake; + atmel_pops.set_mctrl = fns->set_mctrl; + at91_open = fns->open; + at91_close = fns->close; + atmel_pops.pm = fns->pm; + atmel_pops.set_wake = fns->set_wake; } #ifdef CONFIG_SERIAL_ATMEL_CONSOLE -static void at91_console_putchar(struct uart_port *port, int ch) +static void atmel_console_putchar(struct uart_port *port, int ch) { - while (!(UART_GET_CSR(port) & AT91_US_TXRDY)) + while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) barrier(); UART_PUT_CHAR(port, ch); } @@ -737,18 +737,18 @@ static void at91_console_putchar(struct uart_port *port, int ch) /* * Interrupts are disabled on entering */ -static void at91_console_write(struct console *co, const char *s, u_int count) +static void atmel_console_write(struct console *co, const char *s, u_int count) { - struct uart_port *port = &at91_ports[co->index].uart; + struct uart_port *port = &atmel_ports[co->index].uart; unsigned int status, imr; /* * First, save IMR and then disable interrupts */ imr = UART_GET_IMR(port); /* get interrupt mask */ - UART_PUT_IDR(port, AT91_US_RXRDY | AT91_US_TXRDY); + UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY); - uart_console_write(port, s, count, at91_console_putchar); + uart_console_write(port, s, count, atmel_console_putchar); /* * Finally, wait for transmitter to become empty @@ -756,7 +756,7 @@ static void at91_console_write(struct console *co, const char *s, u_int count) */ do { status = UART_GET_CSR(port); - } while (!(status & AT91_US_TXRDY)); + } while (!(status & ATMEL_US_TXRDY)); UART_PUT_IER(port, imr); /* set interrupts back the way they were */ } @@ -764,37 +764,37 @@ static void at91_console_write(struct console *co, const char *s, u_int count) * If the port was already initialised (eg, by a boot loader), try to determine * the current setup. */ -static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) { unsigned int mr, quot; // TODO: CR is a write-only register // unsigned int cr; // -// cr = UART_GET_CR(port) & (AT91_US_RXEN | AT91_US_TXEN); -// if (cr == (AT91_US_RXEN | AT91_US_TXEN)) { +// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN); +// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) { // /* ok, the port was enabled */ // } - mr = UART_GET_MR(port) & AT91_US_CHRL; - if (mr == AT91_US_CHRL_8) + mr = UART_GET_MR(port) & ATMEL_US_CHRL; + if (mr == ATMEL_US_CHRL_8) *bits = 8; else *bits = 7; - mr = UART_GET_MR(port) & AT91_US_PAR; - if (mr == AT91_US_PAR_EVEN) + mr = UART_GET_MR(port) & ATMEL_US_PAR; + if (mr == ATMEL_US_PAR_EVEN) *parity = 'e'; - else if (mr == AT91_US_PAR_ODD) + else if (mr == ATMEL_US_PAR_ODD) *parity = 'o'; quot = UART_GET_BRGR(port); *baud = port->uartclk / (16 * (quot)); } -static int __init at91_console_setup(struct console *co, char *options) +static int __init atmel_console_setup(struct console *co, char *options) { - struct uart_port *port = &at91_ports[co->index].uart; + struct uart_port *port = &atmel_ports[co->index].uart; int baud = 115200; int bits = 8; int parity = 'n'; @@ -804,115 +804,115 @@ static int __init at91_console_setup(struct console *co, char *options) return -ENODEV; UART_PUT_IDR(port, -1); /* disable interrupts */ - UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); - UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); + UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - at91_console_get_options(port, &baud, &parity, &bits); + atmel_console_get_options(port, &baud, &parity, &bits); return uart_set_options(port, co, baud, parity, bits, flow); } -static struct uart_driver at91_uart; +static struct uart_driver atmel_uart; -static struct console at91_console = { - .name = AT91_DEVICENAME, - .write = at91_console_write, +static struct console atmel_console = { + .name = ATMEL_DEVICENAME, + .write = atmel_console_write, .device = uart_console_device, - .setup = at91_console_setup, + .setup = atmel_console_setup, .flags = CON_PRINTBUFFER, .index = -1, - .data = &at91_uart, + .data = &atmel_uart, }; -#define AT91_CONSOLE_DEVICE &at91_console +#define ATMEL_CONSOLE_DEVICE &atmel_console /* * Early console initialization (before VM subsystem initialized). */ -static int __init at91_console_init(void) +static int __init atmel_console_init(void) { if (atmel_default_console_device) { - add_preferred_console(AT91_DEVICENAME, atmel_default_console_device->id, NULL); - at91_init_port(&(at91_ports[atmel_default_console_device->id]), atmel_default_console_device); - register_console(&at91_console); + add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL); + atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device); + register_console(&atmel_console); } return 0; } -console_initcall(at91_console_init); +console_initcall(atmel_console_init); /* * Late console initialization. */ -static int __init at91_late_console_init(void) +static int __init atmel_late_console_init(void) { - if (atmel_default_console_device && !(at91_console.flags & CON_ENABLED)) - register_console(&at91_console); + if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED)) + register_console(&atmel_console); return 0; } -core_initcall(at91_late_console_init); +core_initcall(atmel_late_console_init); #else -#define AT91_CONSOLE_DEVICE NULL +#define ATMEL_CONSOLE_DEVICE NULL #endif -static struct uart_driver at91_uart = { +static struct uart_driver atmel_uart = { .owner = THIS_MODULE, - .driver_name = "at91_serial", - .dev_name = AT91_DEVICENAME, - .major = SERIAL_AT91_MAJOR, + .driver_name = "atmel_serial", + .dev_name = ATMEL_DEVICENAME, + .major = SERIAL_ATMEL_MAJOR, .minor = MINOR_START, .nr = ATMEL_MAX_UART, - .cons = AT91_CONSOLE_DEVICE, + .cons = ATMEL_CONSOLE_DEVICE, }; #ifdef CONFIG_PM -static int at91_serial_suspend(struct platform_device *pdev, pm_message_t state) +static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state) { struct uart_port *port = platform_get_drvdata(pdev); - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock()) enable_irq_wake(port->irq); else { disable_irq_wake(port->irq); - uart_suspend_port(&at91_uart, port); - at91_port->suspended = 1; + uart_suspend_port(&atmel_uart, port); + atmel_port->suspended = 1; } return 0; } -static int at91_serial_resume(struct platform_device *pdev) +static int atmel_serial_resume(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - if (at91_port->suspended) { - uart_resume_port(&at91_uart, port); - at91_port->suspended = 0; + if (atmel_port->suspended) { + uart_resume_port(&atmel_uart, port); + atmel_port->suspended = 0; } return 0; } #else -#define at91_serial_suspend NULL -#define at91_serial_resume NULL +#define atmel_serial_suspend NULL +#define atmel_serial_resume NULL #endif -static int __devinit at91_serial_probe(struct platform_device *pdev) +static int __devinit atmel_serial_probe(struct platform_device *pdev) { - struct at91_uart_port *port; + struct atmel_uart_port *port; int ret; - port = &at91_ports[pdev->id]; - at91_init_port(port, pdev); + port = &atmel_ports[pdev->id]; + atmel_init_port(port, pdev); - ret = uart_add_one_port(&at91_uart, &port->uart); + ret = uart_add_one_port(&atmel_uart, &port->uart); if (!ret) { device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, port); @@ -921,61 +921,61 @@ static int __devinit at91_serial_probe(struct platform_device *pdev) return ret; } -static int __devexit at91_serial_remove(struct platform_device *pdev) +static int __devexit atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; int ret = 0; - clk_disable(at91_port->clk); - clk_put(at91_port->clk); + clk_disable(atmel_port->clk); + clk_put(atmel_port->clk); device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); if (port) { - ret = uart_remove_one_port(&at91_uart, port); + ret = uart_remove_one_port(&atmel_uart, port); kfree(port); } return ret; } -static struct platform_driver at91_serial_driver = { - .probe = at91_serial_probe, - .remove = __devexit_p(at91_serial_remove), - .suspend = at91_serial_suspend, - .resume = at91_serial_resume, +static struct platform_driver atmel_serial_driver = { + .probe = atmel_serial_probe, + .remove = __devexit_p(atmel_serial_remove), + .suspend = atmel_serial_suspend, + .resume = atmel_serial_resume, .driver = { .name = "atmel_usart", .owner = THIS_MODULE, }, }; -static int __init at91_serial_init(void) +static int __init atmel_serial_init(void) { int ret; - ret = uart_register_driver(&at91_uart); + ret = uart_register_driver(&atmel_uart); if (ret) return ret; - ret = platform_driver_register(&at91_serial_driver); + ret = platform_driver_register(&atmel_serial_driver); if (ret) - uart_unregister_driver(&at91_uart); + uart_unregister_driver(&atmel_uart); return ret; } -static void __exit at91_serial_exit(void) +static void __exit atmel_serial_exit(void) { - platform_driver_unregister(&at91_serial_driver); - uart_unregister_driver(&at91_uart); + platform_driver_unregister(&atmel_serial_driver); + uart_unregister_driver(&atmel_uart); } -module_init(at91_serial_init); -module_exit(at91_serial_exit); +module_init(atmel_serial_init); +module_exit(atmel_serial_exit); MODULE_AUTHOR("Rick Bronson"); -MODULE_DESCRIPTION("AT91 generic serial port driver"); +MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h index d38b24a5337..eced2ad1a8d 100644 --- a/drivers/serial/atmel_serial.h +++ b/drivers/serial/atmel_serial.h @@ -13,111 +13,111 @@ * (at your option) any later version. */ -#ifndef AT91RM9200_USART_H -#define AT91RM9200_USART_H +#ifndef ATMEL_SERIAL_H +#define ATMEL_SERIAL_H -#define AT91_US_CR 0x00 /* Control Register */ -#define AT91_US_RSTRX (1 << 2) /* Reset Receiver */ -#define AT91_US_RSTTX (1 << 3) /* Reset Transmitter */ -#define AT91_US_RXEN (1 << 4) /* Receiver Enable */ -#define AT91_US_RXDIS (1 << 5) /* Receiver Disable */ -#define AT91_US_TXEN (1 << 6) /* Transmitter Enable */ -#define AT91_US_TXDIS (1 << 7) /* Transmitter Disable */ -#define AT91_US_RSTSTA (1 << 8) /* Reset Status Bits */ -#define AT91_US_STTBRK (1 << 9) /* Start Break */ -#define AT91_US_STPBRK (1 << 10) /* Stop Break */ -#define AT91_US_STTTO (1 << 11) /* Start Time-out */ -#define AT91_US_SENDA (1 << 12) /* Send Address */ -#define AT91_US_RSTIT (1 << 13) /* Reset Iterations */ -#define AT91_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ -#define AT91_US_RETTO (1 << 15) /* Rearm Time-out */ -#define AT91_US_DTREN (1 << 16) /* Data Terminal Ready Enable */ -#define AT91_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */ -#define AT91_US_RTSEN (1 << 18) /* Request To Send Enable */ -#define AT91_US_RTSDIS (1 << 19) /* Request To Send Disable */ +#define ATMEL_US_CR 0x00 /* Control Register */ +#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */ +#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */ +#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */ +#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */ +#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */ +#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */ +#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */ +#define ATMEL_US_STTBRK (1 << 9) /* Start Break */ +#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */ +#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */ +#define ATMEL_US_SENDA (1 << 12) /* Send Address */ +#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */ +#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ +#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */ +#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable */ +#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */ +#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */ +#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */ -#define AT91_US_MR 0x04 /* Mode Register */ -#define AT91_US_USMODE (0xf << 0) /* Mode of the USART */ -#define AT91_US_USMODE_NORMAL 0 -#define AT91_US_USMODE_RS485 1 -#define AT91_US_USMODE_HWHS 2 -#define AT91_US_USMODE_MODEM 3 -#define AT91_US_USMODE_ISO7816_T0 4 -#define AT91_US_USMODE_ISO7816_T1 6 -#define AT91_US_USMODE_IRDA 8 -#define AT91_US_USCLKS (3 << 4) /* Clock Selection */ -#define AT91_US_CHRL (3 << 6) /* Character Length */ -#define AT91_US_CHRL_5 (0 << 6) -#define AT91_US_CHRL_6 (1 << 6) -#define AT91_US_CHRL_7 (2 << 6) -#define AT91_US_CHRL_8 (3 << 6) -#define AT91_US_SYNC (1 << 8) /* Synchronous Mode Select */ -#define AT91_US_PAR (7 << 9) /* Parity Type */ -#define AT91_US_PAR_EVEN (0 << 9) -#define AT91_US_PAR_ODD (1 << 9) -#define AT91_US_PAR_SPACE (2 << 9) -#define AT91_US_PAR_MARK (3 << 9) -#define AT91_US_PAR_NONE (4 << 9) -#define AT91_US_PAR_MULTI_DROP (6 << 9) -#define AT91_US_NBSTOP (3 << 12) /* Number of Stop Bits */ -#define AT91_US_NBSTOP_1 (0 << 12) -#define AT91_US_NBSTOP_1_5 (1 << 12) -#define AT91_US_NBSTOP_2 (2 << 12) -#define AT91_US_CHMODE (3 << 14) /* Channel Mode */ -#define AT91_US_CHMODE_NORMAL (0 << 14) -#define AT91_US_CHMODE_ECHO (1 << 14) -#define AT91_US_CHMODE_LOC_LOOP (2 << 14) -#define AT91_US_CHMODE_REM_LOOP (3 << 14) -#define AT91_US_MSBF (1 << 16) /* Bit Order */ -#define AT91_US_MODE9 (1 << 17) /* 9-bit Character Length */ -#define AT91_US_CLKO (1 << 18) /* Clock Output Select */ -#define AT91_US_OVER (1 << 19) /* Oversampling Mode */ -#define AT91_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ -#define AT91_US_DSNACK (1 << 21) /* Disable Successive NACK */ -#define AT91_US_MAX_ITER (7 << 24) /* Max Iterations */ -#define AT91_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ +#define ATMEL_US_MR 0x04 /* Mode Register */ +#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */ +#define ATMEL_US_USMODE_NORMAL 0 +#define ATMEL_US_USMODE_RS485 1 +#define ATMEL_US_USMODE_HWHS 2 +#define ATMEL_US_USMODE_MODEM 3 +#define ATMEL_US_USMODE_ISO7816_T0 4 +#define ATMEL_US_USMODE_ISO7816_T1 6 +#define ATMEL_US_USMODE_IRDA 8 +#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */ +#define ATMEL_US_CHRL (3 << 6) /* Character Length */ +#define ATMEL_US_CHRL_5 (0 << 6) +#define ATMEL_US_CHRL_6 (1 << 6) +#define ATMEL_US_CHRL_7 (2 << 6) +#define ATMEL_US_CHRL_8 (3 << 6) +#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */ +#define ATMEL_US_PAR (7 << 9) /* Parity Type */ +#define ATMEL_US_PAR_EVEN (0 << 9) +#define ATMEL_US_PAR_ODD (1 << 9) +#define ATMEL_US_PAR_SPACE (2 << 9) +#define ATMEL_US_PAR_MARK (3 << 9) +#define ATMEL_US_PAR_NONE (4 << 9) +#define ATMEL_US_PAR_MULTI_DROP (6 << 9) +#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */ +#define ATMEL_US_NBSTOP_1 (0 << 12) +#define ATMEL_US_NBSTOP_1_5 (1 << 12) +#define ATMEL_US_NBSTOP_2 (2 << 12) +#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */ +#define ATMEL_US_CHMODE_NORMAL (0 << 14) +#define ATMEL_US_CHMODE_ECHO (1 << 14) +#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) +#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) +#define ATMEL_US_MSBF (1 << 16) /* Bit Order */ +#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */ +#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */ +#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */ +#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ +#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */ +#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */ +#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ -#define AT91_US_IER 0x08 /* Interrupt Enable Register */ -#define AT91_US_RXRDY (1 << 0) /* Receiver Ready */ -#define AT91_US_TXRDY (1 << 1) /* Transmitter Ready */ -#define AT91_US_RXBRK (1 << 2) /* Break Received / End of Break */ -#define AT91_US_ENDRX (1 << 3) /* End of Receiver Transfer */ -#define AT91_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ -#define AT91_US_OVRE (1 << 5) /* Overrun Error */ -#define AT91_US_FRAME (1 << 6) /* Framing Error */ -#define AT91_US_PARE (1 << 7) /* Parity Error */ -#define AT91_US_TIMEOUT (1 << 8) /* Receiver Time-out */ -#define AT91_US_TXEMPTY (1 << 9) /* Transmitter Empty */ -#define AT91_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ -#define AT91_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ -#define AT91_US_RXBUFF (1 << 12) /* Reception Buffer Full */ -#define AT91_US_NACK (1 << 13) /* Non Acknowledge */ -#define AT91_US_RIIC (1 << 16) /* Ring Indicator Input Change */ -#define AT91_US_DSRIC (1 << 17) /* Data Set Ready Input Change */ -#define AT91_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */ -#define AT91_US_CTSIC (1 << 19) /* Clear to Send Input Change */ -#define AT91_US_RI (1 << 20) /* RI */ -#define AT91_US_DSR (1 << 21) /* DSR */ -#define AT91_US_DCD (1 << 22) /* DCD */ -#define AT91_US_CTS (1 << 23) /* CTS */ +#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ +#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */ +#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */ +#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */ +#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */ +#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ +#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */ +#define ATMEL_US_FRAME (1 << 6) /* Framing Error */ +#define ATMEL_US_PARE (1 << 7) /* Parity Error */ +#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */ +#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */ +#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ +#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ +#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */ +#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */ +#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change */ +#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change */ +#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */ +#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */ +#define ATMEL_US_RI (1 << 20) /* RI */ +#define ATMEL_US_DSR (1 << 21) /* DSR */ +#define ATMEL_US_DCD (1 << 22) /* DCD */ +#define ATMEL_US_CTS (1 << 23) /* CTS */ -#define AT91_US_IDR 0x0c /* Interrupt Disable Register */ -#define AT91_US_IMR 0x10 /* Interrupt Mask Register */ -#define AT91_US_CSR 0x14 /* Channel Status Register */ -#define AT91_US_RHR 0x18 /* Receiver Holding Register */ -#define AT91_US_THR 0x1c /* Transmitter Holding Register */ +#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */ +#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */ +#define ATMEL_US_CSR 0x14 /* Channel Status Register */ +#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ +#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ -#define AT91_US_BRGR 0x20 /* Baud Rate Generator Register */ -#define AT91_US_CD (0xffff << 0) /* Clock Divider */ +#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ +#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */ -#define AT91_US_RTOR 0x24 /* Receiver Time-out Register */ -#define AT91_US_TO (0xffff << 0) /* Time-out Value */ +#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ +#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */ -#define AT91_US_TTGR 0x28 /* Transmitter Timeguard Register */ -#define AT91_US_TG (0xff << 0) /* Timeguard Value */ +#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ +#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */ -#define AT91_US_FIDI 0x40 /* FI DI Ratio Register */ -#define AT91_US_NER 0x44 /* Number of Errors Register */ -#define AT91_US_IF 0x4c /* IrDA Filter Register */ +#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */ +#define ATMEL_US_NER 0x44 /* Number of Errors Register */ +#define ATMEL_US_IF 0x4c /* IrDA Filter Register */ #endif -- GitLab From 9ab4f88b7ffdf338773e7755f923bc6b9e079834 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:06 +0200 Subject: [PATCH 0593/1619] [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(-) diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 7397d5df6d9..2c5b72ccc4b 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 de2e68159d9..b661c19f3f7 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 */ -- GitLab From 71f2e2b8783f7b270b673e31e2322572057b286a Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:07 +0200 Subject: [PATCH 0594/1619] [PATCH] atmel_serial: Rename at91_register_uart_fns Rename at91_register_uart_fns and associated structs and variables to make it consistent with the atmel_ prefix used by the rest of the driver. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/atmel_serial.c | 18 +++++++++--------- include/asm-arm/mach/serial_at91.h | 6 +++--- include/asm-avr32/mach/serial_at91.h | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 2c5b72ccc4b..2f9d99bb958 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -101,8 +101,8 @@ //#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNPR) //#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNCR) -static int (*at91_open)(struct uart_port *); -static void (*at91_close)(struct uart_port *); +static int (*atmel_open_hook)(struct uart_port *); +static void (*atmel_close_hook)(struct uart_port *); /* * We wrap our port structure around the generic uart_port. @@ -399,8 +399,8 @@ static int atmel_startup(struct uart_port *port) * If there is a specific "open" function (to register * control line interrupts) */ - if (at91_open) { - retval = at91_open(port); + if (atmel_open_hook) { + retval = atmel_open_hook(port); if (retval) { free_irq(port->irq, port); return retval; @@ -440,8 +440,8 @@ static void atmel_shutdown(struct uart_port *port) * If there is a specific "close" function (to unregister * control line interrupts) */ - if (at91_close) - at91_close(port); + if (atmel_close_hook) + atmel_close_hook(port); } /* @@ -711,7 +711,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct /* * Register board-specific modem-control line handlers. */ -void __init at91_register_uart_fns(struct at91_port_fns *fns) +void __init atmel_register_uart_fns(struct atmel_port_fns *fns) { if (fns->enable_ms) atmel_pops.enable_ms = fns->enable_ms; @@ -719,8 +719,8 @@ void __init at91_register_uart_fns(struct at91_port_fns *fns) atmel_pops.get_mctrl = fns->get_mctrl; if (fns->set_mctrl) atmel_pops.set_mctrl = fns->set_mctrl; - at91_open = fns->open; - at91_close = fns->close; + atmel_open_hook = fns->open; + atmel_close_hook = fns->close; atmel_pops.pm = fns->pm; atmel_pops.set_wake = fns->set_wake; } diff --git a/include/asm-arm/mach/serial_at91.h b/include/asm-arm/mach/serial_at91.h index 239e1f65d67..55b317a8906 100644 --- a/include/asm-arm/mach/serial_at91.h +++ b/include/asm-arm/mach/serial_at91.h @@ -14,7 +14,7 @@ struct uart_port; * This is a temporary structure for registering these * functions; it is intended to be discarded after boot. */ -struct at91_port_fns { +struct atmel_port_fns { void (*set_mctrl)(struct uart_port *, u_int); u_int (*get_mctrl)(struct uart_port *); void (*enable_ms)(struct uart_port *); @@ -25,9 +25,9 @@ struct at91_port_fns { }; #if defined(CONFIG_SERIAL_ATMEL) -void at91_register_uart_fns(struct at91_port_fns *fns); +void atmel_register_uart_fns(struct atmel_port_fns *fns); #else -#define at91_register_uart_fns(fns) do { } while (0) +#define atmel_register_uart_fns(fns) do { } while (0) #endif diff --git a/include/asm-avr32/mach/serial_at91.h b/include/asm-avr32/mach/serial_at91.h index 239e1f65d67..55b317a8906 100644 --- a/include/asm-avr32/mach/serial_at91.h +++ b/include/asm-avr32/mach/serial_at91.h @@ -14,7 +14,7 @@ struct uart_port; * This is a temporary structure for registering these * functions; it is intended to be discarded after boot. */ -struct at91_port_fns { +struct atmel_port_fns { void (*set_mctrl)(struct uart_port *, u_int); u_int (*get_mctrl)(struct uart_port *); void (*enable_ms)(struct uart_port *); @@ -25,9 +25,9 @@ struct at91_port_fns { }; #if defined(CONFIG_SERIAL_ATMEL) -void at91_register_uart_fns(struct at91_port_fns *fns); +void atmel_register_uart_fns(struct atmel_port_fns *fns); #else -#define at91_register_uart_fns(fns) do { } while (0) +#define atmel_register_uart_fns(fns) do { } while (0) #endif -- GitLab From 75d35213777e2b278db57a420efbce2bdb61da93 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:08 +0200 Subject: [PATCH 0595/1619] [PATCH] atmel_serial: Pass fixed register mappings through platform_data In order to initialize the serial console early, the atmel_serial driver had to do a hack where it compared the physical address of the port with an address known to be permanently mapped, and used it as a virtual address. This got around the limitation that ioremap() isn't always available when the console is being initalized. This patch removes that hack and replaces it with a new "regs" field in struct atmel_uart_data that the board-specific code can initialize to a fixed virtual mapping for platform devices where this is possible. It also initializes the DBGU's regs field with the address the driver used to check against. On AVR32, the "regs" field is initialized from the physical base address when this it can be accessed through a permanently 1:1 mapped segment, i.e. the P4 segment. If regs is NULL, the console initialization is delayed until the "real" driver is up and running and ioremap() can be used. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- arch/arm/mach-at91rm9200/devices.c | 1 + arch/avr32/mach-at32ap/at32ap7000.c | 33 ++++++++++++++++++++----- drivers/serial/atmel_serial.c | 5 ++-- include/asm-arm/arch-at91rm9200/board.h | 1 + include/asm-avr32/arch-at32ap/board.h | 5 ++++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index 5a3919f09d4..05982437662 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -561,6 +561,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU), }; static struct platform_device at91rm9200_dbgu_device = { diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 05d1296bd7b..3dd30587508 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -523,32 +523,48 @@ void __init at32_add_system_devices(void) * USART * -------------------------------------------------------------------- */ +static struct atmel_uart_data atmel_usart0_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; static struct resource atmel_usart0_resource[] = { PBMEM(0xffe00c00), IRQ(7), }; -DEFINE_DEV(atmel_usart, 0); +DEFINE_DEV_DATA(atmel_usart, 0); DEV_CLK(usart, atmel_usart0, pba, 4); +static struct atmel_uart_data atmel_usart1_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; static struct resource atmel_usart1_resource[] = { PBMEM(0xffe01000), IRQ(7), }; -DEFINE_DEV(atmel_usart, 1); +DEFINE_DEV_DATA(atmel_usart, 1); DEV_CLK(usart, atmel_usart1, pba, 4); +static struct atmel_uart_data atmel_usart2_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; static struct resource atmel_usart2_resource[] = { PBMEM(0xffe01400), IRQ(8), }; -DEFINE_DEV(atmel_usart, 2); +DEFINE_DEV_DATA(atmel_usart, 2); DEV_CLK(usart, atmel_usart2, pba, 5); +static struct atmel_uart_data atmel_usart3_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; static struct resource atmel_usart3_resource[] = { PBMEM(0xffe01800), IRQ(9), }; -DEFINE_DEV(atmel_usart, 3); +DEFINE_DEV_DATA(atmel_usart, 3); DEV_CLK(usart, atmel_usart3, pba, 6); static inline void configure_usart0_pins(void) @@ -597,8 +613,13 @@ static struct platform_device *setup_usart(unsigned int id) configure_usart3_pins(); break; default: - pdev = NULL; - break; + return NULL; + } + + if (PXSEG(pdev->resource[0].start) == P4SEG) { + /* Addresses in the P4 segment are permanently mapped 1:1 */ + struct atmel_uart_data *data = pdev->dev.platform_data; + data->regs = (void __iomem *)pdev->resource[0].start; } return pdev; diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 2f9d99bb958..34212df3980 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -694,8 +694,9 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct port->mapbase = pdev->resource[0].start; port->irq = pdev->resource[1].start; - if (port->mapbase == AT91_VA_BASE_SYS + AT91_DBGU) /* Part of system perpherals - already mapped */ - port->membase = (void __iomem *) port->mapbase; + if (data->regs) + /* Already mapped by setup code */ + port->membase = data->regs; else { port->flags |= UPF_IOREMAP; port->membase = NULL; diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h index d56527055c9..3cc9aec80f9 100644 --- a/include/asm-arm/arch-at91rm9200/board.h +++ b/include/asm-arm/arch-at91rm9200/board.h @@ -103,6 +103,7 @@ extern void __init at91_init_serial(struct at91_uart_config *config); struct atmel_uart_data { short use_dma_tx; /* use transmit DMA? */ short use_dma_rx; /* use receive DMA? */ + void __iomem *regs; /* virtual base address, if any */ }; extern void __init at91_add_device_serial(void); diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index 82e5404d2f4..435507281f8 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -12,6 +12,11 @@ void at32_add_system_devices(void); #define ATMEL_MAX_UART 4 extern struct platform_device *atmel_default_console_device; +struct atmel_uart_data { + short use_dma_tx; /* use transmit DMA? */ + short use_dma_rx; /* use receive DMA? */ + void __iomem *regs; /* virtual base address, if any */ +}; struct platform_device *at32_add_device_usart(unsigned int id); struct eth_platform_data { -- GitLab From acca9b83acfe89fbb7421d5412176dee2ad2959a Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:09 +0200 Subject: [PATCH 0596/1619] [PATCH] atmel_serial: Support AVR32 Make CONFIG_SERIAL_ATMEL selectable on AVR32 and #ifdef out some ARM- specific code in the driver. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/Kconfig | 24 ++++++++++++------------ drivers/serial/atmel_serial.c | 4 ++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ba19ab571f9..b0d502622d9 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -301,31 +301,31 @@ config SERIAL_AMBA_PL011_CONSOLE config SERIAL_ATMEL bool "AT91 / AT32 on-chip serial port support" - depends on ARM && (ARCH_AT91RM9200 || ARCH_AT91SAM9261) + depends on (ARM && ARCH_AT91) || AVR32 select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Atmel - AT91RM9200 and AT91SAM926 processor. + AT91 and AT32 processors. config SERIAL_ATMEL_CONSOLE bool "Support for console on AT91 / AT32 serial port" depends on SERIAL_ATMEL=y select SERIAL_CORE_CONSOLE help - Say Y here if you wish to use a UART on the Atmel AT91RM9200 or - AT91SAM9261 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). + Say Y here if you wish to use an on-chip UART on a Atmel + AT91 or AT32 processor 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_ATMEL_TTYAT - bool "Install as device ttyAT0-4 instead of ttyS0-4" + bool "Install as device ttyATn instead of ttySn" depends on SERIAL_ATMEL=y help - Say Y here if you wish to have the five internal AT91RM9200 UARTs - appear as /dev/ttyAT0-4 (major 204, minor 154-158) instead of the - normal /dev/ttyS0-4 (major 4, minor 64-68). This is necessary if - you also want other UARTs, such as external 8250/16C550 compatible - UARTs. + Say Y here if you wish to have the internal AT91 / AT32 UARTs + appear as /dev/ttyATn (major 204, minor starting at 154) + instead of the normal /dev/ttySn (major 4, minor starting at + 64). This is necessary if you also want other UARTs, such as + external 8250/16C550 compatible UARTs. The ttySn nodes are legally reserved for the 8250 serial driver but are often misused by other serial drivers. diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 34212df3980..61db2166fbb 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -39,8 +39,10 @@ #include #include #include +#ifdef CONFIG_ARM #include #include +#endif #include "atmel_serial.h" @@ -135,6 +137,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) unsigned int control = 0; unsigned int mode; +#ifdef CONFIG_ARM if (arch_identify() == ARCH_ID_AT91RM9200) { /* * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21. @@ -147,6 +150,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) at91_set_gpio_value(AT91_PIN_PA21, 1); } } +#endif if (mctrl & TIOCM_RTS) control |= ATMEL_US_RTSEN; -- GitLab From c194588dba968510b5aa7a1818bd2c8b36a416f7 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:10 +0200 Subject: [PATCH 0597/1619] [PATCH] AVR32: Allow renumbering of serial devices Allow the board to remap actual USART peripheral devices to serial devices by calling at32_map_usart(hw_id, serial_line). This ensures that even though ATSTK1002 uses USART1 as the first serial port, it will still have a ttyS0 device. This also adds a board-specific early setup hook and moves the at32_setup_serial_console() call there from the platform code. Signed-off-by: Haavard Skinnemoen Signed-off-by: Linus Torvalds --- arch/avr32/boards/atstk1000/atstk1002.c | 16 +++++++++++++--- arch/avr32/kernel/setup.c | 1 + arch/avr32/mach-at32ap/at32ap.c | 3 --- arch/avr32/mach-at32ap/at32ap7000.c | 22 ++++++++++------------ include/asm-avr32/arch-at32ap/board.h | 1 + include/asm-avr32/arch-at32ap/init.h | 1 + 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index 49164e9aadd..cced73c5811 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -10,6 +10,7 @@ #include #include +#include struct eth_platform_data __initdata eth0_data = { .valid = 1, @@ -20,13 +21,22 @@ struct eth_platform_data __initdata eth0_data = { extern struct lcdc_platform_data atstk1000_fb0_data; +void __init setup_board(void) +{ + at32_map_usart(1, 0); /* /dev/ttyS0 */ + at32_map_usart(2, 1); /* /dev/ttyS1 */ + at32_map_usart(3, 2); /* /dev/ttyS2 */ + + at32_setup_serial_console(0); +} + static int __init atstk1002_init(void) { at32_add_system_devices(); - at32_add_device_usart(1); /* /dev/ttyS0 */ - at32_add_device_usart(2); /* /dev/ttyS1 */ - at32_add_device_usart(3); /* /dev/ttyS2 */ + at32_add_device_usart(0); + at32_add_device_usart(1); + at32_add_device_usart(2); at32_add_device_eth(0, ð0_data); at32_add_device_spi(0); diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index 5d68f3c6990..ea2d1ffee47 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -292,6 +292,7 @@ void __init setup_arch (char **cmdline_p) setup_processor(); setup_platform(); + setup_board(); cpu_clk = clk_get(NULL, "cpu"); if (IS_ERR(cpu_clk)) { diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/at32ap.c index f7cedf5aabe..90f207e8e96 100644 --- a/arch/avr32/mach-at32ap/at32ap.c +++ b/arch/avr32/mach-at32ap/at32ap.c @@ -48,9 +48,6 @@ void __init setup_platform(void) at32_sm_init(); at32_clock_init(); at32_portmux_init(); - - /* FIXME: This doesn't belong here */ - at32_setup_serial_console(1); } static int __init pdc_probe(struct platform_device *pdev) diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 3dd30587508..7ff6ad8bab5 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -591,11 +591,13 @@ static inline void configure_usart3_pins(void) portmux_set_func(PIOB, 17, FUNC_B); /* TXD */ } -static struct platform_device *setup_usart(unsigned int id) +static struct platform_device *at32_usarts[4]; + +void __init at32_map_usart(unsigned int hw_id, unsigned int line) { struct platform_device *pdev; - switch (id) { + switch (hw_id) { case 0: pdev = &atmel_usart0_device; configure_usart0_pins(); @@ -613,7 +615,7 @@ static struct platform_device *setup_usart(unsigned int id) configure_usart3_pins(); break; default: - return NULL; + return; } if (PXSEG(pdev->resource[0].start) == P4SEG) { @@ -622,25 +624,21 @@ static struct platform_device *setup_usart(unsigned int id) data->regs = (void __iomem *)pdev->resource[0].start; } - return pdev; + pdev->id = line; + at32_usarts[line] = pdev; } struct platform_device *__init at32_add_device_usart(unsigned int id) { - struct platform_device *pdev; - - pdev = setup_usart(id); - if (pdev) - platform_device_register(pdev); - - return pdev; + platform_device_register(at32_usarts[id]); + return at32_usarts[id]; } struct platform_device *atmel_default_console_device; void __init at32_setup_serial_console(unsigned int usart_id) { - atmel_default_console_device = setup_usart(usart_id); + atmel_default_console_device = at32_usarts[usart_id]; } /* -------------------------------------------------------------------- diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index 435507281f8..a39b3e999f1 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -17,6 +17,7 @@ struct atmel_uart_data { short use_dma_rx; /* use receive DMA? */ void __iomem *regs; /* virtual base address, if any */ }; +void at32_map_usart(unsigned int hw_id, unsigned int line); struct platform_device *at32_add_device_usart(unsigned int id); struct eth_platform_data { diff --git a/include/asm-avr32/arch-at32ap/init.h b/include/asm-avr32/arch-at32ap/init.h index 43722634e06..5e75d850d70 100644 --- a/include/asm-avr32/arch-at32ap/init.h +++ b/include/asm-avr32/arch-at32ap/init.h @@ -11,6 +11,7 @@ #define __ASM_AVR32_AT32AP_INIT_H__ void setup_platform(void); +void setup_board(void); /* Called by setup_platform */ void at32_clock_init(void); -- GitLab From 4d5e392c33820dc8861423bb1b8dae205ea0ad3d Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:11 +0200 Subject: [PATCH 0598/1619] [PATCH] atmel_serial: Fix roundoff error in atmel_console_get_options The atmel_console_get_options() function initializes the baud, parity and bits settings from the actual hardware setup, in case it has been initialized by a e.g. boot loader. The baud rate, however, is not necessarily exactly equal to one of the standard baud rates (115200, etc.) This means that the baud rate calculated by this function may be slightly higher or slightly lower than one of the standard baud rates. If the baud rate is slightly lower than the target, this causes problems when uart_set_option() tries to match the detected baud rate against the standard baud rate, as it will always select a baud rate that is lower or equal to the target rate. For example if the detected baud rate is slightly lower than 115200, usart_set_options() will select 57600. This patch fixes the problem by subtracting 1 from the value in BRGR when calculating the baud rate. The detected baud rate will thus always be higher than the nearest standard baud rate, and uart_set_options() will end up doing the right thing. Tested on ATSTK1000 and AT91RM9200-EK boards. Both are broken without this patch. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/atmel_serial.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 61db2166fbb..955c46da580 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -793,8 +793,14 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, else if (mr == ATMEL_US_PAR_ODD) *parity = 'o'; + /* + * The serial core only rounds down when matching this to a + * supported baud rate. Make sure we don't end up slightly + * lower than one of those, as it would make us fall through + * to a much lower baud rate than we really want. + */ quot = UART_GET_BRGR(port); - *baud = port->uartclk / (16 * (quot)); + *baud = port->uartclk / (16 * (quot - 1)); } static int __init atmel_console_setup(struct console *co, char *options) -- GitLab From f583f4924d669d36de677e0cc2422ee95203d444 Mon Sep 17 00:00:00 2001 From: David C Somayajulu Date: Wed, 4 Oct 2006 08:27:25 +0200 Subject: [PATCH 0599/1619] [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(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 83425fb3c8d..c847e17e5ca 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 1d79b8d4ca6..26f7856ff81 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 c247a28259b..cf4c219c0b5 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 */ -- GitLab From 2c2345c2b4fec30d12e1e1a6ee153a80af101e32 Mon Sep 17 00:00:00 2001 From: Roger Gammans Date: Wed, 4 Oct 2006 13:37:45 +0200 Subject: [PATCH 0600/1619] [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(-) diff --git a/include/linux/bio.h b/include/linux/bio.h index 711c321a701..092dbd0e765 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 406d4ae5763..750f085fa56 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 */ -- GitLab From e3bbff9f3cf91c84c76cfdd5e80041ad1b487192 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 3 Oct 2006 12:28:49 -0700 Subject: [PATCH 0601/1619] [SCSI] megaraid_sas: FW transition and q size changes This patch has the following enhancements : a. handles new transition states of FW to support controller hotplug. b. It reduces by 1 the maximum cmds that the driver may send to FW. c. Sends "Stop Processing" cmd to FW before returning failure from reset routine d. Adds print in megasas_transition routine e. Sends "RESET" flag to FW to do a soft reset of controller to move from Operational to Ready state. f. Sending correct pointer (cmd->sense) to pci_pool_free Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 35 +++++++++++++++++++++++----- drivers/scsi/megaraid/megaraid_sas.h | 11 +++++++-- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 4cab5b534b2..38733b6009a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -832,6 +832,12 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) } if (atomic_read(&instance->fw_outstanding)) { + /* + * Send signal to FW to stop processing any pending cmds. + * The controller will be taken offline by the OS now. + */ + writel(MFI_STOP_ADP, + &instance->reg_set->inbound_doorbell); instance->hw_crit_error = 1; return FAILED; } @@ -1229,10 +1235,12 @@ megasas_transition_to_ready(struct megasas_instance* instance) fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK; + if (fw_state != MFI_STATE_READY) + printk(KERN_INFO "megasas: Waiting for FW to come to ready" + " state\n"); + while (fw_state != MFI_STATE_READY) { - printk(KERN_INFO "megasas: Waiting for FW to come to ready" - " state\n"); switch (fw_state) { case MFI_STATE_FAULT: @@ -1244,19 +1252,27 @@ megasas_transition_to_ready(struct megasas_instance* instance) /* * Set the CLR bit in inbound doorbell */ - writel(MFI_INIT_CLEAR_HANDSHAKE, + writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, &instance->reg_set->inbound_doorbell); max_wait = 2; cur_state = MFI_STATE_WAIT_HANDSHAKE; break; + case MFI_STATE_BOOT_MESSAGE_PENDING: + writel(MFI_INIT_HOTPLUG, + &instance->reg_set->inbound_doorbell); + + max_wait = 10; + cur_state = MFI_STATE_BOOT_MESSAGE_PENDING; + break; + case MFI_STATE_OPERATIONAL: /* - * Bring it to READY state; assuming max wait 2 secs + * Bring it to READY state; assuming max wait 10 secs */ megasas_disable_intr(instance); - writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell); + writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell); max_wait = 10; cur_state = MFI_STATE_OPERATIONAL; @@ -1323,6 +1339,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) return -ENODEV; } }; + printk(KERN_INFO "megasas: FW now in Ready state\n"); return 0; } @@ -1352,7 +1369,7 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance) cmd->frame_phys_addr); if (cmd->sense) - pci_pool_free(instance->sense_dma_pool, cmd->frame, + pci_pool_free(instance->sense_dma_pool, cmd->sense, cmd->sense_phys_addr); } @@ -1690,6 +1707,12 @@ static int megasas_init_mfi(struct megasas_instance *instance) * Get various operational parameters from status register */ instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; + /* + * Reduce the max supported cmds by 1. This is to ensure that the + * reply_q_sz (1 more than the max cmd that driver may send) + * does not exceed max cmds that the FW can support + */ + instance->max_fw_cmds = instance->max_fw_cmds-1; instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> 0x10; /* diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3531a14222a..930c06d0a4f 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -50,6 +50,7 @@ #define MFI_STATE_WAIT_HANDSHAKE 0x60000000 #define MFI_STATE_FW_INIT_2 0x70000000 #define MFI_STATE_DEVICE_SCAN 0x80000000 +#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000 #define MFI_STATE_FLUSH_CACHE 0xA0000000 #define MFI_STATE_READY 0xB0000000 #define MFI_STATE_OPERATIONAL 0xC0000000 @@ -64,12 +65,18 @@ * READY : Move from OPERATIONAL to READY state; discard queue info * MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??) * CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver + * HOTPLUG : Resume from Hotplug + * MFI_STOP_ADP : Send signal to FW to stop processing */ -#define MFI_INIT_ABORT 0x00000000 +#define MFI_INIT_ABORT 0x00000001 #define MFI_INIT_READY 0x00000002 #define MFI_INIT_MFIMODE 0x00000004 #define MFI_INIT_CLEAR_HANDSHAKE 0x00000008 -#define MFI_RESET_FLAGS MFI_INIT_READY|MFI_INIT_MFIMODE +#define MFI_INIT_HOTPLUG 0x00000010 +#define MFI_STOP_ADP 0x00000020 +#define MFI_RESET_FLAGS MFI_INIT_READY| \ + MFI_INIT_MFIMODE| \ + MFI_INIT_ABORT /** * MFI frame flags -- GitLab From b1df99d9434edf3fc26f9e36ee6a443e3611e829 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 3 Oct 2006 12:40:47 -0700 Subject: [PATCH 0602/1619] [SCSI] megaraid_sas: frame count optimization This patch removes duplicated code in frame calculation & adds megasas_get_frame_count() that also takes into account the number of frames that can be contained in the Main frame. FW uses the frame count to pull sufficient number of frames from host memory. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 72 ++++++++++++++++++---------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 38733b6009a..e177fc5c5dd 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -495,6 +495,46 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp, return sge_count; } + /** + * megasas_get_frame_count - Computes the number of frames + * @sge_count : number of sg elements + * + * Returns the number of frames required for numnber of sge's (sge_count) + */ + +u32 megasas_get_frame_count(u8 sge_count) +{ + int num_cnt; + int sge_bytes; + u32 sge_sz; + u32 frame_count=0; + + sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : + sizeof(struct megasas_sge32); + + /* + * Main frame can contain 2 SGEs for 64-bit SGLs and + * 3 SGEs for 32-bit SGLs + */ + if (IS_DMA64) + num_cnt = sge_count - 2; + else + num_cnt = sge_count - 3; + + if(num_cnt>0){ + sge_bytes = sge_sz * num_cnt; + + frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) + + ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ; + } + /* Main frame */ + frame_count +=1; + + if (frame_count > 7) + frame_count = 8; + return frame_count; +} + /** * megasas_build_dcdb - Prepares a direct cdb (DCDB) command * @instance: Adapter soft state @@ -508,8 +548,6 @@ static int megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd *cmd) { - u32 sge_sz; - int sge_bytes; u32 is_logical; u32 device_id; u16 flags = 0; @@ -544,9 +582,6 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, /* * Construct SGL */ - sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : - sizeof(struct megasas_sge32); - if (IS_DMA64) { pthru->flags |= MFI_FRAME_SGL64; pthru->sge_count = megasas_make_sgl64(instance, scp, @@ -562,17 +597,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, pthru->sense_buf_phys_addr_hi = 0; pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr; - sge_bytes = sge_sz * pthru->sge_count; - /* * Compute the total number of frames this command consumes. FW uses * this number to pull sufficient number of frames from host memory. */ - cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) + - ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1; - - if (cmd->frame_count > 7) - cmd->frame_count = 8; + cmd->frame_count = megasas_get_frame_count(pthru->sge_count); return cmd->frame_count; } @@ -589,8 +618,6 @@ static int megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd *cmd) { - u32 sge_sz; - int sge_bytes; u32 device_id; u8 sc = scp->cmnd[0]; u16 flags = 0; @@ -605,7 +632,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, flags = MFI_FRAME_DIR_READ; /* - * Preare the Logical IO frame: 2nd bit is zero for all read cmds + * Prepare the Logical IO frame: 2nd bit is zero for all read cmds */ ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ; ldio->cmd_status = 0x0; @@ -674,9 +701,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, /* * Construct SGL */ - sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : - sizeof(struct megasas_sge32); - if (IS_DMA64) { ldio->flags |= MFI_FRAME_SGL64; ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl); @@ -690,13 +714,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, ldio->sense_buf_phys_addr_hi = 0; ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr; - sge_bytes = sge_sz * ldio->sge_count; - - cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) + - ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1; - - if (cmd->frame_count > 7) - cmd->frame_count = 8; + /* + * Compute the total number of frames this command consumes. FW uses + * this number to pull sufficient number of frames from host memory. + */ + cmd->frame_count = megasas_get_frame_count(ldio->sge_count); return cmd->frame_count; } -- GitLab From b274cab779219325fd480cc696a456d1c3893bd8 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 3 Oct 2006 12:52:12 -0700 Subject: [PATCH 0603/1619] [SCSI] megaraid_sas: function pointer for disable interrupt This patch adds function pointer to invoke disable interrupt for xscale and ppc IOP based controllers. Removes old implementation that checks for controller type in megasas_disable_intr. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 55 ++++++++++++++++------------ drivers/scsi/megaraid/megaraid_sas.h | 1 + 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index e177fc5c5dd..c3b50b37579 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -134,6 +134,19 @@ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs) readl(®s->outbound_intr_mask); } +/** + * megasas_disable_intr_xscale -Disables interrupt + * @regs: MFI register set + */ +static inline void +megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs) +{ + u32 mask = 0x1f; + writel(mask, ®s->outbound_intr_mask); + /* Dummy readl to force pci flush */ + readl(®s->outbound_intr_mask); +} + /** * megasas_read_fw_status_reg_xscale - returns the current FW status value * @regs: MFI register set @@ -185,6 +198,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = { .fire_cmd = megasas_fire_cmd_xscale, .enable_intr = megasas_enable_intr_xscale, + .disable_intr = megasas_disable_intr_xscale, .clear_intr = megasas_clear_intr_xscale, .read_fw_status_reg = megasas_read_fw_status_reg_xscale, }; @@ -214,6 +228,19 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs) readl(®s->outbound_intr_mask); } +/** + * megasas_disable_intr_ppc - Disable interrupt + * @regs: MFI register set + */ +static inline void +megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs) +{ + u32 mask = 0xFFFFFFFF; + writel(mask, ®s->outbound_intr_mask); + /* Dummy readl to force pci flush */ + readl(®s->outbound_intr_mask); +} + /** * megasas_read_fw_status_reg_ppc - returns the current FW status value * @regs: MFI register set @@ -265,6 +292,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = { .fire_cmd = megasas_fire_cmd_ppc, .enable_intr = megasas_enable_intr_ppc, + .disable_intr = megasas_disable_intr_ppc, .clear_intr = megasas_clear_intr_ppc, .read_fw_status_reg = megasas_read_fw_status_reg_ppc, }; @@ -274,25 +302,6 @@ static struct megasas_instance_template megasas_instance_template_ppc = { * specific to ppc (deviceid : 0x60) controllers */ -/** - * megasas_disable_intr - Disables interrupts - * @regs: MFI register set - */ -static inline void -megasas_disable_intr(struct megasas_instance *instance) -{ - u32 mask = 0x1f; - struct megasas_register_set __iomem *regs = instance->reg_set; - - if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R) - mask = 0xffffffff; - - writel(mask, ®s->outbound_intr_mask); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - /** * megasas_issue_polled - Issues a polling command * @instance: Adapter soft state @@ -1293,7 +1302,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) /* * Bring it to READY state; assuming max wait 10 secs */ - megasas_disable_intr(instance); + instance->instancet->disable_intr(instance->reg_set); writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell); max_wait = 10; @@ -1799,7 +1808,7 @@ static int megasas_init_mfi(struct megasas_instance *instance) /* * disable the intr before firing the init frame to FW */ - megasas_disable_intr(instance); + instance->instancet->disable_intr(instance->reg_set); /* * Issue the init frame in polled mode @@ -2279,7 +2288,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) megasas_mgmt_info.max_index--; pci_set_drvdata(pdev, NULL); - megasas_disable_intr(instance); + instance->instancet->disable_intr(instance->reg_set); free_irq(instance->pdev->irq, instance); megasas_release_mfi(instance); @@ -2409,7 +2418,7 @@ static void megasas_detach_one(struct pci_dev *pdev) pci_set_drvdata(instance->pdev, NULL); - megasas_disable_intr(instance); + instance->instancet->disable_intr(instance->reg_set); free_irq(instance->pdev->irq, instance); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 930c06d0a4f..74feffe2fff 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1049,6 +1049,7 @@ struct megasas_evt_detail { void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *); void (*enable_intr)(struct megasas_register_set __iomem *) ; + void (*disable_intr)(struct megasas_register_set __iomem *); int (*clear_intr)(struct megasas_register_set __iomem *); -- GitLab From 658dcedb4e35d77f7f6552b5a640d7d82c372053 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 3 Oct 2006 13:09:14 -0700 Subject: [PATCH 0604/1619] [SCSI] megaraid_sas: prints pending cmds before setting hw_crit_error This patch adds function to print the pending frame details before returning failure from the reset routine. It also exposes a new variable megasas_dbg_lvl that allows the user to set the debug level for logging. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 92 ++++++++++++++++++++++++++++ drivers/scsi/megaraid/megaraid_sas.h | 2 + 2 files changed, 94 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index c3b50b37579..0791d62b167 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -71,6 +71,8 @@ static struct megasas_mgmt_info megasas_mgmt_info; static struct fasync_struct *megasas_async_queue; static DEFINE_MUTEX(megasas_async_queue_mutex); +static u32 megasas_dbg_lvl; + /** * megasas_get_cmd - Get a command from the free pool * @instance: Adapter soft state @@ -758,6 +760,69 @@ static inline int megasas_is_ldio(struct scsi_cmnd *cmd) } } + /** + * megasas_dump_pending_frames - Dumps the frame address of all pending cmds + * in FW + * @instance: Adapter soft state + */ +static inline void +megasas_dump_pending_frames(struct megasas_instance *instance) +{ + struct megasas_cmd *cmd; + int i,n; + union megasas_sgl *mfi_sgl; + struct megasas_io_frame *ldio; + struct megasas_pthru_frame *pthru; + u32 sgcount; + u32 max_cmd = instance->max_fw_cmds; + + printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no); + printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding)); + if (IS_DMA64) + printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no); + else + printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no); + + printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no); + for (i = 0; i < max_cmd; i++) { + cmd = instance->cmd_list[i]; + if(!cmd->scmd) + continue; + printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); + if (megasas_is_ldio(cmd->scmd)){ + ldio = (struct megasas_io_frame *)cmd->frame; + mfi_sgl = &ldio->sgl; + sgcount = ldio->sge_count; + printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount); + } + else { + pthru = (struct megasas_pthru_frame *) cmd->frame; + mfi_sgl = &pthru->sgl; + sgcount = pthru->sge_count; + printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount); + } + if(megasas_dbg_lvl & MEGASAS_DBG_LVL){ + for (n = 0; n < sgcount; n++){ + if (IS_DMA64) + printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ; + else + printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ; + } + } + printk(KERN_ERR "\n"); + } /*for max_cmd*/ + printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no); + for (i = 0; i < max_cmd; i++) { + + cmd = instance->cmd_list[i]; + + if(cmd->sync_cmd == 1){ + printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr); + } + } + printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no); +} + /** * megasas_queue_command - Queue entry point * @scmd: SCSI command to be queued @@ -869,6 +934,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) */ writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); + megasas_dump_pending_frames(instance); instance->hw_crit_error = 1; return FAILED; } @@ -2236,6 +2302,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance->unique_id = pdev->bus->number << 8 | pdev->devfn; instance->init_id = MEGASAS_DEFAULT_INIT_ID; + megasas_dbg_lvl = 0; + /* * Initialize MFI Firmware */ @@ -2862,6 +2930,26 @@ megasas_sysfs_show_release_date(struct device_driver *dd, char *buf) static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date, NULL); +static ssize_t +megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf) +{ + return sprintf(buf,"%u",megasas_dbg_lvl); +} + +static ssize_t +megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count) +{ + int retval = count; + if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){ + printk(KERN_ERR "megasas: could not set dbg_lvl\n"); + retval = -EINVAL; + } + return retval; +} + +static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl, + megasas_sysfs_set_dbg_lvl); + /** * megasas_init - Driver load entry point */ @@ -2902,6 +2990,8 @@ static int __init megasas_init(void) driver_create_file(&megasas_pci_driver.driver, &driver_attr_version); driver_create_file(&megasas_pci_driver.driver, &driver_attr_release_date); + driver_create_file(&megasas_pci_driver.driver, + &driver_attr_dbg_lvl); return rval; } @@ -2914,6 +3004,8 @@ static void __exit megasas_exit(void) driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_release_date); + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_dbg_lvl); pci_unregister_driver(&megasas_pci_driver); unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 74feffe2fff..ad7ef744406 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -537,6 +537,8 @@ struct megasas_ctrl_info { #define MEGASAS_MAX_LUN 8 #define MEGASAS_MAX_LD 64 +#define MEGASAS_DBG_LVL 1 + /* * When SCSI mid-layer calls driver's reset routine, driver waits for * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note -- GitLab From 5d018ad057347995e5c4564b3e43339e6497f839 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 3 Oct 2006 13:13:18 -0700 Subject: [PATCH 0605/1619] [SCSI] megaraid_sas: adds tasklet for cmd completion This patch adds a tasklet for command completion. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 66 ++++++++++++++++++---------- drivers/scsi/megaraid/megaraid_sas.h | 1 + 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 0791d62b167..c730bb14543 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -1271,11 +1271,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, static int megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) { - u32 producer; - u32 consumer; - u32 context; - struct megasas_cmd *cmd; - /* * Check if it is our interrupt * Clear the interrupt @@ -1283,23 +1278,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) if(instance->instancet->clear_intr(instance->reg_set)) return IRQ_NONE; - producer = *instance->producer; - consumer = *instance->consumer; - - while (consumer != producer) { - context = instance->reply_queue[consumer]; - - cmd = instance->cmd_list[context]; - - megasas_complete_cmd(instance, cmd, alt_status); - - consumer++; - if (consumer == (instance->max_fw_cmds + 1)) { - consumer = 0; - } - } - - *instance->consumer = producer; + /* + * Schedule the tasklet for cmd completion + */ + tasklet_schedule(&instance->isr_tasklet); return IRQ_HANDLED; } @@ -1741,6 +1723,39 @@ megasas_get_ctrl_info(struct megasas_instance *instance, return ret; } +/** + * megasas_complete_cmd_dpc - Returns FW's controller structure + * @instance_addr: Address of adapter soft state + * + * Tasklet to complete cmds + */ +void megasas_complete_cmd_dpc(unsigned long instance_addr) +{ + u32 producer; + u32 consumer; + u32 context; + struct megasas_cmd *cmd; + struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + + producer = *instance->producer; + consumer = *instance->consumer; + + while (consumer != producer) { + context = instance->reply_queue[consumer]; + + cmd = instance->cmd_list[context]; + + megasas_complete_cmd(instance, cmd, DID_OK); + + consumer++; + if (consumer == (instance->max_fw_cmds + 1)) { + consumer = 0; + } + } + + *instance->consumer = producer; +} + /** * megasas_init_mfi - Initializes the FW * @instance: Adapter soft state @@ -1911,6 +1926,12 @@ static int megasas_init_mfi(struct megasas_instance *instance) kfree(ctrl_info); + /* + * Setup tasklet for cmd completion + */ + + tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, + (unsigned long)instance); return 0; fail_fw_init: @@ -2470,6 +2491,7 @@ static void megasas_detach_one(struct pci_dev *pdev) scsi_remove_host(instance->host); megasas_flush_cache(instance); megasas_shutdown_controller(instance); + tasklet_kill(&instance->isr_tasklet); /* * Take the instance off the instance array. Note that we will not diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index ad7ef744406..c79e55aa916 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1102,6 +1102,7 @@ struct megasas_instance { u32 hw_crit_error; struct megasas_instance_template *instancet; + struct tasklet_struct isr_tasklet; }; #define MEGASAS_IS_LOGICAL(scp) \ -- GitLab From 2a3681e56e825bce469d2ccf3c85741b5005e1f1 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 3 Oct 2006 13:19:21 -0700 Subject: [PATCH 0606/1619] [SCSI] megaraid_sas: sets ioctl timeout and updates version,changelog This patch sets timeout of max 180 seconds for ioctl completion. It also updates the Changelog and hikes the version to 3.05. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- Documentation/scsi/ChangeLog.megaraid_sas | 45 +++++++++++++++++++++++ drivers/scsi/megaraid/megaraid_sas.c | 12 ++++-- drivers/scsi/megaraid/megaraid_sas.h | 7 ++-- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas index d9e5960dafd..5eb92754499 100644 --- a/Documentation/scsi/ChangeLog.megaraid_sas +++ b/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,4 +1,49 @@ +1 Release Date : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro +2 Current Version : 00.00.03.05 +3 Older Version : 00.00.03.04 + +i. PCI_DEVICE macro used + + Convert the pci_device_id-table of the megaraid_sas-driver to the PCI_DEVICE-macro, to safe some lines. + + - Henrik Kretzschmar +ii. All compiler warnings removed +iii. megasas_ctrl_info struct reverted to 3.02 release +iv. Default value of megasas_dbg_lvl set to 0 +v. Removing in megasas_exit the sysfs entry created for megasas_dbg_lvl +vi. In megasas_teardown_frame_pool(), cmd->frame was passed instead of + cmd->sense to pci_pool_free. Fixed. Bug was pointed out by + Eric Sesterhenn + +1 Release Date : Wed Sep 13 14:22:51 PDT 2006 - Sumant Patro +2 Current Version : 00.00.03.04 +3 Older Version : 00.00.03.03 + +i. Added Reboot notify +ii. Reduced by 1 max cmds sent to FW from Driver to make the reply_q_sz same + as Max Cmds FW can support + +1 Release Date : Tue Aug 22 16:33:14 PDT 2006 - Sumant Patro +2 Current Version : 00.00.03.03 +3 Older Version : 00.00.03.02 + +i. Send stop adapter to FW & Dump pending FW cmds before declaring adapter dead. + New varible added to set dbg level. +ii. Disable interrupt made as fn pointer as they are different for 1068 / 1078 +iii. Frame count optimization. Main frame can contain 2 SGE for 64 bit SGLs and + 3 SGE for 32 bit SGL +iv. Tasklet added for cmd completion +v. If FW in operational state before firing INIT, now we send RESET Flag to FW instead of just READY. This is used to do soft reset. +vi. megasas_ctrl_prop structure updated (based on FW struct) +vii. Added print : FW now in Ready State during initialization + +1 Release Date : Sun Aug 06 22:49:52 PDT 2006 - Sumant Patro +2 Current Version : 00.00.03.02 +3 Older Version : 00.00.03.01 + +i. Added FW tranistion state for Hotplug scenario + 1 Release Date : Sun May 14 22:49:52 PDT 2006 - Sumant Patro 2 Current Version : 00.00.03.01 3 Older Version : 00.00.02.04 diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index c730bb14543..e21f638c00a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.01 + * Version : v00.00.03.05 * * Authors: * Sreenivas Bagalkote @@ -347,6 +347,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) * @cmd: Command to be issued * * This function waits on an event for the command to be returned from ISR. + * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs * Used to issue ioctl commands. */ static int @@ -357,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set); - wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA)); + wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA), + MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); return 0; } @@ -369,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, * * MFI firmware can abort previously issued AEN comamnd (automatic event * notification). The megasas_issue_blocked_abort_cmd() issues such abort - * cmd and blocks till it is completed. + * cmd and waits for return status. + * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs */ static int megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, @@ -403,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, /* * Wait for this cmd to complete */ - wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF)); + wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF), + MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); megasas_return_cmd(instance, cmd); return 0; diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index c79e55aa916..55eddcf8eb1 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,9 @@ /** * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.03.01" -#define MEGASAS_RELDATE "May 14, 2006" -#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006" +#define MEGASAS_VERSION "00.00.03.05" +#define MEGASAS_RELDATE "Oct 02, 2006" +#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006" /* * Device IDs @@ -547,6 +547,7 @@ struct megasas_ctrl_info { * every MEGASAS_RESET_NOTICE_INTERVAL seconds */ #define MEGASAS_RESET_WAIT_TIME 180 +#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180 #define MEGASAS_RESET_NOTICE_INTERVAL 5 #define MEGASAS_IOCTL_CMD 0 -- GitLab From aa97b102527ff94fe04930a660f897ef2bafb2a8 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 4 Oct 2006 20:01:52 +0200 Subject: [PATCH 0607/1619] [S390] update default configuration Signed-off-by: Martin Schwidefsky --- arch/s390/defconfig | 56 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 35da53986b1..62950f53ef5 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc2 -# Thu Jul 27 13:51:07 2006 +# Linux kernel version: 2.6.18 +# Wed Oct 4 19:45:46 2006 # CONFIG_MMU=y CONFIG_LOCKDEP_SUPPORT=y @@ -26,10 +26,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -CONFIG_SYSCTL=y +# CONFIG_UTS_NS is not set CONFIG_AUDIT=y # CONFIG_AUDITSYSCALL is not set CONFIG_IKCONFIG=y @@ -38,7 +39,9 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -47,12 +50,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -71,6 +74,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_BLK_DEV_IO_TRACE is not set # @@ -100,6 +104,7 @@ CONFIG_HOTPLUG_CPU=y CONFIG_DEFAULT_MIGRATION_COST=1000000 CONFIG_COMPAT=y CONFIG_SYSVIPC_COMPAT=y +CONFIG_AUDIT_ARCH=y # # Code generation options @@ -107,6 +112,7 @@ CONFIG_SYSVIPC_COMPAT=y # CONFIG_MARCH_G5 is not set CONFIG_MARCH_Z900=y # CONFIG_MARCH_Z990 is not set +# CONFIG_MARCH_Z9_109 is not set CONFIG_PACK_STACK=y # CONFIG_SMALL_STACK is not set CONFIG_CHECK_STACK=y @@ -165,6 +171,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set CONFIG_NET_KEY=y CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -183,21 +190,28 @@ CONFIG_IP_FIB_HASH=y # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_IPV6_ROUTER_PREF is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set CONFIG_INET6_XFRM_MODE_TRANSPORT=y CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set # CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set @@ -224,7 +238,6 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=y # 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 @@ -301,6 +314,7 @@ CONFIG_SYS_HYPERVISOR=y # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -322,18 +336,18 @@ CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # # CONFIG_ISCSI_TCP is not set -# CONFIG_SCSI_SATA is not set # CONFIG_SCSI_DEBUG is not set CONFIG_ZFCP=y CONFIG_CCW=y @@ -378,6 +392,7 @@ CONFIG_MD_RAID1=m CONFIG_MD_MULTIPATH=m # CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set CONFIG_DM_CRYPT=y CONFIG_DM_SNAPSHOT=y CONFIG_DM_MIRROR=y @@ -487,14 +502,12 @@ CONFIG_IUCV=m # CONFIG_NETIUCV is not set # CONFIG_SMSGIUCV is not set # CONFIG_CLAW is not set -# CONFIG_MPC is not set CONFIG_QETH=y # # Gigabit Ethernet default settings # # CONFIG_QETH_IPV6 is not set -# CONFIG_QETH_PERF_STATS is not set CONFIG_CCWGROUP=y # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -518,8 +531,9 @@ CONFIG_JBD=y CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set +CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -549,8 +563,10 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set @@ -598,6 +614,7 @@ CONFIG_SUNRPC=y # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # CONFIG_9P_FS is not set +CONFIG_GENERIC_ACL=y # # Partition Types @@ -626,11 +643,18 @@ CONFIG_MSDOS_PARTITION=y # # CONFIG_NLS is not set +# +# Distributed Lock Manager +# + # # Instrumentation Support # + +# +# Profiling support +# # CONFIG_PROFILING is not set -CONFIG_STATISTICS=y CONFIG_KPROBES=y # @@ -638,6 +662,7 @@ CONFIG_KPROBES=y # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y @@ -659,10 +684,12 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FRAME_POINTER is not set # CONFIG_UNWIND_INFO is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set # # Security options @@ -674,6 +701,9 @@ CONFIG_FORCED_INLINING=y # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_MANAGER=m # CONFIG_CRYPTO_HMAC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set @@ -685,6 +715,8 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_DES_S390 is not set # CONFIG_CRYPTO_BLOWFISH is not set -- GitLab From b05e37035298148b6c311eccf06ac50fd389f0b2 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 4 Oct 2006 20:01:58 +0200 Subject: [PATCH 0608/1619] [S390] user-copy optimization fallout. Fix new restore_sigregs function. It copies the user space copy of the old psw without correcting the psw.mask and the psw.addr high order bit. While we are at it, simplify save_sigregs a bit. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/signal.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 642095ec7c0..4392a77cbae 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -113,17 +113,15 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, /* Returns non-zero on fault. */ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { - unsigned long old_mask = regs->psw.mask; _sigregs user_sregs; save_access_regs(current->thread.acrs); /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ - regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); - memcpy(&user_sregs.regs.psw, ®s->psw, sizeof(sregs->regs.psw) + - sizeof(sregs->regs.gprs)); - regs->psw.mask = old_mask; + user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); + user_sregs.regs.psw.addr = regs->psw.addr; + memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); memcpy(&user_sregs.regs.acrs, current->thread.acrs, sizeof(sregs->regs.acrs)); /* @@ -139,7 +137,6 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) /* Returns positive number on error */ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { - unsigned long old_mask = regs->psw.mask; int err; _sigregs user_sregs; @@ -147,12 +144,12 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) current_thread_info()->restart_block.fn = do_no_restart_syscall; err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); - regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask); - regs->psw.addr |= PSW_ADDR_AMODE; if (err) return err; - memcpy(®s->psw, &user_sregs.regs.psw, sizeof(sregs->regs.psw) + - sizeof(sregs->regs.gprs)); + regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask, + user_sregs.regs.psw.mask); + regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr; + memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, sizeof(sregs->regs.acrs)); restore_access_regs(current->thread.acrs); -- GitLab From f1ee3281bedbbca70a1f53bc715ea6f27c616052 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 4 Oct 2006 20:02:02 +0200 Subject: [PATCH 0609/1619] [S390] Add timeouts during sense PGID, path verification and disband PGID. While the machine owns us an interrupt in these cases (and we should get one), reality isn't always like that... Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 2 ++ drivers/s390/cio/device_ops.c | 3 +++ drivers/s390/cio/device_pgid.c | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index dace46fc32e..b67620208f3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -349,6 +349,8 @@ ccw_device_done(struct ccw_device *cdev, int state) sch = to_subchannel(cdev->dev.parent); + ccw_device_set_timeout(cdev, 0); + if (state != DEV_STATE_ONLINE) cio_disable_subchannel(sch); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 93a897eebff..e7eeaf1c182 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -216,6 +216,9 @@ ccw_device_call_handler(struct ccw_device *cdev) (stctl & SCSW_STCTL_PRIM_STATUS))) return 0; + /* Clear pending timers for device driver initiated I/O. */ + if (ending_status) + ccw_device_set_timeout(cdev, 0); /* * Now we are ready to call the device driver interrupt handler. */ diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 8ca2d078848..84917b39de4 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -96,6 +96,9 @@ ccw_device_sense_pgid_start(struct ccw_device *cdev) { int ret; + /* Set a timeout of 60s */ + ccw_device_set_timeout(cdev, 60*HZ); + cdev->private->state = DEV_STATE_SENSE_PGID; cdev->private->imask = 0x80; cdev->private->iretry = 5; @@ -480,6 +483,8 @@ ccw_device_verify_start(struct ccw_device *cdev) ccw_device_verify_done(cdev, -ENODEV); return; } + /* After 60s path verification is considered to have failed. */ + ccw_device_set_timeout(cdev, 60*HZ); __ccw_device_verify_start(cdev); } @@ -554,6 +559,9 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event) void ccw_device_disband_start(struct ccw_device *cdev) { + /* After 60s disbanding is considered to have failed. */ + ccw_device_set_timeout(cdev, 60*HZ); + cdev->private->flags.pgid_single = 0; cdev->private->iretry = 5; cdev->private->imask = 0x80; -- GitLab From 4e56296d471a827fdd244cfdb6a1e62fc3af7af0 Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Wed, 4 Oct 2006 20:02:05 +0200 Subject: [PATCH 0610/1619] [S390] zcrypt device registration/unregistration race. Fix a race condition during AP device registration and unregistration. Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 6ed0985c0c9..cd30f37fcea 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -449,8 +449,6 @@ static int ap_device_probe(struct device *dev) ap_dev->drv = ap_drv; rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; - if (rc) - ap_dev->unregistered = 1; return rc; } @@ -487,14 +485,7 @@ static int ap_device_remove(struct device *dev) struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = ap_dev->drv; - spin_lock_bh(&ap_dev->lock); - __ap_flush_queue(ap_dev); - /** - * set ->unregistered to 1 while holding the lock. This prevents - * new messages to be put on the queue from now on. - */ - ap_dev->unregistered = 1; - spin_unlock_bh(&ap_dev->lock); + ap_flush_queue(ap_dev); if (ap_drv->remove) ap_drv->remove(ap_dev); return 0; @@ -763,6 +754,7 @@ static void ap_scan_bus(void *data) break; ap_dev->qid = qid; ap_dev->queue_depth = queue_depth; + ap_dev->unregistered = 1; spin_lock_init(&ap_dev->lock); INIT_LIST_HEAD(&ap_dev->pendingq); INIT_LIST_HEAD(&ap_dev->requestq); @@ -784,7 +776,12 @@ static void ap_scan_bus(void *data) /* Add device attributes. */ rc = sysfs_create_group(&ap_dev->device.kobj, &ap_dev_attr_group); - if (rc) + if (!rc) { + spin_lock_bh(&ap_dev->lock); + ap_dev->unregistered = 0; + spin_unlock_bh(&ap_dev->lock); + } + else device_unregister(&ap_dev->device); } } @@ -970,6 +967,8 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) rc = __ap_queue_message(ap_dev, ap_msg); if (!rc) wake_up(&ap_poll_wait); + if (rc == -ENODEV) + ap_dev->unregistered = 1; } else { ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); rc = 0; @@ -1028,6 +1027,8 @@ static int __ap_poll_all(struct device *dev, void *data) spin_lock(&ap_dev->lock); if (!ap_dev->unregistered) { rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data); + if (rc) + ap_dev->unregistered = 1; } else rc = 0; spin_unlock(&ap_dev->lock); -- GitLab From 8abfe01dae8c0ed7ca6bfb153a7fcab47df72a52 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 4 Oct 2006 20:02:09 +0200 Subject: [PATCH 0611/1619] [S390] Wire up sys_getcpu system call. Signed-off-by: Heiko Carstens --- arch/s390/kernel/compat_wrapper.S | 7 +++++++ arch/s390/kernel/syscalls.S | 2 ++ include/asm-s390/unistd.h | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 4aabeeaa7cf..cb0efae6802 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1658,3 +1658,10 @@ compat_sys_vmsplice_wrapper: llgfr %r4,%r4 # unsigned int llgfr %r5,%r5 # unsigned int jg compat_sys_vmsplice + + .globl sys_getcpu_wrapper +sys_getcpu_wrapper: + llgtr %r2,%r2 # unsigned * + llgtr %r3,%r3 # unsigned * + llgtr %r4,%r4 # struct getcpu_cache * + jg sys_tee diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 93be1d56c03..e59baec5652 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -318,3 +318,5 @@ SYSCALL(sys_splice,sys_splice,sys_splice_wrapper) SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper) SYSCALL(sys_tee,sys_tee,sys_tee_wrapper) SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper) +NI_SYSCALL /* 310 sys_move_pages */ +SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper) diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 0cccfd83c45..a19238cbcff 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -247,8 +247,10 @@ #define __NR_sync_file_range 307 #define __NR_tee 308 #define __NR_vmsplice 309 +/* Number 310 is reserved for new sys_move_pages */ +#define __NR_getcpu 311 -#define NR_syscalls 310 +#define NR_syscalls 312 /* * There are some system calls that are not present on 64 bit, some -- GitLab From 42e47eeb8fb3f9d2abe653cc7f185816068a057d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 4 Oct 2006 20:02:12 +0200 Subject: [PATCH 0612/1619] [S390] incorrect placement of include. The include of linux/smp.h needs to be done before the #if that checks for the compiler version. Seems like fallout from the inline assembly cleanup patch vs. the directed yield patch. Signed-off-by: Martin Schwidefsky --- include/asm-s390/spinlock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h index 6b78af16999..3fd43826fd0 100644 --- a/include/asm-s390/spinlock.h +++ b/include/asm-s390/spinlock.h @@ -11,10 +11,10 @@ #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - #include +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) + static inline int _raw_compare_and_swap(volatile unsigned int *lock, unsigned int old, unsigned int new) -- GitLab From cb601d41c175b7419efc91075a714d6a157bb0ac Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 4 Oct 2006 20:02:15 +0200 Subject: [PATCH 0613/1619] [S390] Remove crept in whitespace from head*.S again. Signed-off-by: Heiko Carstens --- arch/s390/kernel/head31.S | 8 ++++---- arch/s390/kernel/head64.S | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 1b952a3664e..0a2c929486a 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -258,10 +258,10 @@ startup_continue: # find out if the diag 0x9c is available # mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13) - stap __LC_CPUID+4 # store cpu address - lh %r1,__LC_CPUID+4 - diag %r1,0,0x9c # test diag 0x9c - oi 2(%r12),1 # set diag9c flag + stap __LC_CPUID+4 # store cpu address + lh %r1,__LC_CPUID+4 + diag %r1,0,0x9c # test diag 0x9c + oi 2(%r12),1 # set diag9c flag .Lchkdiag9c: lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index b30e5897cdf..42f54d48244 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -253,12 +253,12 @@ startup_continue: # # find out if the diag 0x9c is available # - la %r1,0f-.LPG1(%r13) # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - stap __LC_CPUID+4 # store cpu address - lh %r1,__LC_CPUID+4 - diag %r1,0,0x9c # test diag 0x9c - oi 6(%r12),1 # set diag9c flag + la %r1,0f-.LPG1(%r13) # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + stap __LC_CPUID+4 # store cpu address + lh %r1,__LC_CPUID+4 + diag %r1,0,0x9c # test diag 0x9c + oi 6(%r12),1 # set diag9c flag 0: # -- GitLab From 7676bef9c183fd573822cac9992927ef596d584c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 4 Oct 2006 20:02:19 +0200 Subject: [PATCH 0614/1619] [S390] Have s390 use add_active_range() and free_area_init_nodes. Size zones and holes in an architecture independent manner for s390. Signed-off-by: Heiko Carstens --- arch/s390/Kconfig | 3 +++ arch/s390/defconfig | 1 + arch/s390/kernel/setup.c | 55 ++++++++++------------------------------ arch/s390/mm/init.c | 35 ++++++++----------------- 4 files changed, 27 insertions(+), 67 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f900a516f09..51c2dfe89c6 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -233,6 +233,9 @@ config WARN_STACK_SIZE This allows you to specify the maximum frame size a function may have without the compiler complaining about it. +config ARCH_POPULATES_NODE_MAP + def_bool y + source "mm/Kconfig" comment "I/O subsystem configuration" diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 62950f53ef5..b6cad75fd1f 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -118,6 +118,7 @@ CONFIG_PACK_STACK=y CONFIG_CHECK_STACK=y CONFIG_STACK_GUARD=256 # CONFIG_WARN_STACK is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index a21cfbb9d97..49f2b68e32b 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -70,7 +70,6 @@ struct { #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ -unsigned long __initdata zholes_size[MAX_NR_ZONES]; static unsigned long __initdata memory_end; /* @@ -358,21 +357,6 @@ void machine_power_off(void) */ void (*pm_power_off)(void) = machine_power_off; -static void __init -add_memory_hole(unsigned long start, unsigned long end) -{ - unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; - - if (end <= dma_pfn) - zholes_size[ZONE_DMA] += end - start + 1; - else if (start > dma_pfn) - zholes_size[ZONE_NORMAL] += end - start + 1; - else { - zholes_size[ZONE_DMA] += dma_pfn - start + 1; - zholes_size[ZONE_NORMAL] += end - dma_pfn; - } -} - static int __init early_parse_mem(char *p) { memory_end = memparse(p, &p); @@ -494,7 +478,6 @@ setup_memory(void) { unsigned long bootmap_size; unsigned long start_pfn, end_pfn, init_pfn; - unsigned long last_rw_end; int i; /* @@ -543,46 +526,34 @@ setup_memory(void) #endif /* - * Initialize the boot-time allocator (with low memory only): + * Initialize the boot-time allocator */ bootmap_size = init_bootmem(start_pfn, end_pfn); /* * Register RAM areas with the bootmem allocator. */ - last_rw_end = start_pfn; for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { - unsigned long start_chunk, end_chunk; + unsigned long start_chunk, end_chunk, pfn; if (memory_chunk[i].type != CHUNK_READ_WRITE) continue; - start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1); - start_chunk >>= PAGE_SHIFT; - end_chunk = (memory_chunk[i].addr + memory_chunk[i].size); - end_chunk >>= PAGE_SHIFT; - if (start_chunk < start_pfn) - start_chunk = start_pfn; - if (end_chunk > end_pfn) - end_chunk = end_pfn; - if (start_chunk < end_chunk) { - /* Initialize storage key for RAM pages */ - for (init_pfn = start_chunk ; init_pfn < end_chunk; - init_pfn++) - page_set_storage_key(init_pfn << PAGE_SHIFT, - PAGE_DEFAULT_KEY); - free_bootmem(start_chunk << PAGE_SHIFT, - (end_chunk - start_chunk) << PAGE_SHIFT); - if (last_rw_end < start_chunk) - add_memory_hole(last_rw_end, start_chunk - 1); - last_rw_end = end_chunk; - } + start_chunk = PFN_DOWN(memory_chunk[i].addr); + end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1; + end_chunk = min(end_chunk, end_pfn); + if (start_chunk >= end_chunk) + continue; + add_active_range(0, start_chunk, end_chunk); + pfn = max(start_chunk, start_pfn); + for (; pfn <= end_chunk; pfn++) + page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY); } psw_set_key(PAGE_DEFAULT_KEY); - if (last_rw_end < end_pfn - 1) - add_memory_hole(last_rw_end, end_pfn - 1); + free_bootmem_with_active_regions(0, max_pfn); + reserve_bootmem(0, PFN_PHYS(start_pfn)); /* * Reserve the bootmem bitmap itself as well. We do this in two diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 127044e1707..c302508ae31 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -82,7 +82,6 @@ void show_mem(void) printk("%d pages swap cached\n",cached); } -extern unsigned long __initdata zholes_size[]; /* * paging_init() sets up the page tables */ @@ -99,16 +98,15 @@ void __init paging_init(void) unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; static const int ssm_mask = 0x04000000L; unsigned long ro_start_pfn, ro_end_pfn; - unsigned long zones_size[MAX_NR_ZONES]; + unsigned long max_zone_pfns[MAX_NR_ZONES]; ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata); ro_end_pfn = PFN_UP((unsigned long)&__end_rodata); - memset(zones_size, 0, sizeof(zones_size)); - zones_size[ZONE_DMA] = max_low_pfn; - free_area_init_node(0, &contig_page_data, zones_size, - __pa(PAGE_OFFSET) >> PAGE_SHIFT, - zholes_size); + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = max_low_pfn; + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + free_area_init_nodes(max_zone_pfns); /* unmap whole virtual address space */ @@ -153,7 +151,6 @@ void __init paging_init(void) __raw_local_irq_ssm(ssm_mask); local_flush_tlb(); - return; } #else /* CONFIG_64BIT */ @@ -169,26 +166,16 @@ void __init paging_init(void) unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE; static const int ssm_mask = 0x04000000L; - unsigned long zones_size[MAX_NR_ZONES]; - unsigned long dma_pfn, high_pfn; unsigned long ro_start_pfn, ro_end_pfn; + unsigned long max_zone_pfns[MAX_NR_ZONES]; - memset(zones_size, 0, sizeof(zones_size)); - dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; - high_pfn = max_low_pfn; ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata); ro_end_pfn = PFN_UP((unsigned long)&__end_rodata); - if (dma_pfn > high_pfn) - zones_size[ZONE_DMA] = high_pfn; - else { - zones_size[ZONE_DMA] = dma_pfn; - zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; - } - - /* Initialize mem_map[]. */ - free_area_init_node(0, &contig_page_data, zones_size, - __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS); + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + free_area_init_nodes(max_zone_pfns); /* * map whole physical memory to virtual memory (identity mapping) @@ -237,8 +224,6 @@ void __init paging_init(void) __raw_local_irq_ssm(ssm_mask); local_flush_tlb(); - - return; } #endif /* CONFIG_64BIT */ -- GitLab From 0b2b6e1ddce4696cb7afcbb15a654fe95428a498 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 4 Oct 2006 20:02:23 +0200 Subject: [PATCH 0615/1619] [S390] Remove open-coded mem_map usage. Use page_to_phys and pfn_to_page to avoid open-coded mem_map usage. Signed-off-by: Heiko Carstens --- arch/s390/mm/init.c | 10 ++++++---- include/asm-s390/io.h | 5 ----- include/asm-s390/page.h | 1 + include/asm-s390/pgalloc.h | 2 +- include/asm-s390/pgtable.h | 18 +++++++++--------- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index c302508ae31..d9989171870 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -62,19 +62,21 @@ void show_mem(void) { int i, total = 0, reserved = 0; int shared = 0, cached = 0; + struct page *page; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); i = max_mapnr; while (i-- > 0) { + page = pfn_to_page(i); total++; - if (PageReserved(mem_map+i)) + if (PageReserved(page)) reserved++; - else if (PageSwapCache(mem_map+i)) + else if (PageSwapCache(page)) cached++; - else if (page_count(mem_map+i)) - shared += page_count(mem_map+i) - 1; + else if (page_count(page)) + shared += page_count(page) - 1; } printk("%d pages of RAM\n",total); printk("%d reserved pages\n",reserved); diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h index 63c78b9399c..efb7de9c1c6 100644 --- a/include/asm-s390/io.h +++ b/include/asm-s390/io.h @@ -45,11 +45,6 @@ static inline void * phys_to_virt(unsigned long address) return __io_virt(address); } -/* - * Change "struct page" to physical address. - */ -#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) - extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); static inline void * ioremap (unsigned long offset, unsigned long size) diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 796c400f2b7..363ea761d5e 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -137,6 +137,7 @@ page_get_storage_key(unsigned long addr) #define __pa(x) (unsigned long)(x) #define __va(x) (void *)(unsigned long)(x) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define pfn_valid(pfn) ((pfn) < max_mapnr) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index 803bc706441..28619de5eca 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -116,7 +116,7 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) { - pmd_populate_kernel(mm, pmd, (pte_t *)((page-mem_map) << PAGE_SHIFT)); + pmd_populate_kernel(mm, pmd, (pte_t *)page_to_phys(page)); } /* diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index ecdff13b250..519f0a5ff18 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -599,7 +599,7 @@ ptep_establish(struct vm_area_struct *vma, */ static inline int page_test_and_clear_dirty(struct page *page) { - unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT); + unsigned long physpage = page_to_phys(page); int skey = page_get_storage_key(physpage); if (skey & _PAGE_CHANGED) @@ -612,13 +612,13 @@ static inline int page_test_and_clear_dirty(struct page *page) */ static inline int page_test_and_clear_young(struct page *page) { - unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT); + unsigned long physpage = page_to_phys(page); int ccode; - asm volatile ( - "rrbe 0,%1\n" - "ipm %0\n" - "srl %0,28\n" + asm volatile( + " rrbe 0,%1\n" + " ipm %0\n" + " srl %0,28\n" : "=d" (ccode) : "a" (physpage) : "cc" ); return ccode & 2; } @@ -636,7 +636,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) { - unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT); + unsigned long physpage = page_to_phys(page); return mk_pte_phys(physpage, pgprot); } @@ -664,11 +664,11 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot) #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK) -#define pmd_page(pmd) (mem_map+(pmd_val(pmd) >> PAGE_SHIFT)) +#define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) #define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK) -#define pgd_page(pgd) (mem_map+(pgd_val(pgd) >> PAGE_SHIFT)) +#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT) /* to find an entry in a page-table-directory */ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) -- GitLab From 3230015e15d4cf48e1df80fcf70d150f490cffe6 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 4 Oct 2006 20:02:26 +0200 Subject: [PATCH 0616/1619] [S390] cio: add timeout handler for internal operations. Add timeout handler for common-I/O-layer-internal I/O operations. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index e7eeaf1c182..8994800dba4 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -312,7 +312,10 @@ __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, _ sch = to_subchannel(cdev->dev.parent); do { + ccw_device_set_timeout(cdev, 60 * HZ); ret = cio_start (sch, ccw, lpm); + if (ret != 0) + ccw_device_set_timeout(cdev, 0); if (ret == -EBUSY) { /* Try again later. */ spin_unlock_irq(&sch->lock); -- GitLab From 3bdc9d0b408e01c4e556daba0035ba37f603e920 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 4 Oct 2006 20:02:30 +0200 Subject: [PATCH 0617/1619] [S390] cio: improve unit check handling for internal operations Retry internal operation after unit check instead of aborting them. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 8994800dba4..84b9b18eabc 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -288,10 +288,10 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb) if (cdev->private->flags.doverify || cdev->private->state == DEV_STATE_VERIFY) cdev->private->intparm = -EAGAIN; - if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && - !(irb->ecw[0] & - (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ))) - cdev->private->intparm = -EAGAIN; + else if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && + !(irb->ecw[0] & + (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ))) + cdev->private->intparm = -EAGAIN; else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) && (irb->scsw.dstat & DEV_STAT_DEV_END) && (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP)) -- GitLab From c1278289363d9976c81b3b2512621fe152280e82 Mon Sep 17 00:00:00 2001 From: Henne Date: Wed, 4 Oct 2006 09:33:47 +0200 Subject: [PATCH 0618/1619] [SCSI] scsi: Scsi_Cmnd convertion in aic7xxx_old.c Changes the obsolete Scsi_Cmnd to struct scsi_cmnd in aic7xxx_old.c. Also replacing lots of whitespaces with tabs in structures and functions which have been changed. Signed-off-by: Henrik Kretzschmar Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx_old.c | 298 ++++++++++++++++++------------------- 1 file changed, 144 insertions(+), 154 deletions(-) diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 5dcef48d414..c1766cc2bbc 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -780,24 +780,26 @@ typedef enum { } ahc_bugs; struct aic7xxx_scb { - struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ - Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ - struct aic7xxx_scb *q_next; /* next scb in queue */ - volatile scb_flag_type flags; /* current state of scb */ - struct hw_scatterlist *sg_list; /* SG list in adapter format */ - unsigned char tag_action; - unsigned char sg_count; - unsigned char *sense_cmd; /* - * Allocate 6 characters for - * sense command. - */ - unsigned char *cmnd; - unsigned int sg_length; /* We init this during buildscb so we - * don't have to calculate anything - * during underflow/overflow/stat code - */ - void *kmalloc_ptr; - struct aic7xxx_scb_dma *scb_dma; + struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ + struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */ + struct aic7xxx_scb *q_next; /* next scb in queue */ + volatile scb_flag_type flags; /* current state of scb */ + struct hw_scatterlist *sg_list; /* SG list in adapter format */ + unsigned char tag_action; + unsigned char sg_count; + unsigned char *sense_cmd; /* + * Allocate 6 characters for + * sense command. + */ + unsigned char *cmnd; + unsigned int sg_length; /* + * We init this during + * buildscb so we don't have + * to calculate anything during + * underflow/overflow/stat code + */ + void *kmalloc_ptr; + struct aic7xxx_scb_dma *scb_dma; }; /* @@ -918,79 +920,77 @@ struct aic7xxx_host { * We are grouping things here....first, items that get either read or * written with nearly every interrupt */ - volatile long flags; - ahc_feature features; /* chip features */ - unsigned long base; /* card base address */ - volatile unsigned char __iomem *maddr; /* memory mapped address */ - unsigned long isr_count; /* Interrupt count */ - unsigned long spurious_int; - scb_data_type *scb_data; - struct aic7xxx_cmd_queue { - Scsi_Cmnd *head; - Scsi_Cmnd *tail; - } completeq; + volatile long flags; + ahc_feature features; /* chip features */ + unsigned long base; /* card base address */ + volatile unsigned char __iomem *maddr; /* memory mapped address */ + unsigned long isr_count; /* Interrupt count */ + unsigned long spurious_int; + scb_data_type *scb_data; + struct aic7xxx_cmd_queue { + struct scsi_cmnd *head; + struct scsi_cmnd *tail; + } completeq; - /* - * Things read/written on nearly every entry into aic7xxx_queue() - */ - volatile scb_queue_type waiting_scbs; - unsigned char unpause; /* unpause value for HCNTRL */ - unsigned char pause; /* pause value for HCNTRL */ - volatile unsigned char qoutfifonext; - volatile unsigned char activescbs; /* active scbs */ - volatile unsigned char max_activescbs; - volatile unsigned char qinfifonext; - volatile unsigned char *untagged_scbs; - volatile unsigned char *qoutfifo; - volatile unsigned char *qinfifo; - - unsigned char dev_last_queue_full[MAX_TARGETS]; - unsigned char dev_last_queue_full_count[MAX_TARGETS]; - unsigned short ultraenb; /* Gets downloaded to card as a - bitmap */ - unsigned short discenable; /* Gets downloaded to card as a - bitmap */ - transinfo_type user[MAX_TARGETS]; - - unsigned char msg_buf[13]; /* The message for the target */ - unsigned char msg_type; + /* + * Things read/written on nearly every entry into aic7xxx_queue() + */ + volatile scb_queue_type waiting_scbs; + unsigned char unpause; /* unpause value for HCNTRL */ + unsigned char pause; /* pause value for HCNTRL */ + volatile unsigned char qoutfifonext; + volatile unsigned char activescbs; /* active scbs */ + volatile unsigned char max_activescbs; + volatile unsigned char qinfifonext; + volatile unsigned char *untagged_scbs; + volatile unsigned char *qoutfifo; + volatile unsigned char *qinfifo; + + unsigned char dev_last_queue_full[MAX_TARGETS]; + unsigned char dev_last_queue_full_count[MAX_TARGETS]; + unsigned short ultraenb; /* Gets downloaded to card as a bitmap */ + unsigned short discenable; /* Gets downloaded to card as a bitmap */ + transinfo_type user[MAX_TARGETS]; + + unsigned char msg_buf[13]; /* The message for the target */ + unsigned char msg_type; #define MSG_TYPE_NONE 0x00 #define MSG_TYPE_INITIATOR_MSGOUT 0x01 #define MSG_TYPE_INITIATOR_MSGIN 0x02 - unsigned char msg_len; /* Length of message */ - unsigned char msg_index; /* Index into msg_buf array */ + unsigned char msg_len; /* Length of message */ + unsigned char msg_index; /* Index into msg_buf array */ - /* - * We put the less frequently used host structure items after the more - * frequently used items to try and ease the burden on the cache subsystem. - * These entries are not *commonly* accessed, whereas the preceding entries - * are accessed very often. - */ - - unsigned int irq; /* IRQ for this adapter */ - int instance; /* aic7xxx instance number */ - int scsi_id; /* host adapter SCSI ID */ - int scsi_id_b; /* channel B for twin adapters */ - unsigned int bios_address; - int board_name_index; - unsigned short bios_control; /* bios control - SEEPROM */ - unsigned short adapter_control; /* adapter control - SEEPROM */ - struct pci_dev *pdev; - unsigned char pci_bus; - unsigned char pci_device_fn; - struct seeprom_config sc; - unsigned short sc_type; - unsigned short sc_size; - struct aic7xxx_host *next; /* allow for multiple IRQs */ - struct Scsi_Host *host; /* pointer to scsi host */ - struct list_head aic_devs; /* all aic_dev structs on host */ - int host_no; /* SCSI host number */ - unsigned long mbase; /* I/O memory address */ - ahc_chip chip; /* chip type */ - ahc_bugs bugs; - dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ + /* + * We put the less frequently used host structure items + * after the more frequently used items to try and ease + * the burden on the cache subsystem. + * These entries are not *commonly* accessed, whereas + * the preceding entries are accessed very often. + */ + unsigned int irq; /* IRQ for this adapter */ + int instance; /* aic7xxx instance number */ + int scsi_id; /* host adapter SCSI ID */ + int scsi_id_b; /* channel B for twin adapters */ + unsigned int bios_address; + int board_name_index; + unsigned short bios_control; /* bios control - SEEPROM */ + unsigned short adapter_control; /* adapter control - SEEPROM */ + struct pci_dev *pdev; + unsigned char pci_bus; + unsigned char pci_device_fn; + struct seeprom_config sc; + unsigned short sc_type; + unsigned short sc_size; + struct aic7xxx_host *next; /* allow for multiple IRQs */ + struct Scsi_Host *host; /* pointer to scsi host */ + struct list_head aic_devs; /* all aic_dev structs on host */ + int host_no; /* SCSI host number */ + unsigned long mbase; /* I/O memory address */ + ahc_chip chip; /* chip type */ + ahc_bugs bugs; + dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ }; /* @@ -1271,7 +1271,7 @@ static void aic7xxx_set_syncrate(struct aic7xxx_host *p, static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun, unsigned int width, unsigned int type, struct aic_dev_data *aic_dev); -static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd); +static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd); static void aic7xxx_print_card(struct aic7xxx_host *p); static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p); static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded); @@ -2626,7 +2626,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p) * we're finished. This function queues the completed commands. *-F*************************************************************************/ static void -aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd) +aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd) { aic7xxx_position(cmd) = SCB_LIST_NULL; cmd->host_scribble = (char *)p->completeq.head; @@ -2640,18 +2640,16 @@ aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd) * Description: * Process the completed command queue. *-F*************************************************************************/ -static void -aic7xxx_done_cmds_complete(struct aic7xxx_host *p) +static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p) { - Scsi_Cmnd *cmd; - - while (p->completeq.head != NULL) - { - cmd = p->completeq.head; - p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } + struct scsi_cmnd *cmd; + + while (p->completeq.head != NULL) { + cmd = p->completeq.head; + p->completeq.head = (struct scsi_Cmnd *) cmd->host_scribble; + cmd->host_scribble = NULL; + cmd->scsi_done(cmd); + } } /*+F************************************************************************* @@ -2687,11 +2685,11 @@ aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) static void aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) { - Scsi_Cmnd *cmd = scb->cmd; - struct aic_dev_data *aic_dev = cmd->device->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_scb *scbp; - unsigned char queue_depth; + struct scsi_cmnd *cmd = scb->cmd; + struct aic_dev_data *aic_dev = cmd->device->hostdata; + int tindex = TARGET_INDEX(cmd); + struct aic7xxx_scb *scbp; + unsigned char queue_depth; if (cmd->use_sg > 1) { @@ -2891,7 +2889,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) * aic7xxx_run_done_queue * * Description: - * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the + * Calls the aic7xxx_done() for the scsi_cmnd of each scb in the * aborted list, and adds each scb to the free list. If complete * is TRUE, we also process the commands complete list. *-F*************************************************************************/ @@ -3826,9 +3824,9 @@ aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width) static void aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb) { - struct aic7xxx_hwscb *hscb; - Scsi_Cmnd *cmd; - int actual, i; + struct aic7xxx_hwscb *hscb; + struct scsi_cmnd *cmd; + int actual, i; cmd = scb->cmd; hscb = scb->hscb; @@ -4219,20 +4217,20 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) case BAD_STATUS: { - unsigned char scb_index; - struct aic7xxx_hwscb *hscb; - Scsi_Cmnd *cmd; - - /* The sequencer will notify us when a command has an error that - * would be of interest to the kernel. This allows us to leave - * the sequencer running in the common case of command completes - * without error. The sequencer will have DMA'd the SCB back - * up to us, so we can reference the drivers SCB array. - * - * Set the default return value to 0 indicating not to send - * sense. The sense code will change this if needed and this - * reduces code duplication. - */ + unsigned char scb_index; + struct aic7xxx_hwscb *hscb; + struct scsi_cmnd *cmd; + + /* The sequencer will notify us when a command has an error that + * would be of interest to the kernel. This allows us to leave + * the sequencer running in the common case of command completes + * without error. The sequencer will have DMA'd the SCB back + * up to us, so we can reference the drivers SCB array. + * + * Set the default return value to 0 indicating not to send + * sense. The sense code will change this if needed and this + * reduces code duplication. + */ aic_outb(p, 0, RETURN_1); scb_index = aic_inb(p, SCB_TAG); if (scb_index > p->scb_data->numscbs) @@ -5800,9 +5798,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) } else if ((status & SELTO) != 0) { - unsigned char scbptr; - unsigned char nextscb; - Scsi_Cmnd *cmd; + unsigned char scbptr; + unsigned char nextscb; + struct scsi_cmnd *cmd; scbptr = aic_inb(p, WAITING_SCBH); if (scbptr > p->scb_data->maxhscbs) @@ -5941,11 +5939,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) /* * Determine the bus phase and queue an appropriate message. */ - char *phase; - Scsi_Cmnd *cmd; - unsigned char mesg_out = MSG_NOOP; - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char sstat2 = aic_inb(p, SSTAT2); + char *phase; + struct scsi_cmnd *cmd; + unsigned char mesg_out = MSG_NOOP; + unsigned char lastphase = aic_inb(p, LASTPHASE); + unsigned char sstat2 = aic_inb(p, SSTAT2); cmd = scb->cmd; switch (lastphase) @@ -6248,10 +6246,10 @@ aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer) static void aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) { - struct aic7xxx_scb *scb = NULL; - struct aic_dev_data *aic_dev; - Scsi_Cmnd *cmd; - unsigned char scb_index, tindex; + struct aic7xxx_scb *scb = NULL; + struct aic_dev_data *aic_dev; + struct scsi_cmnd *cmd; + unsigned char scb_index, tindex; #ifdef AIC7XXX_VERBOSE_DEBUGGING if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) ) @@ -10131,9 +10129,8 @@ skip_pci_controller: * Description: * Build a SCB. *-F*************************************************************************/ -static void -aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, - struct aic7xxx_scb *scb) +static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd, + struct aic7xxx_scb *scb) { unsigned short mask; struct aic7xxx_hwscb *hscb; @@ -10285,8 +10282,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, * Description: * Queue a SCB to the controller. *-F*************************************************************************/ -static int -aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) +static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) { struct aic7xxx_host *p; struct aic7xxx_scb *scb; @@ -10319,11 +10315,11 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) } scb->cmd = cmd; - /* - * Make sure the Scsi_Cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ + /* + * Make sure the scsi_cmnd pointer is saved, the struct it points to + * is set up properly, and the parity error flag is reset, then send + * the SCB to the sequencer and watch the fun begin. + */ aic7xxx_position(cmd) = scb->hscb->tag; cmd->scsi_done = fn; cmd->result = DID_OK; @@ -10356,8 +10352,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) * aborted, then we will reset the channel and have all devices renegotiate. * Returns an enumerated type that indicates the status of the operation. *-F*************************************************************************/ -static int -__aic7xxx_bus_device_reset(Scsi_Cmnd *cmd) +static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) { struct aic7xxx_host *p; struct aic7xxx_scb *scb; @@ -10550,8 +10545,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cmd) return SUCCESS; } -static int -aic7xxx_bus_device_reset(Scsi_Cmnd *cmd) +static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) { int rc; @@ -10570,8 +10564,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd) * Description: * Abort the current SCSI command(s). *-F*************************************************************************/ -static void -aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd) +static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd) { printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION); @@ -10595,8 +10588,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd) * Description: * Abort the current SCSI command(s). *-F*************************************************************************/ -static int -__aic7xxx_abort(Scsi_Cmnd *cmd) +static int __aic7xxx_abort(struct scsi_cmnd *cmd) { struct aic7xxx_scb *scb = NULL; struct aic7xxx_host *p; @@ -10813,8 +10805,7 @@ success: return SUCCESS; } -static int -aic7xxx_abort(Scsi_Cmnd *cmd) +static int aic7xxx_abort(struct scsi_cmnd *cmd) { int rc; @@ -10836,8 +10827,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd) * DEVICE RESET message - on the offending target before pulling * the SCSI bus reset line. *-F*************************************************************************/ -static int -aic7xxx_reset(Scsi_Cmnd *cmd) +static int aic7xxx_reset(struct scsi_cmnd *cmd) { struct aic7xxx_scb *scb; struct aic7xxx_host *p; -- GitLab From de77aaff5f0178f44867f131deb5e2cb1610fe6b Mon Sep 17 00:00:00 2001 From: Henne Date: Wed, 4 Oct 2006 10:22:09 +0200 Subject: [PATCH 0619/1619] [SCSI] scsi: remove hosts.h Remove the obsolete hosts.h file under drivers/scsi. Signed-off-by: Henrik Kretzschmar Signed-off-by: James Bottomley --- drivers/scsi/dpt_i2o.c | 2 +- drivers/scsi/dpti.h | 2 +- drivers/scsi/hosts.h | 2 -- drivers/scsi/ips.c | 6 ------ drivers/scsi/pcmcia/nsp_cs.c | 1 - 5 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 drivers/scsi/hosts.h diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 7b3bd34faf4..b20b37661d6 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -2212,7 +2212,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht) */ host->io_port = 0; host->n_io_port = 0; - /* see comments in hosts.h */ + /* see comments in scsi_host.h */ host->max_id = 16; host->max_lun = 256; host->max_channel = pHba->top_scsi_channel + 1; diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 2ad2a89b5db..28998326492 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -44,7 +44,7 @@ static int adpt_device_reset(struct scsi_cmnd* cmd); /* - * struct scsi_host_template (see hosts.h) + * struct scsi_host_template (see scsi/scsi_host.h) */ #define DPT_DRIVER_NAME "Adaptec I2O RAID" diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h deleted file mode 100644 index c27264bed5d..00000000000 --- a/drivers/scsi/hosts.h +++ /dev/null @@ -1,2 +0,0 @@ -#warning "This file is obsolete, please use instead" -#include diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 95b7536626f..9a9ab297cf1 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -182,14 +182,8 @@ #include #include - #include "scsi.h" - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) -#include "hosts.h" -#else #include -#endif #include "ips.h" diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 0d4c04e1f3d..053303d3611 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -80,7 +80,6 @@ static int free_ports = 0; module_param(free_ports, bool, 0); MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); -/* /usr/src/linux/drivers/scsi/hosts.h */ static struct scsi_host_template nsp_driver_template = { .proc_name = "nsp_cs", .proc_info = nsp_proc_info, -- GitLab From 37e0333c68ca9cbddfc0108e1889556287563df0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 05:23:04 -0400 Subject: [PATCH 0620/1619] [SCSI] SCSI osst: add error handling to module init, sysfs - check all sysfs-related return codes, and propagate them back to callers - properly unwind errors in osst_probe(), init_osst(). This fixes a leak that occured if scsi driver registration failed, and fixes an oops if sysfs creation returned an error. (unrelated) - kzalloc() cleanup in new_tape_buf() Signed-off-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/scsi/osst.c | 131 ++++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 9ecb323ebae..824fe080d1d 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5206,12 +5206,12 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d priority = GFP_KERNEL; i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = (struct osst_buffer *)kmalloc(i, priority); + tb = kzalloc(i, priority); if (!tb) { printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); return NULL; } - memset(tb, 0, i); + tb->sg_segs = tb->orig_sg_segs = 0; tb->use_sg = max_sg; tb->in_use = 1; @@ -5574,9 +5574,9 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf) static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL); -static void osst_create_driverfs_files(struct device_driver *driverfs) +static int osst_create_driverfs_files(struct device_driver *driverfs) { - driver_create_file(driverfs, &driver_attr_version); + return driver_create_file(driverfs, &driver_attr_version); } static void osst_remove_driverfs_files(struct device_driver *driverfs) @@ -5662,50 +5662,70 @@ CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); static struct class *osst_sysfs_class; -static int osst_sysfs_valid = 0; - -static void osst_sysfs_init(void) +static int osst_sysfs_init(void) { osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); - if ( IS_ERR(osst_sysfs_class) ) - printk(KERN_WARNING "osst :W: Unable to register sysfs class\n"); - else - osst_sysfs_valid = 1; + if (IS_ERR(osst_sysfs_class)) { + printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); + return PTR_ERR(osst_sysfs_class); + } + + return 0; } -static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) +static void osst_sysfs_destroy(dev_t dev) { - struct class_device *osst_class_member; + class_device_destroy(osst_sysfs_class, dev); +} - if (!osst_sysfs_valid) return; +static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) +{ + struct class_device *osst_class_member; + int err; - osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name); + osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, + device, "%s", name); if (IS_ERR(osst_class_member)) { printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); - return; + return PTR_ERR(osst_class_member); } + class_set_devdata(osst_class_member, STp); - class_device_create_file(osst_class_member, &class_device_attr_ADR_rev); - class_device_create_file(osst_class_member, &class_device_attr_media_version); - class_device_create_file(osst_class_member, &class_device_attr_capacity); - class_device_create_file(osst_class_member, &class_device_attr_BOT_frame); - class_device_create_file(osst_class_member, &class_device_attr_EOD_frame); - class_device_create_file(osst_class_member, &class_device_attr_file_count); -} + err = class_device_create_file(osst_class_member, + &class_device_attr_ADR_rev); + if (err) + goto err_out; + err = class_device_create_file(osst_class_member, + &class_device_attr_media_version); + if (err) + goto err_out; + err = class_device_create_file(osst_class_member, + &class_device_attr_capacity); + if (err) + goto err_out; + err = class_device_create_file(osst_class_member, + &class_device_attr_BOT_frame); + if (err) + goto err_out; + err = class_device_create_file(osst_class_member, + &class_device_attr_EOD_frame); + if (err) + goto err_out; + err = class_device_create_file(osst_class_member, + &class_device_attr_file_count); + if (err) + goto err_out; -static void osst_sysfs_destroy(dev_t dev) -{ - if (!osst_sysfs_valid) return; + return 0; - class_device_destroy(osst_sysfs_class, dev); +err_out: + osst_sysfs_destroy(dev); + return err; } static void osst_sysfs_cleanup(void) { - if (osst_sysfs_valid) { - class_destroy(osst_sysfs_class); - osst_sysfs_valid = 0; - } + class_destroy(osst_sysfs_class); } /* @@ -5720,7 +5740,7 @@ static int osst_probe(struct device *dev) struct st_partstat * STps; struct osst_buffer * buffer; struct gendisk * drive; - int i, dev_num; + int i, dev_num, err = -ENODEV; if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) return -ENODEV; @@ -5848,13 +5868,20 @@ static int osst_probe(struct device *dev) init_MUTEX(&tpnt->lock); osst_nr_dev++; write_unlock(&os_scsi_tapes_lock); + { char name[8]; + /* Rewind entry */ - osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); + err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); + if (err) + goto out_free_buffer; + /* No-rewind entry */ snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); - osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); + err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); + if (err) + goto out_free_sysfs1; } sdev_printk(KERN_INFO, SDp, @@ -5863,9 +5890,13 @@ static int osst_probe(struct device *dev) return 0; +out_free_sysfs1: + osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); +out_free_buffer: + kfree(buffer); out_put_disk: put_disk(drive); - return -ENODEV; + return err; }; static int osst_remove(struct device *dev) @@ -5902,19 +5933,39 @@ static int osst_remove(struct device *dev) static int __init init_osst(void) { + int err; + printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); validate_options(); - osst_sysfs_init(); - if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) { + err = osst_sysfs_init(); + if (err) + return err; + + err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); + if (err < 0) { printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); - osst_sysfs_cleanup(); - return 1; + goto err_out; } - osst_create_driverfs_files(&osst_template.gendrv); + + err = scsi_register_driver(&osst_template.gendrv); + if (err) + goto err_out_chrdev; + + err = osst_create_driverfs_files(&osst_template.gendrv); + if (err) + goto err_out_scsidrv; return 0; + +err_out_scsidrv: + scsi_unregister_driver(&osst_template.gendrv); +err_out_chrdev: + unregister_chrdev(OSST_MAJOR, "osst"); +err_out: + osst_sysfs_cleanup(); + return err; } static void __exit exit_osst (void) -- GitLab From 5e4009ba3d5af40f5615fdb4304cc4a9947cca0a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 05:32:54 -0400 Subject: [PATCH 0621/1619] [SCSI] SCSI sd: fix module init/exit error handling - Properly handle and unwind errors in init_sd(). Fixes leaks on error, if class_register() or scsi_register_driver() failed. - Ensure that exit_sd() execution order is the perfect inverse of initialization order. FIXME: If some-but-not-all register_blkdev() calls fail, we wind up calling unregister_blkdev() for block devices we did not register. This was a pre-existing bug. Signed-off-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 638cff41d43..7a9d552f50e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1795,7 +1795,7 @@ static void sd_shutdown(struct device *dev) **/ static int __init init_sd(void) { - int majors = 0, i; + int majors = 0, i, err; SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); @@ -1806,9 +1806,22 @@ static int __init init_sd(void) if (!majors) return -ENODEV; - class_register(&sd_disk_class); + err = class_register(&sd_disk_class); + if (err) + goto err_out; - return scsi_register_driver(&sd_template.gendrv); + err = scsi_register_driver(&sd_template.gendrv); + if (err) + goto err_out_class; + + return 0; + +err_out_class: + class_unregister(&sd_disk_class); +err_out: + for (i = 0; i < SD_MAJORS; i++) + unregister_blkdev(sd_major(i), "sd"); + return err; } /** @@ -1823,10 +1836,10 @@ static void __exit exit_sd(void) SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); scsi_unregister_driver(&sd_template.gendrv); + class_unregister(&sd_disk_class); + for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); - - class_unregister(&sd_disk_class); } module_init(init_sd); -- GitLab From 13026a6b985b9d1e19330d5656e211f15b5aca3b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 06:00:38 -0400 Subject: [PATCH 0622/1619] [SCSI] SCSI st: fix error handling in module init, sysfs - Notice and handle sysfs errors in module init, tape init - Properly unwind errors in module init - Remove bogus st_sysfs_class==NULL test, it is guaranteed !NULL at that point Signed-off-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/scsi/st.c | 115 +++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7f669b60067..3babdc76b3f 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); static int st_probe(struct device *); static int st_remove(struct device *); -static void do_create_driverfs_files(void); +static int do_create_driverfs_files(void); static void do_remove_driverfs_files(void); -static void do_create_class_files(struct scsi_tape *, int, int); +static int do_create_class_files(struct scsi_tape *, int, int); static struct scsi_driver st_template = { .owner = THIS_MODULE, @@ -4048,7 +4048,9 @@ static int st_probe(struct device *dev) STm->cdevs[j] = cdev; } - do_create_class_files(tpnt, dev_num, mode); + error = do_create_class_files(tpnt, dev_num, mode); + if (error) + goto out_free_tape; } sdev_printk(KERN_WARNING, SDp, @@ -4157,32 +4159,45 @@ static void scsi_tape_release(struct kref *kref) static int __init init_st(void) { + int err; + validate_options(); - printk(KERN_INFO - "st: Version %s, fixed bufsize %d, s/g segs %d\n", + printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n", verstr, st_fixed_buffer_size, st_max_sg_segs); st_sysfs_class = class_create(THIS_MODULE, "scsi_tape"); if (IS_ERR(st_sysfs_class)) { - st_sysfs_class = NULL; printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); - return 1; + return PTR_ERR(st_sysfs_class); } - if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), - ST_MAX_TAPE_ENTRIES, "st")) { - if (scsi_register_driver(&st_template.gendrv) == 0) { - do_create_driverfs_files(); - return 0; - } - unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), - ST_MAX_TAPE_ENTRIES); + err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), + ST_MAX_TAPE_ENTRIES, "st"); + if (err) { + printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", + SCSI_TAPE_MAJOR); + goto err_class; } - class_destroy(st_sysfs_class); - printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR); - return 1; + err = scsi_register_driver(&st_template.gendrv); + if (err) + goto err_chrdev; + + err = do_create_driverfs_files(); + if (err) + goto err_scsidrv; + + return 0; + +err_scsidrv: + scsi_unregister_driver(&st_template.gendrv); +err_chrdev: + unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), + ST_MAX_TAPE_ENTRIES); +err_class: + class_destroy(st_sysfs_class); + return err; } static void __exit exit_st(void) @@ -4225,14 +4240,33 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf) } static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); -static void do_create_driverfs_files(void) +static int do_create_driverfs_files(void) { struct device_driver *driverfs = &st_template.gendrv; + int err; + + err = driver_create_file(driverfs, &driver_attr_try_direct_io); + if (err) + return err; + err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size); + if (err) + goto err_try_direct_io; + err = driver_create_file(driverfs, &driver_attr_max_sg_segs); + if (err) + goto err_attr_fixed_buf; + err = driver_create_file(driverfs, &driver_attr_version); + if (err) + goto err_attr_max_sg; - driver_create_file(driverfs, &driver_attr_try_direct_io); - driver_create_file(driverfs, &driver_attr_fixed_buffer_size); - driver_create_file(driverfs, &driver_attr_max_sg_segs); - driver_create_file(driverfs, &driver_attr_version); + return 0; + +err_attr_max_sg: + driver_remove_file(driverfs, &driver_attr_max_sg_segs); +err_attr_fixed_buf: + driver_remove_file(driverfs, &driver_attr_fixed_buffer_size); +err_try_direct_io: + driver_remove_file(driverfs, &driver_attr_try_direct_io); + return err; } static void do_remove_driverfs_files(void) @@ -4293,15 +4327,12 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf) CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); -static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) +static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) { int i, rew, error; char name[10]; struct class_device *st_class_member; - if (!st_sysfs_class) - return; - for (rew=0; rew < 2; rew++) { /* Make sure that the minor numbers corresponding to the four first modes always get the same names */ @@ -4316,18 +4347,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) if (IS_ERR(st_class_member)) { printk(KERN_WARNING "st%d: class_device_create failed\n", dev_num); + error = PTR_ERR(st_class_member); goto out; } class_set_devdata(st_class_member, &STp->modes[mode]); - class_device_create_file(st_class_member, - &class_device_attr_defined); - class_device_create_file(st_class_member, - &class_device_attr_default_blksize); - class_device_create_file(st_class_member, - &class_device_attr_default_density); - class_device_create_file(st_class_member, - &class_device_attr_default_compression); + error = class_device_create_file(st_class_member, + &class_device_attr_defined); + if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_default_blksize); + if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_default_density); + if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_default_compression); + if (error) goto out; + if (mode == 0 && rew == 0) { error = sysfs_create_link(&STp->device->sdev_gendev.kobj, &st_class_member->kobj, @@ -4336,11 +4373,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) printk(KERN_ERR "st%d: Can't create sysfs link from SCSI device.\n", dev_num); + goto out; } } } - out: - return; + + return 0; + +out: + return error; } /* The following functions may be useful for a larger audience. */ -- GitLab From bb0766204c81d6bd01532476aec4e512c960fb4d Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 06:19:18 -0400 Subject: [PATCH 0623/1619] [SCSI] SCSI aic94xx: handle sysfs errors Handle and unwind from errors returned by driver model functions. Signed-off-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/aic94xx_init.c | 41 +++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index ee2ccad7048..57379c929d8 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -310,11 +310,29 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev, } static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); -static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha) +static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) { - device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision); - device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); - device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); + int err; + + err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision); + if (err) + return err; + + err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); + if (err) + goto err_rev; + + err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); + if (err) + goto err_biosb; + + return 0; + +err_biosb: + device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); +err_rev: + device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); + return err; } static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha) @@ -646,7 +664,9 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, } ASD_DPRINTK("escbs posted\n"); - asd_create_dev_attrs(asd_ha); + err = asd_create_dev_attrs(asd_ha); + if (err) + goto Err_dev_attrs; err = asd_register_sas_ha(asd_ha); if (err) @@ -669,6 +689,7 @@ Err_en_phys: asd_unregister_sas_ha(asd_ha); Err_reg_sas: asd_remove_dev_attrs(asd_ha); +Err_dev_attrs: Err_escbs: asd_disable_ints(asd_ha); free_irq(dev->irq, asd_ha); @@ -755,9 +776,9 @@ static ssize_t asd_version_show(struct device_driver *driver, char *buf) } static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL); -static void asd_create_driver_attrs(struct device_driver *driver) +static int asd_create_driver_attrs(struct device_driver *driver) { - driver_create_file(driver, &driver_attr_version); + return driver_create_file(driver, &driver_attr_version); } static void asd_remove_driver_attrs(struct device_driver *driver) @@ -835,10 +856,14 @@ static int __init aic94xx_init(void) if (err) goto out_release_transport; - asd_create_driver_attrs(&aic94xx_pci_driver.driver); + err = asd_create_driver_attrs(&aic94xx_pci_driver.driver); + if (err) + goto out_unregister_pcidrv; return err; + out_unregister_pcidrv: + pci_unregister_driver(&aic94xx_pci_driver); out_release_transport: sas_release_transport(aic94xx_transport_template); out_destroy_caches: -- GitLab From 83aabc1be551dd1f07266c125ff48ec62a2ce515 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 06:34:03 -0400 Subject: [PATCH 0624/1619] [SCSI] SCSI megaraid_sas: handle thrown errors - handle clear_user() error - handle and properly unwind from sysfs errors thrown during mod init - adjust order of calls in megasas_exit() to precisely match registration order in megasas_init() Signed-off-by: Jeff Garzik Updated for extra attribute and Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 42 ++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index e21f638c00a..977b6e8d852 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -2864,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) int i; int error = 0; - clear_user(ioc, sizeof(*ioc)); + if (clear_user(ioc, sizeof(*ioc))) + return -EFAULT; if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) || copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) || @@ -3010,16 +3011,33 @@ static int __init megasas_init(void) if (rval) { printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n"); - unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); - } - - driver_create_file(&megasas_pci_driver.driver, &driver_attr_version); - driver_create_file(&megasas_pci_driver.driver, - &driver_attr_release_date); - driver_create_file(&megasas_pci_driver.driver, - &driver_attr_dbg_lvl); + goto err_pcidrv; + } + + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_version); + if (rval) + goto err_dcf_attr_ver; + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_release_date); + if (rval) + goto err_dcf_rel_date; + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_dbg_lvl); + if (rval) + goto err_dcf_dbg_lvl; return rval; +err_dcf_dbg_lvl: + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_release_date); +err_dcf_rel_date: + driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); +err_dcf_attr_ver: + pci_unregister_driver(&megasas_pci_driver); +err_pcidrv: + unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); + return rval; } /** @@ -3027,11 +3045,11 @@ static int __init megasas_init(void) */ static void __exit megasas_exit(void) { - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_release_date); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_release_date); + driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); pci_unregister_driver(&megasas_pci_driver); unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); -- GitLab From ed542bed126caeefc6546b276e4af852d4d34f33 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 07:05:11 -0400 Subject: [PATCH 0625/1619] [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(-) diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 327b33a57b0..86e13183c9b 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 d0dd38b3a2f..d22ad392242 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 *); + -- GitLab From afaf5a2d341d33b66b47c2716a263ce593460a08 Mon Sep 17 00:00:00 2001 From: David Somayajulu Date: Tue, 19 Sep 2006 10:28:00 -0700 Subject: [PATCH 0626/1619] [SCSI] Initial Commit of qla4xxx open-iSCSI driver for Qlogic Corporation's iSCSI HBAs Signed-off-by: Ravi Anand Signed-off-by: David Somayajulu Signed-off-by: Doug Maxey Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 1 + drivers/scsi/Makefile | 1 + drivers/scsi/qla4xxx/Kconfig | 7 + drivers/scsi/qla4xxx/Makefile | 5 + drivers/scsi/qla4xxx/ql4_dbg.c | 197 ++++ drivers/scsi/qla4xxx/ql4_dbg.h | 55 + drivers/scsi/qla4xxx/ql4_def.h | 586 ++++++++++ drivers/scsi/qla4xxx/ql4_fw.h | 843 +++++++++++++ drivers/scsi/qla4xxx/ql4_glbl.h | 78 ++ drivers/scsi/qla4xxx/ql4_init.c | 1340 +++++++++++++++++++++ drivers/scsi/qla4xxx/ql4_inline.h | 84 ++ drivers/scsi/qla4xxx/ql4_iocb.c | 368 ++++++ drivers/scsi/qla4xxx/ql4_isr.c | 797 +++++++++++++ drivers/scsi/qla4xxx/ql4_mbx.c | 930 +++++++++++++++ drivers/scsi/qla4xxx/ql4_nvram.c | 224 ++++ drivers/scsi/qla4xxx/ql4_nvram.h | 256 ++++ drivers/scsi/qla4xxx/ql4_os.c | 1755 ++++++++++++++++++++++++++++ drivers/scsi/qla4xxx/ql4_version.h | 13 + 18 files changed, 7540 insertions(+) create mode 100644 drivers/scsi/qla4xxx/Kconfig create mode 100644 drivers/scsi/qla4xxx/Makefile create mode 100644 drivers/scsi/qla4xxx/ql4_dbg.c create mode 100644 drivers/scsi/qla4xxx/ql4_dbg.h create mode 100644 drivers/scsi/qla4xxx/ql4_def.h create mode 100644 drivers/scsi/qla4xxx/ql4_fw.h create mode 100644 drivers/scsi/qla4xxx/ql4_glbl.h create mode 100644 drivers/scsi/qla4xxx/ql4_init.c create mode 100644 drivers/scsi/qla4xxx/ql4_inline.h create mode 100644 drivers/scsi/qla4xxx/ql4_iocb.c create mode 100644 drivers/scsi/qla4xxx/ql4_isr.c create mode 100644 drivers/scsi/qla4xxx/ql4_mbx.c create mode 100644 drivers/scsi/qla4xxx/ql4_nvram.c create mode 100644 drivers/scsi/qla4xxx/ql4_nvram.h create mode 100644 drivers/scsi/qla4xxx/ql4_os.c create mode 100644 drivers/scsi/qla4xxx/ql4_version.h diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8a22a71280a..3ff5ec8f0d3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1244,6 +1244,7 @@ config SCSI_QLOGICPTI module will be called qlogicpti. source "drivers/scsi/qla2xxx/Kconfig" +source "drivers/scsi/qla4xxx/Kconfig" config SCSI_LPFC tristate "Emulex LightPulse Fibre Channel Support" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 1ef951be7a5..bcca39c3bcb 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ +obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/ obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_PAS16) += pas16.o obj-$(CONFIG_SCSI_SEAGATE) += seagate.o diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig new file mode 100644 index 00000000000..08a07f0b8d9 --- /dev/null +++ b/drivers/scsi/qla4xxx/Kconfig @@ -0,0 +1,7 @@ +config SCSI_QLA_ISCSI + tristate "QLogic ISP4XXX host adapter family support" + depends on PCI && SCSI + select SCSI_ISCSI_ATTRS + ---help--- + This driver supports the QLogic 40xx (ISP4XXX) iSCSI host + adapter family. diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile new file mode 100644 index 00000000000..86ea37baa0f --- /dev/null +++ b/drivers/scsi/qla4xxx/Makefile @@ -0,0 +1,5 @@ +qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ + ql4_nvram.o ql4_dbg.o + +obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o + diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c new file mode 100644 index 00000000000..752031fadfe --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_dbg.c @@ -0,0 +1,197 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#include "ql4_def.h" +#include + +static void qla4xxx_print_srb_info(struct srb * srb) +{ + printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags); + printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n", + __func__, srb->cmd, (unsigned long) srb->dma_handle); + printk("%s: fw_ddb_index = %d, lun = %d\n", + __func__, srb->fw_ddb_index, srb->cmd->device->lun); + printk("%s: iocb_tov = %d\n", + __func__, srb->iocb_tov); + printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n", + __func__, srb->cc_stat, srb->r_start, srb->u_start); +} + +void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd) +{ + printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); + printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n", + cmd->device->channel, cmd->device->id, cmd->device->lun, + cmd->cmd_len); + scsi_print_command(cmd); + printk(" seg_cnt = %d\n", cmd->use_sg); + printk(" request buffer = 0x%p, request buffer len = 0x%x\n", + cmd->request_buffer, cmd->request_bufflen); + if (cmd->use_sg) { + struct scatterlist *sg; + sg = (struct scatterlist *)cmd->request_buffer; + printk(" SG buffer: \n"); + qla4xxx_dump_buffer((caddr_t) sg, + (cmd->use_sg * sizeof(*sg))); + } + printk(" tag = %d, transfersize = 0x%x \n", cmd->tag, + cmd->transfersize); + printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr); + printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow, + cmd->sc_data_direction); + printk(" Current time (jiffies) = 0x%lx, " + "timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires); + qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr); +} + +void __dump_registers(struct scsi_qla_host *ha) +{ + uint8_t i; + for (i = 0; i < MBOX_REG_COUNT; i++) { + printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, mailbox[i]), i, + readw(&ha->reg->mailbox[i])); + } + printk(KERN_INFO "0x%02X flash_address = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, flash_address), + readw(&ha->reg->flash_address)); + printk(KERN_INFO "0x%02X flash_data = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, flash_data), + readw(&ha->reg->flash_data)); + printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, ctrl_status), + readw(&ha->reg->ctrl_status)); + if (is_qla4010(ha)) { + printk(KERN_INFO "0x%02X nvram = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram), + readw(&ha->reg->u1.isp4010.nvram)); + } + + else if (is_qla4022(ha)) { + printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u1.isp4022.intr_mask), + readw(&ha->reg->u1.isp4022.intr_mask)); + printk(KERN_INFO "0x%02X nvram = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram), + readw(&ha->reg->u1.isp4022.nvram)); + printk(KERN_INFO "0x%02X semaphore = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u1.isp4022.semaphore), + readw(&ha->reg->u1.isp4022.semaphore)); + } + printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, req_q_in), + readw(&ha->reg->req_q_in)); + printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, rsp_q_out), + readw(&ha->reg->rsp_q_out)); + if (is_qla4010(ha)) { + printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.ext_hw_conf), + readw(&ha->reg->u2.isp4010.ext_hw_conf)); + printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.port_ctrl), + readw(&ha->reg->u2.isp4010.port_ctrl)); + printk(KERN_INFO "0x%02X port_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.port_status), + readw(&ha->reg->u2.isp4010.port_status)); + printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.req_q_out), + readw(&ha->reg->u2.isp4010.req_q_out)); + printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out), + readw(&ha->reg->u2.isp4010.gp_out)); + printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in), + readw(&ha->reg->u2.isp4010.gp_in)); + printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.port_err_status), + readw(&ha->reg->u2.isp4010.port_err_status)); + } + + else if (is_qla4022(ha)) { + printk(KERN_INFO "Page 0 Registers:\n"); + printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.ext_hw_conf), + readw(&ha->reg->u2.isp4022.p0.ext_hw_conf)); + printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.port_ctrl), + readw(&ha->reg->u2.isp4022.p0.port_ctrl)); + printk(KERN_INFO "0x%02X port_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.port_status), + readw(&ha->reg->u2.isp4022.p0.port_status)); + printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.gp_out), + readw(&ha->reg->u2.isp4022.p0.gp_out)); + printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in), + readw(&ha->reg->u2.isp4022.p0.gp_in)); + printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.port_err_status), + readw(&ha->reg->u2.isp4022.p0.port_err_status)); + printk(KERN_INFO "Page 1 Registers:\n"); + writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), + &ha->reg->ctrl_status); + printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p1.req_q_out), + readw(&ha->reg->u2.isp4022.p1.req_q_out)); + writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), + &ha->reg->ctrl_status); + } +} + +void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha) +{ + unsigned long flags = 0; + int i = 0; + spin_lock_irqsave(&ha->hardware_lock, flags); + for (i = 1; i < MBOX_REG_COUNT; i++) + printk(KERN_INFO " Mailbox[%d] = %08x\n", i, + readw(&ha->reg->mailbox[i])); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +void qla4xxx_dump_registers(struct scsi_qla_host *ha) +{ + unsigned long flags = 0; + spin_lock_irqsave(&ha->hardware_lock, flags); + __dump_registers(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +void qla4xxx_dump_buffer(void *b, uint32_t size) +{ + uint32_t cnt; + uint8_t *c = b; + + printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh " + "Fh\n"); + printk("------------------------------------------------------------" + "--\n"); + for (cnt = 0; cnt < size; cnt++, c++) { + printk(KERN_DEBUG "%02x", *c); + if (!(cnt % 16)) + printk(KERN_DEBUG "\n"); + + else + printk(KERN_DEBUG " "); + } + if (cnt % 16) + printk(KERN_DEBUG "\n"); +} diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h new file mode 100644 index 00000000000..56ddc227f84 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_dbg.h @@ -0,0 +1,55 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +/* + * Driver debug definitions. + */ +/* #define QL_DEBUG */ /* DEBUG messages */ +/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */ +/* #define QL_DEBUG_LEVEL_4 */ +/* #define QL_DEBUG_LEVEL_5 */ +/* #define QL_DEBUG_LEVEL_9 */ + +#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */ +#if defined(QL_DEBUG) +#define DEBUG(x) do {x;} while (0); +#else +#define DEBUG(x) do {} while (0); +#endif + +#if defined(QL_DEBUG_LEVEL_2) +#define DEBUG2(x) do {if(extended_error_logging == 2) x;} while (0); +#define DEBUG2_3(x) do {x;} while (0); +#else /* */ +#define DEBUG2(x) do {} while (0); +#endif /* */ + +#if defined(QL_DEBUG_LEVEL_3) +#define DEBUG3(x) do {if(extended_error_logging == 3) x;} while (0); +#else /* */ +#define DEBUG3(x) do {} while (0); +#if !defined(QL_DEBUG_LEVEL_2) +#define DEBUG2_3(x) do {} while (0); +#endif /* */ +#endif /* */ +#if defined(QL_DEBUG_LEVEL_4) +#define DEBUG4(x) do {x;} while (0); +#else /* */ +#define DEBUG4(x) do {} while (0); +#endif /* */ + +#if defined(QL_DEBUG_LEVEL_5) +#define DEBUG5(x) do {x;} while (0); +#else /* */ +#define DEBUG5(x) do {} while (0); +#endif /* */ + +#if defined(QL_DEBUG_LEVEL_9) +#define DEBUG9(x) do {x;} while (0); +#else /* */ +#define DEBUG9(x) do {} while (0); +#endif /* */ diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h new file mode 100644 index 00000000000..a7f6c7b1c59 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -0,0 +1,586 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#ifndef __QL4_DEF_H +#define __QL4_DEF_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010 +#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010 +#endif + +#ifndef PCI_DEVICE_ID_QLOGIC_ISP4022 +#define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022 +#endif /* */ + +#define QLA_SUCCESS 0 +#define QLA_ERROR 1 + +/* + * Data bit definitions + */ +#define BIT_0 0x1 +#define BIT_1 0x2 +#define BIT_2 0x4 +#define BIT_3 0x8 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x100 +#define BIT_9 0x200 +#define BIT_10 0x400 +#define BIT_11 0x800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x10000 +#define BIT_17 0x20000 +#define BIT_18 0x40000 +#define BIT_19 0x80000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x1000000 +#define BIT_25 0x2000000 +#define BIT_26 0x4000000 +#define BIT_27 0x8000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + +/* + * Host adapter default definitions + ***********************************/ +#define MAX_HBAS 16 +#define MAX_BUSES 1 +#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) +#define MAX_LUNS 0xffff +#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */ +#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) +#define MAX_PDU_ENTRIES 32 +#define INVALID_ENTRY 0xFFFF +#define MAX_CMDS_TO_RISC 1024 +#define MAX_SRBS MAX_CMDS_TO_RISC +#define MBOX_AEN_REG_COUNT 5 +#define MAX_INIT_RETRIES 5 +#define IOCB_HIWAT_CUSHION 16 + +/* + * Buffer sizes + */ +#define REQUEST_QUEUE_DEPTH MAX_CMDS_TO_RISC +#define RESPONSE_QUEUE_DEPTH 64 +#define QUEUE_SIZE 64 +#define DMA_BUFFER_SIZE 512 + +/* + * Misc + */ +#define MAC_ADDR_LEN 6 /* in bytes */ +#define IP_ADDR_LEN 4 /* in bytes */ +#define DRIVER_NAME "qla4xxx" + +#define MAX_LINKED_CMDS_PER_LUN 3 +#define MAX_REQS_SERVICED_PER_INTR 16 + +#define ISCSI_IPADDR_SIZE 4 /* IP address size */ +#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */ +#define ISCSI_NAME_SIZE 255 /* ISCSI Name size - + * usually a string */ + +#define LSDW(x) ((u32)((u64)(x))) +#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) + +/* + * Retry & Timeout Values + */ +#define MBOX_TOV 60 +#define SOFT_RESET_TOV 30 +#define RESET_INTR_TOV 3 +#define SEMAPHORE_TOV 10 +#define ADAPTER_INIT_TOV 120 +#define ADAPTER_RESET_TOV 180 +#define EXTEND_CMD_TOV 60 +#define WAIT_CMD_TOV 30 +#define EH_WAIT_CMD_TOV 120 +#define FIRMWARE_UP_TOV 60 +#define RESET_FIRMWARE_TOV 30 +#define LOGOUT_TOV 10 +#define IOCB_TOV_MARGIN 10 +#define RELOGIN_TOV 18 +#define ISNS_DEREG_TOV 5 + +#define MAX_RESET_HA_RETRIES 2 + +/* + * SCSI Request Block structure (srb) that is placed + * on cmd->SCp location of every I/O [We have 22 bytes available] + */ +struct srb { + struct list_head list; /* (8) */ + struct scsi_qla_host *ha; /* HA the SP is queued on */ + struct ddb_entry *ddb; + uint16_t flags; /* (1) Status flags. */ + +#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */ +#define SRB_GOT_SENSE BIT_4 /* sense data recieved. */ + uint8_t state; /* (1) Status flags. */ + +#define SRB_NO_QUEUE_STATE 0 /* Request is in between states */ +#define SRB_FREE_STATE 1 +#define SRB_ACTIVE_STATE 3 +#define SRB_ACTIVE_TIMEOUT_STATE 4 +#define SRB_SUSPENDED_STATE 7 /* Request in suspended state */ + + struct scsi_cmnd *cmd; /* (4) SCSI command block */ + dma_addr_t dma_handle; /* (4) for unmap of single transfers */ + atomic_t ref_count; /* reference count for this srb */ + uint32_t fw_ddb_index; + uint8_t err_id; /* error id */ +#define SRB_ERR_PORT 1 /* Request failed because "port down" */ +#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */ +#define SRB_ERR_DEVICE 3 /* Request failed because "device error" */ +#define SRB_ERR_OTHER 4 + + uint16_t reserved; + uint16_t iocb_tov; + uint16_t iocb_cnt; /* Number of used iocbs */ + uint16_t cc_stat; + u_long r_start; /* Time we recieve a cmd from OS */ + u_long u_start; /* Time when we handed the cmd to F/W */ +}; + + /* + * Device Database (DDB) structure + */ +struct ddb_entry { + struct list_head list; /* ddb list */ + struct scsi_qla_host *ha; + struct iscsi_cls_session *sess; + struct iscsi_cls_conn *conn; + + atomic_t state; /* DDB State */ + + unsigned long flags; /* DDB Flags */ + + unsigned long dev_scan_wait_to_start_relogin; + unsigned long dev_scan_wait_to_complete_relogin; + + uint16_t os_target_id; /* Target ID */ + uint16_t fw_ddb_index; /* DDB firmware index */ + uint8_t reserved[2]; + uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ + + uint32_t CmdSn; + uint16_t target_session_id; + uint16_t connection_id; + uint16_t exe_throttle; /* Max mumber of cmds outstanding + * simultaneously */ + uint16_t task_mgmt_timeout; /* Min time for task mgmt cmds to + * complete */ + uint16_t default_relogin_timeout; /* Max time to wait for + * relogin to complete */ + uint16_t tcp_source_port_num; + uint32_t default_time2wait; /* Default Min time between + * relogins (+aens) */ + + atomic_t port_down_timer; /* Device connection timer */ + atomic_t retry_relogin_timer; /* Min Time between relogins + * (4000 only) */ + atomic_t relogin_timer; /* Max Time to wait for relogin to complete */ + atomic_t relogin_retry_count; /* Num of times relogin has been + * retried */ + + uint16_t port; + uint32_t tpgt; + uint8_t ip_addr[ISCSI_IPADDR_SIZE]; + uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */ + uint8_t iscsi_alias[0x20]; +}; + +/* + * DDB states. + */ +#define DDB_STATE_DEAD 0 /* We can no longer talk to + * this device */ +#define DDB_STATE_ONLINE 1 /* Device ready to accept + * commands */ +#define DDB_STATE_MISSING 2 /* Device logged off, trying + * to re-login */ + +/* + * DDB flags. + */ +#define DF_RELOGIN 0 /* Relogin to device */ +#define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL + * logged it out */ +#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ +#define DF_FO_MASKED 3 + +/* + * Asynchronous Event Queue structure + */ +struct aen { + uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; +}; + + +#include "ql4_fw.h" +#include "ql4_nvram.h" + +/* + * Linux Host Adapter structure + */ +struct scsi_qla_host { + /* Linux adapter configuration data */ + struct Scsi_Host *host; /* pointer to host data */ + uint32_t tot_ddbs; + unsigned long flags; + +#define AF_ONLINE 0 /* 0x00000001 */ +#define AF_INIT_DONE 1 /* 0x00000002 */ +#define AF_MBOX_COMMAND 2 /* 0x00000004 */ +#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */ +#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */ +#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ +#define AF_LINK_UP 8 /* 0x00000100 */ +#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */ +#define AF_IRQ_ATTACHED 10 /* 0x00000400 */ +#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */ +#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */ + + unsigned long dpc_flags; + +#define DPC_RESET_HA 1 /* 0x00000002 */ +#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */ +#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */ +#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */ +#define DPC_RESET_HA_INTR 5 /* 0x00000020 */ +#define DPC_ISNS_RESTART 7 /* 0x00000080 */ +#define DPC_AEN 9 /* 0x00000200 */ +#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ + + uint16_t iocb_cnt; + uint16_t iocb_hiwat; + + /* SRB cache. */ +#define SRB_MIN_REQ 128 + mempool_t *srb_mempool; + + /* pci information */ + struct pci_dev *pdev; + + struct isp_reg __iomem *reg; /* Base I/O address */ + unsigned long pio_address; + unsigned long pio_length; +#define MIN_IOBASE_LEN 0x100 + + uint16_t req_q_count; + uint8_t marker_needed; + uint8_t rsvd1; + + unsigned long host_no; + + /* NVRAM registers */ + struct eeprom_data *nvram; + spinlock_t hardware_lock ____cacheline_aligned; + spinlock_t list_lock; + uint32_t eeprom_cmd_data; + + /* Counters for general statistics */ + uint64_t adapter_error_count; + uint64_t device_error_count; + uint64_t total_io_count; + uint64_t total_mbytes_xferred; + uint64_t link_failure_count; + uint64_t invalid_crc_count; + uint32_t spurious_int_count; + uint32_t aborted_io_count; + uint32_t io_timeout_count; + uint32_t mailbox_timeout_count; + uint32_t seconds_since_last_intr; + uint32_t seconds_since_last_heartbeat; + uint32_t mac_index; + + /* Info Needed for Management App */ + /* --- From GetFwVersion --- */ + uint32_t firmware_version[2]; + uint32_t patch_number; + uint32_t build_number; + + /* --- From Init_FW --- */ + /* init_cb_t *init_cb; */ + uint16_t firmware_options; + uint16_t tcp_options; + uint8_t ip_address[IP_ADDR_LEN]; + uint8_t subnet_mask[IP_ADDR_LEN]; + uint8_t gateway[IP_ADDR_LEN]; + uint8_t alias[32]; + uint8_t name_string[256]; + uint8_t heartbeat_interval; + uint8_t rsvd; + + /* --- From FlashSysInfo --- */ + uint8_t my_mac[MAC_ADDR_LEN]; + uint8_t serial_number[16]; + + /* --- From GetFwState --- */ + uint32_t firmware_state; + uint32_t board_id; + uint32_t addl_fw_state; + + /* Linux kernel thread */ + struct workqueue_struct *dpc_thread; + struct work_struct dpc_work; + + /* Linux timer thread */ + struct timer_list timer; + uint32_t timer_active; + + /* Recovery Timers */ + uint32_t port_down_retry_count; + uint32_t discovery_wait; + atomic_t check_relogin_timeouts; + uint32_t retry_reset_ha_cnt; + uint32_t isp_reset_timer; /* reset test timer */ + uint32_t nic_reset_timer; /* simulated nic reset test timer */ + int eh_start; + struct list_head free_srb_q; + uint16_t free_srb_q_count; + uint16_t num_srbs_allocated; + + /* DMA Memory Block */ + void *queues; + dma_addr_t queues_dma; + unsigned long queues_len; + +#define MEM_ALIGN_VALUE \ + ((max(REQUEST_QUEUE_DEPTH, RESPONSE_QUEUE_DEPTH)) * \ + sizeof(struct queue_entry)) + /* request and response queue variables */ + dma_addr_t request_dma; + struct queue_entry *request_ring; + struct queue_entry *request_ptr; + dma_addr_t response_dma; + struct queue_entry *response_ring; + struct queue_entry *response_ptr; + dma_addr_t shadow_regs_dma; + struct shadow_regs *shadow_regs; + uint16_t request_in; /* Current indexes. */ + uint16_t request_out; + uint16_t response_in; + uint16_t response_out; + + /* aen queue variables */ + uint16_t aen_q_count; /* Number of available aen_q entries */ + uint16_t aen_in; /* Current indexes */ + uint16_t aen_out; + struct aen aen_q[MAX_AEN_ENTRIES]; + + /* This mutex protects several threads to do mailbox commands + * concurrently. + */ + struct mutex mbox_sem; + wait_queue_head_t mailbox_wait_queue; + + /* temporary mailbox status registers */ + volatile uint8_t mbox_status_count; + volatile uint32_t mbox_status[MBOX_REG_COUNT]; + + /* local device database list (contains internal ddb entries) */ + struct list_head ddb_list; + + /* Map ddb_list entry by FW ddb index */ + struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES]; + +}; + +static inline int is_qla4010(struct scsi_qla_host *ha) +{ + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010; +} + +static inline int is_qla4022(struct scsi_qla_host *ha) +{ + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022; +} + +static inline int adapter_up(struct scsi_qla_host *ha) +{ + return (test_bit(AF_ONLINE, &ha->flags) != 0) && + (test_bit(AF_LINK_UP, &ha->flags) != 0); +} + +static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost) +{ + return (struct scsi_qla_host *)shost->hostdata; +} + +static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u1.isp4022.semaphore : + &ha->reg->u1.isp4010.nvram); +} + +static inline void __iomem* isp_nvram(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u1.isp4022.nvram : + &ha->reg->u1.isp4010.nvram); +} + +static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u2.isp4022.p0.ext_hw_conf : + &ha->reg->u2.isp4010.ext_hw_conf); +} + +static inline void __iomem* isp_port_status(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u2.isp4022.p0.port_status : + &ha->reg->u2.isp4010.port_status); +} + +static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u2.isp4022.p0.port_ctrl : + &ha->reg->u2.isp4010.port_ctrl); +} + +static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u2.isp4022.p0.port_err_status : + &ha->reg->u2.isp4010.port_err_status); +} + +static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + &ha->reg->u2.isp4022.p0.gp_out : + &ha->reg->u2.isp4010.gp_out); +} + +static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha) +{ + return (is_qla4022(ha) ? + offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2 : + offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2); +} + +int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits); +void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask); +int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits); + +static inline int ql4xxx_lock_flash(struct scsi_qla_host *a) +{ + if (is_qla4022(a)) + return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK, + (QL4022_RESOURCE_BITS_BASE_CODE | + (a->mac_index)) << 13); + else + return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK, + QL4010_FLASH_SEM_BITS); +} + +static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a) +{ + if (is_qla4022(a)) + ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK); + else + ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK); +} + +static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a) +{ + if (is_qla4022(a)) + return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK, + (QL4022_RESOURCE_BITS_BASE_CODE | + (a->mac_index)) << 10); + else + return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK, + QL4010_NVRAM_SEM_BITS); +} + +static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a) +{ + if (is_qla4022(a)) + ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK); + else + ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK); +} + +static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a) +{ + if (is_qla4022(a)) + return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK, + (QL4022_RESOURCE_BITS_BASE_CODE | + (a->mac_index)) << 1); + else + return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK, + QL4010_DRVR_SEM_BITS); +} + +static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) +{ + if (is_qla4022(a)) + ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK); + else + ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK); +} + +/*---------------------------------------------------------------------------*/ + +/* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */ +#define PRESERVE_DDB_LIST 0 +#define REBUILD_DDB_LIST 1 + +/* Defines for process_aen() */ +#define PROCESS_ALL_AENS 0 +#define FLUSH_DDB_CHANGED_AENS 1 +#define RELOGIN_DDB_CHANGED_AENS 2 + +#include "ql4_version.h" +#include "ql4_glbl.h" +#include "ql4_dbg.h" +#include "ql4_inline.h" + + +#endif /*_QLA4XXX_H */ diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h new file mode 100644 index 00000000000..427489de64b --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -0,0 +1,843 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#ifndef _QLA4X_FW_H +#define _QLA4X_FW_H + + +#define MAX_PRST_DEV_DB_ENTRIES 64 +#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES +#define MAX_DEV_DB_ENTRIES 512 + +/************************************************************************* + * + * ISP 4010 I/O Register Set Structure and Definitions + * + *************************************************************************/ + +struct port_ctrl_stat_regs { + __le32 ext_hw_conf; /* 80 x50 R/W */ + __le32 intChipConfiguration; /* 84 x54 */ + __le32 port_ctrl; /* 88 x58 */ + __le32 port_status; /* 92 x5c */ + __le32 HostPrimMACHi; /* 96 x60 */ + __le32 HostPrimMACLow; /* 100 x64 */ + __le32 HostSecMACHi; /* 104 x68 */ + __le32 HostSecMACLow; /* 108 x6c */ + __le32 EPPrimMACHi; /* 112 x70 */ + __le32 EPPrimMACLow; /* 116 x74 */ + __le32 EPSecMACHi; /* 120 x78 */ + __le32 EPSecMACLow; /* 124 x7c */ + __le32 HostPrimIPHi; /* 128 x80 */ + __le32 HostPrimIPMidHi; /* 132 x84 */ + __le32 HostPrimIPMidLow; /* 136 x88 */ + __le32 HostPrimIPLow; /* 140 x8c */ + __le32 HostSecIPHi; /* 144 x90 */ + __le32 HostSecIPMidHi; /* 148 x94 */ + __le32 HostSecIPMidLow; /* 152 x98 */ + __le32 HostSecIPLow; /* 156 x9c */ + __le32 EPPrimIPHi; /* 160 xa0 */ + __le32 EPPrimIPMidHi; /* 164 xa4 */ + __le32 EPPrimIPMidLow; /* 168 xa8 */ + __le32 EPPrimIPLow; /* 172 xac */ + __le32 EPSecIPHi; /* 176 xb0 */ + __le32 EPSecIPMidHi; /* 180 xb4 */ + __le32 EPSecIPMidLow; /* 184 xb8 */ + __le32 EPSecIPLow; /* 188 xbc */ + __le32 IPReassemblyTimeout; /* 192 xc0 */ + __le32 EthMaxFramePayload; /* 196 xc4 */ + __le32 TCPMaxWindowSize; /* 200 xc8 */ + __le32 TCPCurrentTimestampHi; /* 204 xcc */ + __le32 TCPCurrentTimestampLow; /* 208 xd0 */ + __le32 LocalRAMAddress; /* 212 xd4 */ + __le32 LocalRAMData; /* 216 xd8 */ + __le32 PCSReserved1; /* 220 xdc */ + __le32 gp_out; /* 224 xe0 */ + __le32 gp_in; /* 228 xe4 */ + __le32 ProbeMuxAddr; /* 232 xe8 */ + __le32 ProbeMuxData; /* 236 xec */ + __le32 ERMQueueBaseAddr0; /* 240 xf0 */ + __le32 ERMQueueBaseAddr1; /* 244 xf4 */ + __le32 MACConfiguration; /* 248 xf8 */ + __le32 port_err_status; /* 252 xfc COR */ +}; + +struct host_mem_cfg_regs { + __le32 NetRequestQueueOut; /* 80 x50 */ + __le32 NetRequestQueueOutAddrHi; /* 84 x54 */ + __le32 NetRequestQueueOutAddrLow; /* 88 x58 */ + __le32 NetRequestQueueBaseAddrHi; /* 92 x5c */ + __le32 NetRequestQueueBaseAddrLow; /* 96 x60 */ + __le32 NetRequestQueueLength; /* 100 x64 */ + __le32 NetResponseQueueIn; /* 104 x68 */ + __le32 NetResponseQueueInAddrHi; /* 108 x6c */ + __le32 NetResponseQueueInAddrLow; /* 112 x70 */ + __le32 NetResponseQueueBaseAddrHi; /* 116 x74 */ + __le32 NetResponseQueueBaseAddrLow; /* 120 x78 */ + __le32 NetResponseQueueLength; /* 124 x7c */ + __le32 req_q_out; /* 128 x80 */ + __le32 RequestQueueOutAddrHi; /* 132 x84 */ + __le32 RequestQueueOutAddrLow; /* 136 x88 */ + __le32 RequestQueueBaseAddrHi; /* 140 x8c */ + __le32 RequestQueueBaseAddrLow; /* 144 x90 */ + __le32 RequestQueueLength; /* 148 x94 */ + __le32 ResponseQueueIn; /* 152 x98 */ + __le32 ResponseQueueInAddrHi; /* 156 x9c */ + __le32 ResponseQueueInAddrLow; /* 160 xa0 */ + __le32 ResponseQueueBaseAddrHi; /* 164 xa4 */ + __le32 ResponseQueueBaseAddrLow; /* 168 xa8 */ + __le32 ResponseQueueLength; /* 172 xac */ + __le32 NetRxLargeBufferQueueOut; /* 176 xb0 */ + __le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */ + __le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */ + __le32 NetRxLargeBufferQueueLength; /* 188 xbc */ + __le32 NetRxLargeBufferLength; /* 192 xc0 */ + __le32 NetRxSmallBufferQueueOut; /* 196 xc4 */ + __le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */ + __le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */ + __le32 NetRxSmallBufferQueueLength; /* 208 xd0 */ + __le32 NetRxSmallBufferLength; /* 212 xd4 */ + __le32 HMCReserved0[10]; /* 216 xd8 */ +}; + +struct local_ram_cfg_regs { + __le32 BufletSize; /* 80 x50 */ + __le32 BufletMaxCount; /* 84 x54 */ + __le32 BufletCurrCount; /* 88 x58 */ + __le32 BufletPauseThresholdCount; /* 92 x5c */ + __le32 BufletTCPWinThresholdHi; /* 96 x60 */ + __le32 BufletTCPWinThresholdLow; /* 100 x64 */ + __le32 IPHashTableBaseAddr; /* 104 x68 */ + __le32 IPHashTableSize; /* 108 x6c */ + __le32 TCPHashTableBaseAddr; /* 112 x70 */ + __le32 TCPHashTableSize; /* 116 x74 */ + __le32 NCBAreaBaseAddr; /* 120 x78 */ + __le32 NCBMaxCount; /* 124 x7c */ + __le32 NCBCurrCount; /* 128 x80 */ + __le32 DRBAreaBaseAddr; /* 132 x84 */ + __le32 DRBMaxCount; /* 136 x88 */ + __le32 DRBCurrCount; /* 140 x8c */ + __le32 LRCReserved[28]; /* 144 x90 */ +}; + +struct prot_stat_regs { + __le32 MACTxFrameCount; /* 80 x50 R */ + __le32 MACTxByteCount; /* 84 x54 R */ + __le32 MACRxFrameCount; /* 88 x58 R */ + __le32 MACRxByteCount; /* 92 x5c R */ + __le32 MACCRCErrCount; /* 96 x60 R */ + __le32 MACEncErrCount; /* 100 x64 R */ + __le32 MACRxLengthErrCount; /* 104 x68 R */ + __le32 IPTxPacketCount; /* 108 x6c R */ + __le32 IPTxByteCount; /* 112 x70 R */ + __le32 IPTxFragmentCount; /* 116 x74 R */ + __le32 IPRxPacketCount; /* 120 x78 R */ + __le32 IPRxByteCount; /* 124 x7c R */ + __le32 IPRxFragmentCount; /* 128 x80 R */ + __le32 IPDatagramReassemblyCount; /* 132 x84 R */ + __le32 IPV6RxPacketCount; /* 136 x88 R */ + __le32 IPErrPacketCount; /* 140 x8c R */ + __le32 IPReassemblyErrCount; /* 144 x90 R */ + __le32 TCPTxSegmentCount; /* 148 x94 R */ + __le32 TCPTxByteCount; /* 152 x98 R */ + __le32 TCPRxSegmentCount; /* 156 x9c R */ + __le32 TCPRxByteCount; /* 160 xa0 R */ + __le32 TCPTimerExpCount; /* 164 xa4 R */ + __le32 TCPRxAckCount; /* 168 xa8 R */ + __le32 TCPTxAckCount; /* 172 xac R */ + __le32 TCPRxErrOOOCount; /* 176 xb0 R */ + __le32 PSReserved0; /* 180 xb4 */ + __le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */ + __le32 ECCErrCorrectionCount; /* 188 xbc R */ + __le32 PSReserved1[16]; /* 192 xc0 */ +}; + + +/* remote register set (access via PCI memory read/write) */ +struct isp_reg { +#define MBOX_REG_COUNT 8 + __le32 mailbox[MBOX_REG_COUNT]; + + __le32 flash_address; /* 0x20 */ + __le32 flash_data; + __le32 ctrl_status; + + union { + struct { + __le32 nvram; + __le32 reserved1[2]; /* 0x30 */ + } __attribute__ ((packed)) isp4010; + struct { + __le32 intr_mask; + __le32 nvram; /* 0x30 */ + __le32 semaphore; + } __attribute__ ((packed)) isp4022; + } u1; + + __le32 req_q_in; /* SCSI Request Queue Producer Index */ + __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */ + + __le32 reserved2[4]; /* 0x40 */ + + union { + struct { + __le32 ext_hw_conf; /* 0x50 */ + __le32 flow_ctrl; + __le32 port_ctrl; + __le32 port_status; + + __le32 reserved3[8]; /* 0x60 */ + + __le32 req_q_out; /* 0x80 */ + + __le32 reserved4[23]; /* 0x84 */ + + __le32 gp_out; /* 0xe0 */ + __le32 gp_in; + + __le32 reserved5[5]; + + __le32 port_err_status; /* 0xfc */ + } __attribute__ ((packed)) isp4010; + struct { + union { + struct port_ctrl_stat_regs p0; + struct host_mem_cfg_regs p1; + struct local_ram_cfg_regs p2; + struct prot_stat_regs p3; + __le32 r_union[44]; + }; + + } __attribute__ ((packed)) isp4022; + } u2; +}; /* 256 x100 */ + + +/* Semaphore Defines for 4010 */ +#define QL4010_DRVR_SEM_BITS 0x00000030 +#define QL4010_GPIO_SEM_BITS 0x000000c0 +#define QL4010_SDRAM_SEM_BITS 0x00000300 +#define QL4010_PHY_SEM_BITS 0x00000c00 +#define QL4010_NVRAM_SEM_BITS 0x00003000 +#define QL4010_FLASH_SEM_BITS 0x0000c000 + +#define QL4010_DRVR_SEM_MASK 0x00300000 +#define QL4010_GPIO_SEM_MASK 0x00c00000 +#define QL4010_SDRAM_SEM_MASK 0x03000000 +#define QL4010_PHY_SEM_MASK 0x0c000000 +#define QL4010_NVRAM_SEM_MASK 0x30000000 +#define QL4010_FLASH_SEM_MASK 0xc0000000 + +/* Semaphore Defines for 4022 */ +#define QL4022_RESOURCE_MASK_BASE_CODE 0x7 +#define QL4022_RESOURCE_BITS_BASE_CODE 0x4 + + +#define QL4022_DRVR_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (1+16)) +#define QL4022_DDR_RAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (4+16)) +#define QL4022_PHY_GIO_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (7+16)) +#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16)) +#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16)) + + + +/* Page # defines for 4022 */ +#define PORT_CTRL_STAT_PAGE 0 /* 4022 */ +#define HOST_MEM_CFG_PAGE 1 /* 4022 */ +#define LOCAL_RAM_CFG_PAGE 2 /* 4022 */ +#define PROT_STAT_PAGE 3 /* 4022 */ + +/* Register Mask - sets corresponding mask bits in the upper word */ +static inline uint32_t set_rmask(uint32_t val) +{ + return (val & 0xffff) | (val << 16); +} + + +static inline uint32_t clr_rmask(uint32_t val) +{ + return 0 | (val << 16); +} + +/* ctrl_status definitions */ +#define CSR_SCSI_PAGE_SELECT 0x00000003 +#define CSR_SCSI_INTR_ENABLE 0x00000004 /* 4010 */ +#define CSR_SCSI_RESET_INTR 0x00000008 +#define CSR_SCSI_COMPLETION_INTR 0x00000010 +#define CSR_SCSI_PROCESSOR_INTR 0x00000020 +#define CSR_INTR_RISC 0x00000040 +#define CSR_BOOT_ENABLE 0x00000080 +#define CSR_NET_PAGE_SELECT 0x00000300 /* 4010 */ +#define CSR_FUNC_NUM 0x00000700 /* 4022 */ +#define CSR_NET_RESET_INTR 0x00000800 /* 4010 */ +#define CSR_FORCE_SOFT_RESET 0x00002000 /* 4022 */ +#define CSR_FATAL_ERROR 0x00004000 +#define CSR_SOFT_RESET 0x00008000 +#define ISP_CONTROL_FN_MASK CSR_FUNC_NUM +#define ISP_CONTROL_FN0_SCSI 0x0500 +#define ISP_CONTROL_FN1_SCSI 0x0700 + +#define INTR_PENDING (CSR_SCSI_COMPLETION_INTR |\ + CSR_SCSI_PROCESSOR_INTR |\ + CSR_SCSI_RESET_INTR) + +/* ISP InterruptMask definitions */ +#define IMR_SCSI_INTR_ENABLE 0x00000004 /* 4022 */ + +/* ISP 4022 nvram definitions */ +#define NVR_WRITE_ENABLE 0x00000010 /* 4022 */ + +/* ISP port_status definitions */ + +/* ISP Semaphore definitions */ + +/* ISP General Purpose Output definitions */ +#define GPOR_TOPCAT_RESET 0x00000004 + +/* shadow registers (DMA'd from HA to system memory. read only) */ +struct shadow_regs { + /* SCSI Request Queue Consumer Index */ + __le32 req_q_out; /* 0 x0 R */ + + /* SCSI Completion Queue Producer Index */ + __le32 rsp_q_in; /* 4 x4 R */ +}; /* 8 x8 */ + + +/* External hardware configuration register */ +union external_hw_config_reg { + struct { + /* FIXME: Do we even need this? All values are + * referred to by 16 bit quantities. Platform and + * endianess issues. */ + __le32 bReserved0:1; + __le32 bSDRAMProtectionMethod:2; + __le32 bSDRAMBanks:1; + __le32 bSDRAMChipWidth:1; + __le32 bSDRAMChipSize:2; + __le32 bParityDisable:1; + __le32 bExternalMemoryType:1; + __le32 bFlashBIOSWriteEnable:1; + __le32 bFlashUpperBankSelect:1; + __le32 bWriteBurst:2; + __le32 bReserved1:3; + __le32 bMask:16; + }; + uint32_t Asuint32_t; +}; + +/************************************************************************* + * + * Mailbox Commands Structures and Definitions + * + *************************************************************************/ + +/* Mailbox command definitions */ +#define MBOX_CMD_ABOUT_FW 0x0009 +#define MBOX_CMD_LUN_RESET 0x0016 +#define MBOX_CMD_GET_FW_STATUS 0x001F +#define MBOX_CMD_SET_ISNS_SERVICE 0x0021 +#define ISNS_DISABLE 0 +#define ISNS_ENABLE 1 +#define MBOX_CMD_READ_FLASH 0x0026 +#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031 +#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056 +#define LOGOUT_OPTION_CLOSE_SESSION 0x01 +#define LOGOUT_OPTION_RELOGIN 0x02 +#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A +#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060 +#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061 +#define MBOX_CMD_REQUEST_DATABASE_ENTRY 0x0062 +#define MBOX_CMD_SET_DATABASE_ENTRY 0x0063 +#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064 +#define DDB_DS_UNASSIGNED 0x00 +#define DDB_DS_NO_CONNECTION_ACTIVE 0x01 +#define DDB_DS_SESSION_ACTIVE 0x04 +#define DDB_DS_SESSION_FAILED 0x06 +#define DDB_DS_LOGIN_IN_PROCESS 0x07 +#define MBOX_CMD_GET_FW_STATE 0x0069 + +/* Mailbox 1 */ +#define FW_STATE_READY 0x0000 +#define FW_STATE_CONFIG_WAIT 0x0001 +#define FW_STATE_ERROR 0x0004 +#define FW_STATE_DHCP_IN_PROGRESS 0x0008 + +/* Mailbox 3 */ +#define FW_ADDSTATE_OPTICAL_MEDIA 0x0001 +#define FW_ADDSTATE_DHCP_ENABLED 0x0002 +#define FW_ADDSTATE_LINK_UP 0x0010 +#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020 +#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B +#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074 +#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */ +#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077 + +/* Mailbox status definitions */ +#define MBOX_COMPLETION_STATUS 4 +#define MBOX_STS_BUSY 0x0007 +#define MBOX_STS_INTERMEDIATE_COMPLETION 0x1000 +#define MBOX_STS_COMMAND_COMPLETE 0x4000 +#define MBOX_STS_COMMAND_ERROR 0x4005 + +#define MBOX_ASYNC_EVENT_STATUS 8 +#define MBOX_ASTS_SYSTEM_ERROR 0x8002 +#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003 +#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004 +#define MBOX_ASTS_PROTOCOL_STATISTIC_ALARM 0x8005 +#define MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED 0x8006 +#define MBOX_ASTS_LINK_UP 0x8010 +#define MBOX_ASTS_LINK_DOWN 0x8011 +#define MBOX_ASTS_DATABASE_CHANGED 0x8014 +#define MBOX_ASTS_UNSOLICITED_PDU_RECEIVED 0x8015 +#define MBOX_ASTS_SELF_TEST_FAILED 0x8016 +#define MBOX_ASTS_LOGIN_FAILED 0x8017 +#define MBOX_ASTS_DNS 0x8018 +#define MBOX_ASTS_HEARTBEAT 0x8019 +#define MBOX_ASTS_NVRAM_INVALID 0x801A +#define MBOX_ASTS_MAC_ADDRESS_CHANGED 0x801B +#define MBOX_ASTS_IP_ADDRESS_CHANGED 0x801C +#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D +#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F +#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021 +#define ISNS_EVENT_DATA_RECEIVED 0x0000 +#define ISNS_EVENT_CONNECTION_OPENED 0x0001 +#define ISNS_EVENT_CONNECTION_FAILED 0x0002 +#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022 +#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027 + +/*************************************************************************/ + +/* Host Adapter Initialization Control Block (from host) */ +struct init_fw_ctrl_blk { + uint8_t Version; /* 00 */ + uint8_t Control; /* 01 */ + + uint16_t FwOptions; /* 02-03 */ +#define FWOPT_HEARTBEAT_ENABLE 0x1000 +#define FWOPT_SESSION_MODE 0x0040 +#define FWOPT_INITIATOR_MODE 0x0020 +#define FWOPT_TARGET_MODE 0x0010 + + uint16_t ExecThrottle; /* 04-05 */ + uint8_t RetryCount; /* 06 */ + uint8_t RetryDelay; /* 07 */ + uint16_t MaxEthFrPayloadSize; /* 08-09 */ + uint16_t AddFwOptions; /* 0A-0B */ + + uint8_t HeartbeatInterval; /* 0C */ + uint8_t InstanceNumber; /* 0D */ + uint16_t RES2; /* 0E-0F */ + uint16_t ReqQConsumerIndex; /* 10-11 */ + uint16_t ComplQProducerIndex; /* 12-13 */ + uint16_t ReqQLen; /* 14-15 */ + uint16_t ComplQLen; /* 16-17 */ + uint32_t ReqQAddrLo; /* 18-1B */ + uint32_t ReqQAddrHi; /* 1C-1F */ + uint32_t ComplQAddrLo; /* 20-23 */ + uint32_t ComplQAddrHi; /* 24-27 */ + uint32_t ShadowRegBufAddrLo; /* 28-2B */ + uint32_t ShadowRegBufAddrHi; /* 2C-2F */ + + uint16_t iSCSIOptions; /* 30-31 */ + + uint16_t TCPOptions; /* 32-33 */ + + uint16_t IPOptions; /* 34-35 */ + + uint16_t MaxPDUSize; /* 36-37 */ + uint16_t RcvMarkerInt; /* 38-39 */ + uint16_t SndMarkerInt; /* 3A-3B */ + uint16_t InitMarkerlessInt; /* 3C-3D */ + uint16_t FirstBurstSize; /* 3E-3F */ + uint16_t DefaultTime2Wait; /* 40-41 */ + uint16_t DefaultTime2Retain; /* 42-43 */ + uint16_t MaxOutStndngR2T; /* 44-45 */ + uint16_t KeepAliveTimeout; /* 46-47 */ + uint16_t PortNumber; /* 48-49 */ + uint16_t MaxBurstSize; /* 4A-4B */ + uint32_t RES4; /* 4C-4F */ + uint8_t IPAddr[4]; /* 50-53 */ + uint8_t RES5[12]; /* 54-5F */ + uint8_t SubnetMask[4]; /* 60-63 */ + uint8_t RES6[12]; /* 64-6F */ + uint8_t GatewayIPAddr[4]; /* 70-73 */ + uint8_t RES7[12]; /* 74-7F */ + uint8_t PriDNSIPAddr[4]; /* 80-83 */ + uint8_t SecDNSIPAddr[4]; /* 84-87 */ + uint8_t RES8[8]; /* 88-8F */ + uint8_t Alias[32]; /* 90-AF */ + uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */ + uint8_t CHAPNameSecretsTable[8]; /* B8-BF */ + uint8_t EthernetMACAddr[6]; /* C0-C5 */ + uint16_t TargetPortalGroup; /* C6-C7 */ + uint8_t SendScale; /* C8 */ + uint8_t RecvScale; /* C9 */ + uint8_t TypeOfService; /* CA */ + uint8_t Time2Live; /* CB */ + uint16_t VLANPriority; /* CC-CD */ + uint16_t Reserved8; /* CE-CF */ + uint8_t SecIPAddr[4]; /* D0-D3 */ + uint8_t Reserved9[12]; /* D4-DF */ + uint8_t iSNSIPAddr[4]; /* E0-E3 */ + uint16_t iSNSServerPortNumber; /* E4-E5 */ + uint8_t Reserved10[10]; /* E6-EF */ + uint8_t SLPDAIPAddr[4]; /* F0-F3 */ + uint8_t Reserved11[12]; /* F4-FF */ + uint8_t iSCSINameString[256]; /* 100-1FF */ +}; + +/*************************************************************************/ + +struct dev_db_entry { + uint8_t options; /* 00 */ +#define DDB_OPT_DISC_SESSION 0x10 +#define DDB_OPT_TARGET 0x02 /* device is a target */ + + uint8_t control; /* 01 */ + + uint16_t exeThrottle; /* 02-03 */ + uint16_t exeCount; /* 04-05 */ + uint8_t retryCount; /* 06 */ + uint8_t retryDelay; /* 07 */ + uint16_t iSCSIOptions; /* 08-09 */ + + uint16_t TCPOptions; /* 0A-0B */ + + uint16_t IPOptions; /* 0C-0D */ + + uint16_t maxPDUSize; /* 0E-0F */ + uint16_t rcvMarkerInt; /* 10-11 */ + uint16_t sndMarkerInt; /* 12-13 */ + uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */ + uint16_t firstBurstSize; /* 16-17 */ + uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */ + uint16_t maxTime2Retain; /* 1A-1B */ + uint16_t maxOutstndngR2T; /* 1C-1D */ + uint16_t keepAliveTimeout; /* 1E-1F */ + uint8_t ISID[6]; /* 20-25 big-endian, must be converted + * to little-endian */ + uint16_t TSID; /* 26-27 */ + uint16_t portNumber; /* 28-29 */ + uint16_t maxBurstSize; /* 2A-2B */ + uint16_t taskMngmntTimeout; /* 2C-2D */ + uint16_t reserved1; /* 2E-2F */ + uint8_t ipAddr[0x10]; /* 30-3F */ + uint8_t iSCSIAlias[0x20]; /* 40-5F */ + uint8_t targetAddr[0x20]; /* 60-7F */ + uint8_t userID[0x20]; /* 80-9F */ + uint8_t password[0x20]; /* A0-BF */ + uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a + * pointer to a string so we + * don't have to reserve soooo + * much RAM */ + uint16_t ddbLink; /* 1C0-1C1 */ + uint16_t CHAPTableIndex; /* 1C2-1C3 */ + uint16_t TargetPortalGroup; /* 1C4-1C5 */ + uint16_t reserved2[2]; /* 1C6-1C7 */ + uint32_t statSN; /* 1C8-1CB */ + uint32_t expStatSN; /* 1CC-1CF */ + uint16_t reserved3[0x2C]; /* 1D0-1FB */ + uint16_t ddbValidCookie; /* 1FC-1FD */ + uint16_t ddbValidSize; /* 1FE-1FF */ +}; + +/*************************************************************************/ + +/* Flash definitions */ + +#define FLASH_OFFSET_SYS_INFO 0x02000000 +#define FLASH_DEFAULTBLOCKSIZE 0x20000 +#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes + * for EOF + * signature */ + +struct sys_info_phys_addr { + uint8_t address[6]; /* 00-05 */ + uint8_t filler[2]; /* 06-07 */ +}; + +struct flash_sys_info { + uint32_t cookie; /* 00-03 */ + uint32_t physAddrCount; /* 04-07 */ + struct sys_info_phys_addr physAddr[4]; /* 08-27 */ + uint8_t vendorId[128]; /* 28-A7 */ + uint8_t productId[128]; /* A8-127 */ + uint32_t serialNumber; /* 128-12B */ + + /* PCI Configuration values */ + uint32_t pciDeviceVendor; /* 12C-12F */ + uint32_t pciDeviceId; /* 130-133 */ + uint32_t pciSubsysVendor; /* 134-137 */ + uint32_t pciSubsysId; /* 138-13B */ + + /* This validates version 1. */ + uint32_t crumbs; /* 13C-13F */ + + uint32_t enterpriseNumber; /* 140-143 */ + + uint32_t mtu; /* 144-147 */ + uint32_t reserved0; /* 148-14b */ + uint32_t crumbs2; /* 14c-14f */ + uint8_t acSerialNumber[16]; /* 150-15f */ + uint32_t crumbs3; /* 160-16f */ + + /* Leave this last in the struct so it is declared invalid if + * any new items are added. + */ + uint32_t reserved1[39]; /* 170-1ff */ +}; /* 200 */ + +struct crash_record { + uint16_t fw_major_version; /* 00 - 01 */ + uint16_t fw_minor_version; /* 02 - 03 */ + uint16_t fw_patch_version; /* 04 - 05 */ + uint16_t fw_build_version; /* 06 - 07 */ + + uint8_t build_date[16]; /* 08 - 17 */ + uint8_t build_time[16]; /* 18 - 27 */ + uint8_t build_user[16]; /* 28 - 37 */ + uint8_t card_serial_num[16]; /* 38 - 47 */ + + uint32_t time_of_crash_in_secs; /* 48 - 4B */ + uint32_t time_of_crash_in_ms; /* 4C - 4F */ + + uint16_t out_RISC_sd_num_frames; /* 50 - 51 */ + uint16_t OAP_sd_num_words; /* 52 - 53 */ + uint16_t IAP_sd_num_frames; /* 54 - 55 */ + uint16_t in_RISC_sd_num_words; /* 56 - 57 */ + + uint8_t reserved1[28]; /* 58 - 7F */ + + uint8_t out_RISC_reg_dump[256]; /* 80 -17F */ + uint8_t in_RISC_reg_dump[256]; /*180 -27F */ + uint8_t in_out_RISC_stack_dump[0]; /*280 - ??? */ +}; + +struct conn_event_log_entry { +#define MAX_CONN_EVENT_LOG_ENTRIES 100 + uint32_t timestamp_sec; /* 00 - 03 seconds since boot */ + uint32_t timestamp_ms; /* 04 - 07 milliseconds since boot */ + uint16_t device_index; /* 08 - 09 */ + uint16_t fw_conn_state; /* 0A - 0B */ + uint8_t event_type; /* 0C - 0C */ + uint8_t error_code; /* 0D - 0D */ + uint16_t error_code_detail; /* 0E - 0F */ + uint8_t num_consecutive_events; /* 10 - 10 */ + uint8_t rsvd[3]; /* 11 - 13 */ +}; + +/************************************************************************* + * + * IOCB Commands Structures and Definitions + * + *************************************************************************/ +#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */ +#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */ + +/* IOCB header structure */ +struct qla4_header { + uint8_t entryType; +#define ET_STATUS 0x03 +#define ET_MARKER 0x04 +#define ET_CONT_T1 0x0A +#define ET_STATUS_CONTINUATION 0x10 +#define ET_CMND_T3 0x19 +#define ET_PASSTHRU0 0x3A +#define ET_PASSTHRU_STATUS 0x3C + + uint8_t entryStatus; + uint8_t systemDefined; + uint8_t entryCount; + + /* SyetemDefined definition */ +}; + +/* Generic queue entry structure*/ +struct queue_entry { + uint8_t data[60]; + uint32_t signature; + +}; + +/* 64 bit addressing segment counts*/ + +#define COMMAND_SEG_A64 1 +#define CONTINUE_SEG_A64 5 + +/* 64 bit addressing segment definition*/ + +struct data_seg_a64 { + struct { + uint32_t addrLow; + uint32_t addrHigh; + + } base; + + uint32_t count; + +}; + +/* Command Type 3 entry structure*/ + +struct command_t3_entry { + struct qla4_header hdr; /* 00-03 */ + + uint32_t handle; /* 04-07 */ + uint16_t target; /* 08-09 */ + uint16_t connection_id; /* 0A-0B */ + + uint8_t control_flags; /* 0C */ + + /* data direction (bits 5-6) */ +#define CF_WRITE 0x20 +#define CF_READ 0x40 +#define CF_NO_DATA 0x00 + + /* task attributes (bits 2-0) */ +#define CF_HEAD_TAG 0x03 +#define CF_ORDERED_TAG 0x02 +#define CF_SIMPLE_TAG 0x01 + + /* STATE FLAGS FIELD IS A PLACE HOLDER. THE FW WILL SET BITS + * IN THIS FIELD AS THE COMMAND IS PROCESSED. WHEN THE IOCB IS + * CHANGED TO AN IOSB THIS FIELD WILL HAVE THE STATE FLAGS SET + * PROPERLY. + */ + uint8_t state_flags; /* 0D */ + uint8_t cmdRefNum; /* 0E */ + uint8_t reserved1; /* 0F */ + uint8_t cdb[IOCB_MAX_CDB_LEN]; /* 10-1F */ + struct scsi_lun lun; /* FCP LUN (BE). */ + uint32_t cmdSeqNum; /* 28-2B */ + uint16_t timeout; /* 2C-2D */ + uint16_t dataSegCnt; /* 2E-2F */ + uint32_t ttlByteCnt; /* 30-33 */ + struct data_seg_a64 dataseg[COMMAND_SEG_A64]; /* 34-3F */ + +}; + + +/* Continuation Type 1 entry structure*/ +struct continuation_t1_entry { + struct qla4_header hdr; + + struct data_seg_a64 dataseg[CONTINUE_SEG_A64]; + +}; + +/* Parameterize for 64 or 32 bits */ +#define COMMAND_SEG COMMAND_SEG_A64 +#define CONTINUE_SEG CONTINUE_SEG_A64 + +#define ET_COMMAND ET_CMND_T3 +#define ET_CONTINUE ET_CONT_T1 + +/* Marker entry structure*/ +struct marker_entry { + struct qla4_header hdr; /* 00-03 */ + + uint32_t system_defined; /* 04-07 */ + uint16_t target; /* 08-09 */ + uint16_t modifier; /* 0A-0B */ +#define MM_LUN_RESET 0 + + uint16_t flags; /* 0C-0D */ + uint16_t reserved1; /* 0E-0F */ + struct scsi_lun lun; /* FCP LUN (BE). */ + uint64_t reserved2; /* 18-1F */ + uint64_t reserved3; /* 20-27 */ + uint64_t reserved4; /* 28-2F */ + uint64_t reserved5; /* 30-37 */ + uint64_t reserved6; /* 38-3F */ +}; + +/* Status entry structure*/ +struct status_entry { + struct qla4_header hdr; /* 00-03 */ + + uint32_t handle; /* 04-07 */ + + uint8_t scsiStatus; /* 08 */ +#define SCSI_CHECK_CONDITION 0x02 + + uint8_t iscsiFlags; /* 09 */ +#define ISCSI_FLAG_RESIDUAL_UNDER 0x02 +#define ISCSI_FLAG_RESIDUAL_OVER 0x04 + + uint8_t iscsiResponse; /* 0A */ + + uint8_t completionStatus; /* 0B */ +#define SCS_COMPLETE 0x00 +#define SCS_INCOMPLETE 0x01 +#define SCS_RESET_OCCURRED 0x04 +#define SCS_ABORTED 0x05 +#define SCS_TIMEOUT 0x06 +#define SCS_DATA_OVERRUN 0x07 +#define SCS_DATA_UNDERRUN 0x15 +#define SCS_QUEUE_FULL 0x1C +#define SCS_DEVICE_UNAVAILABLE 0x28 +#define SCS_DEVICE_LOGGED_OUT 0x29 + + uint8_t reserved1; /* 0C */ + + /* state_flags MUST be at the same location as state_flags in + * the Command_T3/4_Entry */ + uint8_t state_flags; /* 0D */ + + uint16_t senseDataByteCnt; /* 0E-0F */ + uint32_t residualByteCnt; /* 10-13 */ + uint32_t bidiResidualByteCnt; /* 14-17 */ + uint32_t expSeqNum; /* 18-1B */ + uint32_t maxCmdSeqNum; /* 1C-1F */ + uint8_t senseData[IOCB_MAX_SENSEDATA_LEN]; /* 20-3F */ + +}; + +struct passthru0 { + struct qla4_header hdr; /* 00-03 */ + uint32_t handle; /* 04-07 */ + uint16_t target; /* 08-09 */ + uint16_t connectionID; /* 0A-0B */ +#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000) + + uint16_t controlFlags; /* 0C-0D */ +#define PT_FLAG_ETHERNET_FRAME 0x8000 +#define PT_FLAG_ISNS_PDU 0x8000 +#define PT_FLAG_SEND_BUFFER 0x0200 +#define PT_FLAG_WAIT_4_RESPONSE 0x0100 + + uint16_t timeout; /* 0E-0F */ +#define PT_DEFAULT_TIMEOUT 30 /* seconds */ + + struct data_seg_a64 outDataSeg64; /* 10-1B */ + uint32_t res1; /* 1C-1F */ + struct data_seg_a64 inDataSeg64; /* 20-2B */ + uint8_t res2[20]; /* 2C-3F */ +}; + +struct passthru_status { + struct qla4_header hdr; /* 00-03 */ + uint32_t handle; /* 04-07 */ + uint16_t target; /* 08-09 */ + uint16_t connectionID; /* 0A-0B */ + + uint8_t completionStatus; /* 0C */ +#define PASSTHRU_STATUS_COMPLETE 0x01 + + uint8_t residualFlags; /* 0D */ + + uint16_t timeout; /* 0E-0F */ + uint16_t portNumber; /* 10-11 */ + uint8_t res1[10]; /* 12-1B */ + uint32_t outResidual; /* 1C-1F */ + uint8_t res2[12]; /* 20-2B */ + uint32_t inResidual; /* 2C-2F */ + uint8_t res4[16]; /* 30-3F */ +}; + +#endif /* _QLA4X_FW_H */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h new file mode 100644 index 00000000000..418fb7a13a6 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -0,0 +1,78 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#ifndef __QLA4x_GBL_H +#define __QLA4x_GBL_H + +int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); +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); + +void qla4xxx_free_ddb_list(struct scsi_qla_host * ha); +void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen); + +int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha); +int qla4xxx_relogin_device(struct scsi_qla_host * ha, + struct ddb_entry * ddb_entry); +int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, + int lun); +int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, + uint32_t offset, uint32_t len); +int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); +int qla4xxx_get_firmware_state(struct scsi_qla_host * ha); +int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha); + +/* FIXME: Goodness! this really wants a small struct to hold the + * parameters. On x86 the args will get passed on the stack! */ +int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, + uint16_t fw_ddb_index, + struct dev_db_entry *fw_ddb_entry, + dma_addr_t fw_ddb_entry_dma, + uint32_t *num_valid_ddb_entries, + uint32_t *next_ddb_index, + uint32_t *fw_ddb_device_state, + uint32_t *conn_err_detail, + uint16_t *tcp_source_port_num, + uint16_t *connection_id); + +struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha, + uint32_t fw_ddb_index); +int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, + dma_addr_t fw_ddb_entry_dma); + +void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry); +u16 rd_nvram_word(struct scsi_qla_host * ha, int offset); +void qla4xxx_get_crash_record(struct scsi_qla_host * ha); +struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha); +int qla4xxx_add_sess(struct ddb_entry *); +void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry); +int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, + uint16_t fw_ddb_index, + uint16_t connection_id, + uint16_t option); +int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, + uint16_t fw_ddb_index); +int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha); +int qla4xxx_get_fw_version(struct scsi_qla_host * ha); +void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, + uint32_t intr_status); +int qla4xxx_init_rings(struct scsi_qla_host * ha); +void qla4xxx_dump_buffer(void *b, uint32_t size); +struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index); +void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); +int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); +int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, + uint32_t fw_ddb_index, uint32_t state); + +extern int extended_error_logging; +extern int ql4xdiscoverywait; +extern int ql4xdontresethba; +#endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c new file mode 100644 index 00000000000..bb3a1c11f44 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -0,0 +1,1340 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#include "ql4_def.h" + +/* + * QLogic ISP4xxx Hardware Support Function Prototypes. + */ + +static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) +{ + uint32_t value; + uint8_t func_number; + unsigned long flags; + + /* Get the function number */ + spin_lock_irqsave(&ha->hardware_lock, flags); + value = readw(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + func_number = (uint8_t) ((value >> 4) & 0x30); + switch (value & ISP_CONTROL_FN_MASK) { + case ISP_CONTROL_FN0_SCSI: + ha->mac_index = 1; + break; + case ISP_CONTROL_FN1_SCSI: + ha->mac_index = 3; + break; + default: + DEBUG2(printk("scsi%ld: %s: Invalid function number, " + "ispControlStatus = 0x%x\n", ha->host_no, + __func__, value)); + break; + } + DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__, + ha->mac_index)); +} + +/** + * qla4xxx_free_ddb - deallocate ddb + * @ha: pointer to host adapter structure. + * @ddb_entry: pointer to device database entry + * + * This routine deallocates and unlinks the specified ddb_entry from the + * adapter's + **/ +void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) +{ + /* Remove device entry from list */ + list_del_init(&ddb_entry->list); + + /* Remove device pointer from index mapping arrays */ + ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = + (struct ddb_entry *) INVALID_ENTRY; + ha->tot_ddbs--; + + /* Free memory and scsi-ml struct for device entry */ + qla4xxx_destroy_sess(ddb_entry); +} + +/** + * qla4xxx_free_ddb_list - deallocate all ddbs + * @ha: pointer to host adapter structure. + * + * This routine deallocates and removes all devices on the sppecified adapter. + **/ +void qla4xxx_free_ddb_list(struct scsi_qla_host *ha) +{ + struct list_head *ptr; + struct ddb_entry *ddb_entry; + + while (!list_empty(&ha->ddb_list)) { + ptr = ha->ddb_list.next; + /* Free memory for device entry and remove */ + ddb_entry = list_entry(ptr, struct ddb_entry, list); + qla4xxx_free_ddb(ha, ddb_entry); + } +} + +/** + * qla4xxx_init_rings - initialize hw queues + * @ha: pointer to host adapter structure. + * + * This routine initializes the internal queues for the specified adapter. + * The QLA4010 requires us to restart the queues at index 0. + * The QLA4000 doesn't care, so just default to QLA4010's requirement. + **/ +int qla4xxx_init_rings(struct scsi_qla_host *ha) +{ + unsigned long flags = 0; + + /* Initialize request queue. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->request_out = 0; + ha->request_in = 0; + ha->request_ptr = &ha->request_ring[ha->request_in]; + ha->req_q_count = REQUEST_QUEUE_DEPTH; + + /* Initialize response queue. */ + ha->response_in = 0; + ha->response_out = 0; + ha->response_ptr = &ha->response_ring[ha->response_out]; + + /* + * Initialize DMA Shadow registers. The firmware is really supposed to + * take care of this, but on some uniprocessor systems, the shadow + * registers aren't cleared-- causing the interrupt_handler to think + * there are responses to be processed when there aren't. + */ + ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0); + ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0); + wmb(); + + writel(0, &ha->reg->req_q_in); + writel(0, &ha->reg->rsp_q_out); + readl(&ha->reg->rsp_q_out); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_SUCCESS; +} + +/** + * qla4xxx_validate_mac_address - validate adapter MAC address(es) + * @ha: pointer to host adapter structure. + * + **/ +static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) +{ + struct flash_sys_info *sys_info; + dma_addr_t sys_info_dma; + int status = QLA_ERROR; + + sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), + &sys_info_dma, GFP_KERNEL); + if (sys_info == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", + ha->host_no, __func__)); + + goto exit_validate_mac_no_free; + } + memset(sys_info, 0, sizeof(*sys_info)); + + /* Get flash sys info */ + if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO, + sizeof(*sys_info)) != QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO " + "failed\n", ha->host_no, __func__)); + + goto exit_validate_mac; + } + + /* Save M.A.C. address & serial_number */ + memcpy(ha->my_mac, &sys_info->physAddr[0].address[0], + min(sizeof(ha->my_mac), + sizeof(sys_info->physAddr[0].address))); + memcpy(ha->serial_number, &sys_info->acSerialNumber, + min(sizeof(ha->serial_number), + sizeof(sys_info->acSerialNumber))); + + status = QLA_SUCCESS; + + exit_validate_mac: + dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info, + sys_info_dma); + + exit_validate_mac_no_free: + return status; +} + +/** + * qla4xxx_init_local_data - initialize adapter specific local data + * @ha: pointer to host adapter structure. + * + **/ +static int qla4xxx_init_local_data(struct scsi_qla_host *ha) +{ + /* Initilize aen queue */ + ha->aen_q_count = MAX_AEN_ENTRIES; + + return qla4xxx_get_firmware_status(ha); +} + +static int qla4xxx_fw_ready(struct scsi_qla_host *ha) +{ + uint32_t timeout_count; + int ready = 0; + + DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n")); + for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0; + timeout_count--) { + if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) + qla4xxx_get_dhcp_ip_address(ha); + + /* Get firmware state. */ + if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: unable to get firmware " + "state\n", ha->host_no, __func__)); + break; + + } + + if (ha->firmware_state & FW_STATE_ERROR) { + DEBUG2(printk("scsi%ld: %s: an unrecoverable error has" + " occurred\n", ha->host_no, __func__)); + break; + + } + if (ha->firmware_state & FW_STATE_CONFIG_WAIT) { + /* + * The firmware has not yet been issued an Initialize + * Firmware command, so issue it now. + */ + if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) + break; + + /* Go back and test for ready state - no wait. */ + continue; + } + + if (ha->firmware_state == FW_STATE_READY) { + DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n")); + /* The firmware is ready to process SCSI commands. */ + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: MEDIA TYPE - %s\n", + ha->host_no, + __func__, (ha->addl_fw_state & + FW_ADDSTATE_OPTICAL_MEDIA) + != 0 ? "OPTICAL" : "COPPER")); + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: DHCP STATE Enabled " + "%s\n", + ha->host_no, __func__, + (ha->addl_fw_state & + FW_ADDSTATE_DHCP_ENABLED) != 0 ? + "YES" : "NO")); + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: LINK %s\n", + ha->host_no, __func__, + (ha->addl_fw_state & + FW_ADDSTATE_LINK_UP) != 0 ? + "UP" : "DOWN")); + DEBUG2(dev_info(&ha->pdev->dev, + "scsi%ld: %s: iSNS Service " + "Started %s\n", + ha->host_no, __func__, + (ha->addl_fw_state & + FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? + "YES" : "NO")); + + ready = 1; + break; + } + DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " + "seconds expired= %d\n", ha->host_no, __func__, + ha->firmware_state, ha->addl_fw_state, + timeout_count)); + msleep(1000); + } /* end of for */ + + if (timeout_count <= 0) + DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", + ha->host_no, __func__)); + + if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) { + DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to" + " grab an IP address from DHCP server\n", + ha->host_no, __func__)); + ready = 1; + } + + return ready; +} + +/** + * qla4xxx_init_firmware - initializes the firmware. + * @ha: pointer to host adapter structure. + * + **/ +static int qla4xxx_init_firmware(struct scsi_qla_host *ha) +{ + int status = QLA_ERROR; + + dev_info(&ha->pdev->dev, "Initializing firmware..\n"); + if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) { + DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware " + "control block\n", ha->host_no, __func__)); + return status; + } + if (!qla4xxx_fw_ready(ha)) + return status; + + set_bit(AF_ONLINE, &ha->flags); + return qla4xxx_get_firmware_status(ha); +} + +static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, + uint32_t fw_ddb_index) +{ + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + struct ddb_entry *ddb_entry = NULL; + int found = 0; + uint32_t device_state; + + /* Make sure the dma buffer is valid */ + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, + sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (fw_ddb_entry == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", + ha->host_no, __func__)); + return NULL; + } + + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, NULL, + &device_state, NULL, NULL, NULL) == + QLA_ERROR) { + DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " + "fw_ddb_index %d\n", ha->host_no, __func__, + fw_ddb_index)); + return NULL; + } + + /* Allocate DDB if not already allocated. */ + DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no, + __func__, fw_ddb_index)); + list_for_each_entry(ddb_entry, &ha->ddb_list, list) { + if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsiName, + ISCSI_NAME_SIZE) == 0) { + found++; + break; + } + } + + if (!found) { + DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating " + "new ddb\n", ha->host_no, __func__, + fw_ddb_index)); + ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); + } + + /* if not found allocate new ddb */ + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); + + return ddb_entry; +} + +/** + * qla4xxx_update_ddb_entry - update driver's internal ddb + * @ha: pointer to host adapter structure. + * @ddb_entry: pointer to device database structure to be filled + * @fw_ddb_index: index of the ddb entry in fw ddb table + * + * This routine updates the driver's internal device database entry + * with information retrieved from the firmware's device database + * entry for the specified device. The ddb_entry->fw_ddb_index field + * must be initialized prior to calling this routine + * + **/ +int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + uint32_t fw_ddb_index) +{ + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + int status = QLA_ERROR; + + if (ddb_entry == NULL) { + DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no, + __func__)); + goto exit_update_ddb; + } + + /* Make sure the dma buffer is valid */ + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, + sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (fw_ddb_entry == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", + ha->host_no, __func__)); + + goto exit_update_ddb; + } + + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, NULL, + &ddb_entry->fw_ddb_device_state, NULL, + &ddb_entry->tcp_source_port_num, + &ddb_entry->connection_id) == + QLA_ERROR) { + DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " + "fw_ddb_index %d\n", ha->host_no, __func__, + fw_ddb_index)); + + goto exit_update_ddb; + } + + status = QLA_SUCCESS; + ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->TSID); + ddb_entry->task_mgmt_timeout = + le16_to_cpu(fw_ddb_entry->taskMngmntTimeout); + ddb_entry->CmdSn = 0; + ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exeThrottle); + ddb_entry->default_relogin_timeout = + le16_to_cpu(fw_ddb_entry->taskMngmntTimeout); + ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->minTime2Wait); + + /* Update index in case it changed */ + ddb_entry->fw_ddb_index = fw_ddb_index; + ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + + ddb_entry->port = le16_to_cpu(fw_ddb_entry->portNumber); + ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->TargetPortalGroup); + memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsiName[0], + min(sizeof(ddb_entry->iscsi_name), + sizeof(fw_ddb_entry->iscsiName))); + memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ipAddr[0], + min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ipAddr))); + + DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", + ha->host_no, __func__, fw_ddb_index, + ddb_entry->fw_ddb_device_state, status)); + + exit_update_ddb: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); + + return status; +} + +/** + * qla4xxx_alloc_ddb - allocate device database entry + * @ha: Pointer to host adapter structure. + * @fw_ddb_index: Firmware's device database index + * + * This routine allocates a ddb_entry, ititializes some values, and + * inserts it into the ddb list. + **/ +struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + uint32_t fw_ddb_index) +{ + struct ddb_entry *ddb_entry; + + DEBUG2(printk("scsi%ld: %s: fw_ddb_index [%d]\n", ha->host_no, + __func__, fw_ddb_index)); + + ddb_entry = qla4xxx_alloc_sess(ha); + if (ddb_entry == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " + "to add fw_ddb_index [%d]\n", + ha->host_no, __func__, fw_ddb_index)); + return ddb_entry; + } + + ddb_entry->fw_ddb_index = fw_ddb_index; + atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count); + atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->relogin_retry_count, 0); + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + list_add_tail(&ddb_entry->list, &ha->ddb_list); + ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + ha->tot_ddbs++; + + return ddb_entry; +} + +/** + * qla4xxx_configure_ddbs - builds driver ddb list + * @ha: Pointer to host adapter structure. + * + * This routine searches for all valid firmware ddb entries and builds + * an internal ddb list. Ddbs that are considered valid are those with + * a device state of SESSION_ACTIVE. + **/ +static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) +{ + int status = QLA_SUCCESS; + uint32_t fw_ddb_index = 0; + uint32_t next_fw_ddb_index = 0; + uint32_t ddb_state; + uint32_t conn_err, err_code; + struct ddb_entry *ddb_entry; + + dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); + for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; + fw_ddb_index = next_fw_ddb_index) { + /* First, let's see if a device exists here */ + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, + &next_fw_ddb_index, &ddb_state, + &conn_err, NULL, NULL) == + QLA_ERROR) { + DEBUG2(printk("scsi%ld: %s: get_ddb_entry, " + "fw_ddb_index %d failed", ha->host_no, + __func__, fw_ddb_index)); + return QLA_ERROR; + } + + DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, " + "next_fw_ddb_index=%d.\n", ha->host_no, __func__, + fw_ddb_index, ddb_state, next_fw_ddb_index)); + + /* Issue relogin, if necessary. */ + if (ddb_state == DDB_DS_SESSION_FAILED || + ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) { + /* Try and login to device */ + DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n", + ha->host_no, __func__, fw_ddb_index)); + err_code = ((conn_err & 0x00ff0000) >> 16); + if (err_code == 0x1c || err_code == 0x06) { + DEBUG2(printk("scsi%ld: %s send target " + "completed " + "or access denied failure\n", + ha->host_no, __func__)); + } else + qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0); + } + + if (ddb_state != DDB_DS_SESSION_ACTIVE) + goto next_one; + /* + * if fw_ddb with session active state found, + * add to ddb_list + */ + DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n", + ha->host_no, __func__, fw_ddb_index)); + + /* Add DDB to internal our ddb list. */ + ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index); + if (ddb_entry == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " + "for device at fw_ddb_index %d\n", + ha->host_no, __func__, fw_ddb_index)); + return QLA_ERROR; + } + /* Fill in the device structure */ + if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == + QLA_ERROR) { + ha->fw_ddb_index_map[fw_ddb_index] = + (struct ddb_entry *)INVALID_ENTRY; + + + DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed " + "for fw_ddb_index %d.\n", + ha->host_no, __func__, fw_ddb_index)); + return QLA_ERROR; + } + +next_one: + /* We know we've reached the last device when + * next_fw_ddb_index is 0 */ + if (next_fw_ddb_index == 0) + break; + } + + dev_info(&ha->pdev->dev, "DDB list done..\n"); + + return status; +} + +struct qla4_relog_scan { + int halt_wait; + uint32_t conn_err; + uint32_t err_code; + uint32_t fw_ddb_index; + uint32_t next_fw_ddb_index; + uint32_t fw_ddb_device_state; +}; + +static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs) +{ + struct ddb_entry *ddb_entry; + + /* + * Don't want to do a relogin if connection + * error is 0x1c. + */ + rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16); + if (rs->err_code == 0x1c || rs->err_code == 0x06) { + DEBUG2(printk( + "scsi%ld: %s send target" + " completed or " + "access denied failure\n", + ha->host_no, __func__)); + } else { + /* We either have a device that is in + * the process of relogging in or a + * device that is waiting to be + * relogged in */ + rs->halt_wait = 0; + + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, + rs->fw_ddb_index); + if (ddb_entry == NULL) + return QLA_ERROR; + + if (ddb_entry->dev_scan_wait_to_start_relogin != 0 + && time_after_eq(jiffies, + ddb_entry-> + dev_scan_wait_to_start_relogin)) + { + ddb_entry->dev_scan_wait_to_start_relogin = 0; + qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0); + } + } + return QLA_SUCCESS; +} + +static int qla4_scan_for_relogin(struct scsi_qla_host *ha, + struct qla4_relog_scan *rs) +{ + int error; + + /* scan for relogins + * ----------------- */ + for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES; + rs->fw_ddb_index = rs->next_fw_ddb_index) { + if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0, + NULL, &rs->next_fw_ddb_index, + &rs->fw_ddb_device_state, + &rs->conn_err, NULL, NULL) + == QLA_ERROR) + return QLA_ERROR; + + if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS) + rs->halt_wait = 0; + + if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED || + rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) { + error = qla4_test_rdy(ha, rs); + if (error) + return error; + } + + /* We know we've reached the last device when + * next_fw_ddb_index is 0 */ + if (rs->next_fw_ddb_index == 0) + break; + } + return QLA_SUCCESS; +} + +/** + * qla4xxx_devices_ready - wait for target devices to be logged in + * @ha: pointer to adapter structure + * + * This routine waits up to ql4xdiscoverywait seconds + * F/W database during driver load time. + **/ +static int qla4xxx_devices_ready(struct scsi_qla_host *ha) +{ + int error; + unsigned long discovery_wtime; + struct qla4_relog_scan rs; + + discovery_wtime = jiffies + (ql4xdiscoverywait * HZ); + + DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait)); + do { + /* poll for AEN. */ + qla4xxx_get_firmware_state(ha); + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) { + /* Set time-between-relogin timer */ + qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS); + } + + /* if no relogins active or needed, halt discvery wait */ + rs.halt_wait = 1; + + error = qla4_scan_for_relogin(ha, &rs); + + if (rs.halt_wait) { + DEBUG2(printk("scsi%ld: %s: Delay halted. Devices " + "Ready.\n", ha->host_no, __func__)); + return QLA_SUCCESS; + } + + msleep(2000); + } while (!time_after_eq(jiffies, discovery_wtime)); + + DEBUG3(qla4xxx_get_conn_event_log(ha)); + + return QLA_SUCCESS; +} + +static void qla4xxx_flush_AENS(struct scsi_qla_host *ha) +{ + unsigned long wtime; + + /* Flush the 0x8014 AEN from the firmware as a result of + * Auto connect. We are basically doing get_firmware_ddb() + * to determine whether we need to log back in or not. + * Trying to do a set ddb before we have processed 0x8014 + * will result in another set_ddb() for the same ddb. In other + * words there will be stale entries in the aen_q. + */ + wtime = jiffies + (2 * HZ); + do { + if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) + if (ha->firmware_state & (BIT_2 | BIT_0)) + return; + + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + + msleep(1000); + } while (!time_after_eq(jiffies, wtime)); + +} + +static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) +{ + uint16_t fw_ddb_index; + int status = QLA_SUCCESS; + + /* free the ddb list if is not empty */ + if (!list_empty(&ha->ddb_list)) + qla4xxx_free_ddb_list(ha); + + for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) + ha->fw_ddb_index_map[fw_ddb_index] = + (struct ddb_entry *)INVALID_ENTRY; + + ha->tot_ddbs = 0; + + qla4xxx_flush_AENS(ha); + + /* + * First perform device discovery for active + * fw ddb indexes and build + * ddb list. + */ + if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) + return status; + + /* Wait for an AEN */ + qla4xxx_devices_ready(ha); + + /* + * Targets can come online after the inital discovery, so processing + * the aens here will catch them. + */ + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) + qla4xxx_process_aen(ha, PROCESS_ALL_AENS); + + return status; +} + +/** + * qla4xxx_update_ddb_list - update the driver ddb list + * @ha: pointer to host adapter structure. + * + * This routine obtains device information from the F/W database after + * firmware or adapter resets. The device table is preserved. + **/ +int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha) +{ + int status = QLA_SUCCESS; + struct ddb_entry *ddb_entry, *detemp; + + /* Update the device information for all devices. */ + list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) { + qla4xxx_update_ddb_entry(ha, ddb_entry, + ddb_entry->fw_ddb_index); + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked " + "ONLINE\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + } + return status; +} + +/** + * qla4xxx_relogin_device - re-establish session + * @ha: Pointer to host adapter structure. + * @ddb_entry: Pointer to device database entry + * + * This routine does a session relogin with the specified device. + * The ddb entry must be assigned prior to making this call. + **/ +int qla4xxx_relogin_device(struct scsi_qla_host *ha, + struct ddb_entry * ddb_entry) +{ + uint16_t relogin_timer; + + relogin_timer = max(ddb_entry->default_relogin_timeout, + (uint16_t)RELOGIN_TOV); + atomic_set(&ddb_entry->relogin_timer, relogin_timer); + + DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, + ddb_entry->fw_ddb_index, relogin_timer)); + + qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0); + + return QLA_SUCCESS; +} + +/** + * qla4010_get_topcat_presence - check if it is QLA4040 TopCat Chip + * @ha: Pointer to host adapter structure. + * + **/ +static int qla4010_get_topcat_presence(struct scsi_qla_host *ha) +{ + unsigned long flags; + uint16_t topcat; + + if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) + return QLA_ERROR; + spin_lock_irqsave(&ha->hardware_lock, flags); + topcat = rd_nvram_word(ha, offsetof(struct eeprom_data, + isp4010.topcat)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if ((topcat & TOPCAT_MASK) == TOPCAT_PRESENT) + set_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags); + else + clear_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags); + ql4xxx_unlock_nvram(ha); + return QLA_SUCCESS; +} + + +static int qla4xxx_config_nvram(struct scsi_qla_host *ha) +{ + unsigned long flags; + union external_hw_config_reg extHwConfig; + + DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no, + __func__)); + if (ql4xxx_lock_flash(ha) != QLA_SUCCESS) + return (QLA_ERROR); + if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) { + ql4xxx_unlock_flash(ha); + return (QLA_ERROR); + } + + /* Get EEPRom Parameters from NVRAM and validate */ + dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n"); + if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) { + spin_lock_irqsave(&ha->hardware_lock, flags); + extHwConfig.Asuint32_t = + rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } else { + /* + * QLogic adapters should always have a valid NVRAM. + * If not valid, do not load. + */ + dev_warn(&ha->pdev->dev, + "scsi%ld: %s: EEProm checksum invalid. " + "Please update your EEPROM\n", ha->host_no, + __func__); + + /* set defaults */ + if (is_qla4010(ha)) + extHwConfig.Asuint32_t = 0x1912; + else if (is_qla4022(ha)) + extHwConfig.Asuint32_t = 0x0023; + } + DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n", + ha->host_no, __func__, extHwConfig.Asuint32_t)); + + spin_lock_irqsave(&ha->hardware_lock, flags); + writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha)); + readl(isp_ext_hw_conf(ha)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + ql4xxx_unlock_nvram(ha); + ql4xxx_unlock_flash(ha); + + return (QLA_SUCCESS); +} + +static void qla4x00_pci_config(struct scsi_qla_host *ha) +{ + uint16_t w, mwi; + + dev_info(&ha->pdev->dev, "Configuring PCI space...\n"); + + pci_set_master(ha->pdev); + mwi = 0; + if (pci_set_mwi(ha->pdev)) + mwi = PCI_COMMAND_INVALIDATE; + /* + * We want to respect framework's setting of PCI configuration space + * command register and also want to make sure that all bits of + * interest to us are properly set in command register. + */ + pci_read_config_word(ha->pdev, PCI_COMMAND, &w); + w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + w &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(ha->pdev, PCI_COMMAND, w); +} + +static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) +{ + int status = QLA_ERROR; + uint32_t max_wait_time; + unsigned long flags; + uint32_t mbox_status; + + dev_info(&ha->pdev->dev, "Starting firmware ...\n"); + + /* + * Start firmware from flash ROM + * + * WORKAROUND: Stuff a non-constant value that the firmware can + * use as a seed for a random number generator in MB7 prior to + * setting BOOT_ENABLE. Fixes problem where the TCP + * connections use the same TCP ports after each reboot, + * causing some connections to not get re-established. + */ + DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n", + ha->host_no, __func__)); + + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(jiffies, &ha->reg->mailbox[7]); + if (is_qla4022(ha)) + writel(set_rmask(NVR_WRITE_ENABLE), + &ha->reg->u1.isp4022.nvram); + + writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* Wait for firmware to come UP. */ + max_wait_time = FIRMWARE_UP_TOV * 4; + do { + uint32_t ctrl_status; + + spin_lock_irqsave(&ha->hardware_lock, flags); + ctrl_status = readw(&ha->reg->ctrl_status); + mbox_status = readw(&ha->reg->mailbox[0]); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR)) + break; + if (mbox_status == MBOX_STS_COMMAND_COMPLETE) + break; + + DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to " + "complete... ctrl_sts=0x%x, remaining=%d\n", + ha->host_no, __func__, ctrl_status, + max_wait_time)); + + msleep(250); + } while ((max_wait_time--)); + + if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { + DEBUG(printk("scsi%ld: %s: Firmware has started\n", + ha->host_no, __func__)); + + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + status = QLA_SUCCESS; + } else { + printk(KERN_INFO "scsi%ld: %s: Boot firmware failed " + "- mbox status 0x%x\n", ha->host_no, __func__, + mbox_status); + status = QLA_ERROR; + } + return status; +} + +static int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) +{ +#define QL4_LOCK_DRVR_WAIT 300 +#define QL4_LOCK_DRVR_SLEEP 100 + + int drvr_wait = QL4_LOCK_DRVR_WAIT; + while (drvr_wait) { + if (ql4xxx_lock_drvr(a) == 0) { + msleep(QL4_LOCK_DRVR_SLEEP); + if (drvr_wait) { + DEBUG2(printk("scsi%ld: %s: Waiting for " + "Global Init Semaphore...n", + a->host_no, + __func__)); + } + drvr_wait -= QL4_LOCK_DRVR_SLEEP; + } else { + DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " + "acquired.n", a->host_no, __func__)); + return QLA_SUCCESS; + } + } + return QLA_ERROR; +} + +/** + * qla4xxx_start_firmware - starts qla4xxx firmware + * @ha: Pointer to host adapter structure. + * + * This routine performs the neccessary steps to start the firmware for + * the QLA4010 adapter. + **/ +static int qla4xxx_start_firmware(struct scsi_qla_host *ha) +{ + unsigned long flags = 0; + uint32_t mbox_status; + int status = QLA_ERROR; + int soft_reset = 1; + int config_chip = 0; + + if (is_qla4010(ha)){ + if (qla4010_get_topcat_presence(ha) != QLA_SUCCESS) + return QLA_ERROR; + } + + if (is_qla4022(ha)) + ql4xxx_set_mac_number(ha); + + if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) + return QLA_ERROR; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no, + __func__, readw(isp_port_ctrl(ha)))); + DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no, + __func__, readw(isp_port_status(ha)))); + + /* Is Hardware already initialized? */ + if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) { + DEBUG(printk("scsi%ld: %s: Hardware has already been " + "initialized\n", ha->host_no, __func__)); + + /* Receive firmware boot acknowledgement */ + mbox_status = readw(&ha->reg->mailbox[0]); + + DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= " + "0x%x\n", ha->host_no, __func__, mbox_status)); + + /* Is firmware already booted? */ + if (mbox_status == 0) { + /* F/W not running, must be config by net driver */ + config_chip = 1; + soft_reset = 0; + } else { + writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: Get firmware " + "state -- state = 0x%x\n", + ha->host_no, + __func__, ha->firmware_state)); + /* F/W is running */ + if (ha->firmware_state & + FW_STATE_CONFIG_WAIT) { + DEBUG2(printk("scsi%ld: %s: Firmware " + "in known state -- " + "config and " + "boot, state = 0x%x\n", + ha->host_no, __func__, + ha->firmware_state)); + config_chip = 1; + soft_reset = 0; + } + } else { + DEBUG2(printk("scsi%ld: %s: Firmware in " + "unknown state -- resetting," + " state = " + "0x%x\n", ha->host_no, __func__, + ha->firmware_state)); + } + spin_lock_irqsave(&ha->hardware_lock, flags); + } + } else { + DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been " + "started - resetting\n", ha->host_no, __func__)); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ", + ha->host_no, __func__, soft_reset, config_chip)); + if (soft_reset) { + DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no, + __func__)); + status = qla4xxx_soft_reset(ha); + if (status == QLA_ERROR) { + DEBUG(printk("scsi%d: %s: Soft Reset failed!\n", + ha->host_no, __func__)); + ql4xxx_unlock_drvr(ha); + return QLA_ERROR; + } + config_chip = 1; + + /* Reset clears the semaphore, so aquire again */ + if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) + return QLA_ERROR; + } + + if (config_chip) { + if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS) + status = qla4xxx_start_firmware_from_flash(ha); + } + + ql4xxx_unlock_drvr(ha); + if (status == QLA_SUCCESS) { + qla4xxx_get_fw_version(ha); + if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags)) + qla4xxx_get_crash_record(ha); + } else { + DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n", + ha->host_no, __func__)); + } + return status; +} + + +/** + * qla4xxx_initialize_adapter - initiailizes hba + * @ha: Pointer to host adapter structure. + * @renew_ddb_list: Indicates what to do with the adapter's ddb list + * after adapter recovery has completed. + * 0=preserve ddb list, 1=destroy and rebuild ddb list + * + * This routine parforms all of the steps necessary to initialize the adapter. + * + **/ +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, + uint8_t renew_ddb_list) +{ + int status = QLA_ERROR; + int8_t ip_address[IP_ADDR_LEN] = {0} ; + + ha->eeprom_cmd_data = 0; + + qla4x00_pci_config(ha); + + qla4xxx_disable_intrs(ha); + + /* Initialize the Host adapter request/response queues and firmware */ + if (qla4xxx_start_firmware(ha) == QLA_ERROR) + return status; + + if (qla4xxx_validate_mac_address(ha) == QLA_ERROR) + return status; + + if (qla4xxx_init_local_data(ha) == QLA_ERROR) + return status; + + status = qla4xxx_init_firmware(ha); + if (status == QLA_ERROR) + return status; + + /* + * FW is waiting to get an IP address from DHCP server: Skip building + * the ddb_list and wait for DHCP lease acquired aen to come in + * followed by 0x8014 aen" to trigger the tgt discovery process. + */ + if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) + return status; + + /* Skip device discovery if ip and subnet is zero */ + if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 || + memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0) + return status; + + if (renew_ddb_list == PRESERVE_DDB_LIST) { + /* + * We want to preserve lun states (i.e. suspended, etc.) + * for recovery initiated by the driver. So just update + * the device states for the existing ddb_list. + */ + qla4xxx_reinitialize_ddb_list(ha); + } else if (renew_ddb_list == REBUILD_DDB_LIST) { + /* + * We want to build the ddb_list from scratch during + * driver initialization and recovery initiated by the + * INT_HBA_RESET IOCTL. + */ + status = qla4xxx_initialize_ddb_list(ha); + if (status == QLA_ERROR) { + DEBUG2(printk("%s(%ld) Error occurred during build" + "ddb list\n", __func__, ha->host_no)); + goto exit_init_hba; + } + + } + if (!ha->tot_ddbs) { + DEBUG2(printk("scsi%ld: Failed to initialize devices or none " + "present in Firmware device database\n", + ha->host_no)); + } + + exit_init_hba: + return status; + +} + +/** + * qla4xxx_add_device_dynamically - ddb addition due to an AEN + * @ha: Pointer to host adapter structure. + * @fw_ddb_index: Firmware's device database index + * + * This routine processes adds a device as a result of an 8014h AEN. + **/ +static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, + uint32_t fw_ddb_index) +{ + struct ddb_entry * ddb_entry; + + /* First allocate a device structure */ + ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index); + if (ddb_entry == NULL) { + DEBUG2(printk(KERN_WARNING + "scsi%ld: Unable to allocate memory to add " + "fw_ddb_index %d\n", ha->host_no, fw_ddb_index)); + return; + } + + if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == + QLA_ERROR) { + ha->fw_ddb_index_map[fw_ddb_index] = + (struct ddb_entry *)INVALID_ENTRY; + DEBUG2(printk(KERN_WARNING + "scsi%ld: failed to add new device at index " + "[%d]\n Unable to retrieve fw ddb entry\n", + ha->host_no, fw_ddb_index)); + qla4xxx_free_ddb(ha, ddb_entry); + return; + } + + if (qla4xxx_add_sess(ddb_entry)) { + DEBUG2(printk(KERN_WARNING + "scsi%ld: failed to add new device at index " + "[%d]\n Unable to add connection and session\n", + ha->host_no, fw_ddb_index)); + qla4xxx_free_ddb(ha, ddb_entry); + } +} + +/** + * qla4xxx_process_ddb_changed - process ddb state change + * @ha - Pointer to host adapter structure. + * @fw_ddb_index - Firmware's device database index + * @state - Device state + * + * This routine processes a Decive Database Changed AEN Event. + **/ +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + uint32_t fw_ddb_index, uint32_t state) +{ + struct ddb_entry * ddb_entry; + uint32_t old_fw_ddb_device_state; + + /* check for out of range index */ + if (fw_ddb_index >= MAX_DDB_ENTRIES) + return QLA_ERROR; + + /* Get the corresponging ddb entry */ + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); + /* Device does not currently exist in our database. */ + if (ddb_entry == NULL) { + if (state == DDB_DS_SESSION_ACTIVE) + qla4xxx_add_device_dynamically(ha, fw_ddb_index); + return QLA_SUCCESS; + } + + /* Device already exists in our database. */ + old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; + DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for " + "index [%d]\n", ha->host_no, __func__, + ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); + if (old_fw_ddb_device_state == state && + state == DDB_DS_SESSION_ACTIVE) { + /* Do nothing, state not changed. */ + return QLA_SUCCESS; + } + + ddb_entry->fw_ddb_device_state = state; + /* Device is back online. */ + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->port_down_timer, + ha->port_down_retry_count); + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + atomic_set(&ddb_entry->relogin_retry_count, 0); + atomic_set(&ddb_entry->relogin_timer, 0); + clear_bit(DF_RELOGIN, &ddb_entry->flags); + clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); + iscsi_if_create_session_done(ddb_entry->conn); + /* + * Change the lun state to READY in case the lun TIMEOUT before + * the device came back. + */ + } else { + /* Device went away, try to relogin. */ + /* Mark device missing */ + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + /* + * Relogin if device state changed to a not active state. + * However, do not relogin if this aen is a result of an IOCTL + * logout (DF_NO_RELOGIN) or if this is a discovered device. + */ + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && + !test_bit(DF_RELOGIN, &ddb_entry->flags) && + !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && + !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) { + /* + * This triggers a relogin. After the relogin_timer + * expires, the relogin gets scheduled. We must wait a + * minimum amount of time since receiving an 0x8014 AEN + * with failed device_state or a logout response before + * we can issue another relogin. + */ + /* Firmware padds this timeout: (time2wait +1). + * Driver retry to login should be longer than F/W. + * Otherwise F/W will fail + * set_ddb() mbx cmd with 0x4005 since it still + * counting down its time2wait. + */ + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + } + } + + return QLA_SUCCESS; +} + diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h new file mode 100644 index 00000000000..0d61797af7d --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_inline.h @@ -0,0 +1,84 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +/* + * + * qla4xxx_lookup_ddb_by_fw_index + * This routine locates a device handle given the firmware device + * database index. If device doesn't exist, returns NULL. + * + * Input: + * ha - Pointer to host adapter structure. + * fw_ddb_index - Firmware's device database index + * + * Returns: + * Pointer to the corresponding internal device database structure + */ +static inline struct ddb_entry * +qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index) +{ + struct ddb_entry *ddb_entry = NULL; + + if ((fw_ddb_index < MAX_DDB_ENTRIES) && + (ha->fw_ddb_index_map[fw_ddb_index] != + (struct ddb_entry *) INVALID_ENTRY)) { + ddb_entry = ha->fw_ddb_index_map[fw_ddb_index]; + } + + DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n", + ha->host_no, __func__, fw_ddb_index, ddb_entry)); + + return ddb_entry; +} + +static inline void +__qla4xxx_enable_intrs(struct scsi_qla_host *ha) +{ + if (is_qla4022(ha)) { + writel(set_rmask(IMR_SCSI_INTR_ENABLE), + &ha->reg->u1.isp4022.intr_mask); + readl(&ha->reg->u1.isp4022.intr_mask); + } else { + writel(set_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } + set_bit(AF_INTERRUPTS_ON, &ha->flags); +} + +static inline void +__qla4xxx_disable_intrs(struct scsi_qla_host *ha) +{ + if (is_qla4022(ha)) { + writel(clr_rmask(IMR_SCSI_INTR_ENABLE), + &ha->reg->u1.isp4022.intr_mask); + readl(&ha->reg->u1.isp4022.intr_mask); + } else { + writel(clr_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } + clear_bit(AF_INTERRUPTS_ON, &ha->flags); +} + +static inline void +qla4xxx_enable_intrs(struct scsi_qla_host *ha) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + __qla4xxx_enable_intrs(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +static inline void +qla4xxx_disable_intrs(struct scsi_qla_host *ha) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + __qla4xxx_disable_intrs(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c new file mode 100644 index 00000000000..c0a254b89a3 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -0,0 +1,368 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#include "ql4_def.h" + +#include + +/** + * qla4xxx_get_req_pkt - returns a valid entry in request queue. + * @ha: Pointer to host adapter structure. + * @queue_entry: Pointer to pointer to queue entry structure + * + * This routine performs the following tasks: + * - returns the current request_in pointer (if queue not full) + * - advances the request_in pointer + * - checks for queue full + **/ +int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, + struct queue_entry **queue_entry) +{ + uint16_t request_in; + uint8_t status = QLA_SUCCESS; + + *queue_entry = ha->request_ptr; + + /* get the latest request_in and request_out index */ + request_in = ha->request_in; + ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); + + /* Advance request queue pointer and check for queue full */ + if (request_in == (REQUEST_QUEUE_DEPTH - 1)) { + request_in = 0; + ha->request_ptr = ha->request_ring; + } else { + request_in++; + ha->request_ptr++; + } + + /* request queue is full, try again later */ + if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) { + /* restore request pointer */ + ha->request_ptr = *queue_entry; + status = QLA_ERROR; + } else { + ha->request_in = request_in; + memset(*queue_entry, 0, sizeof(**queue_entry)); + } + + return status; +} + +/** + * qla4xxx_send_marker_iocb - issues marker iocb to HBA + * @ha: Pointer to host adapter structure. + * @ddb_entry: Pointer to device database entry + * @lun: SCSI LUN + * @marker_type: marker identifier + * + * This routine issues a marker IOCB. + **/ +int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, int lun) +{ + struct marker_entry *marker_entry; + unsigned long flags = 0; + uint8_t status = QLA_SUCCESS; + + /* Acquire hardware specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Get pointer to the queue entry for the marker */ + if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) != + QLA_SUCCESS) { + status = QLA_ERROR; + goto exit_send_marker; + } + + /* Put the marker in the request queue */ + marker_entry->hdr.entryType = ET_MARKER; + marker_entry->hdr.entryCount = 1; + marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); + marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); + int_to_scsilun(lun, &marker_entry->lun); + wmb(); + + /* Tell ISP it's got a new I/O request */ + writel(ha->request_in, &ha->reg->req_q_in); + readl(&ha->reg->req_q_in); + +exit_send_marker: + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return status; +} + +struct continuation_t1_entry* qla4xxx_alloc_cont_entry( + struct scsi_qla_host *ha) +{ + struct continuation_t1_entry *cont_entry; + + cont_entry = (struct continuation_t1_entry *)ha->request_ptr; + + /* Advance request queue pointer */ + if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) { + ha->request_in = 0; + ha->request_ptr = ha->request_ring; + } else { + ha->request_in++; + ha->request_ptr++; + } + + /* Load packet defaults */ + cont_entry->hdr.entryType = ET_CONTINUE; + cont_entry->hdr.entryCount = 1; + cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in); + + return cont_entry; +} + +uint16_t qla4xxx_calc_request_entries(uint16_t dsds) +{ + uint16_t iocbs; + + iocbs = 1; + if (dsds > COMMAND_SEG) { + iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG; + if ((dsds - COMMAND_SEG) % CONTINUE_SEG) + iocbs++; + } + return iocbs; +} + +void qla4xxx_build_scsi_iocbs(struct srb *srb, + struct command_t3_entry *cmd_entry, + uint16_t tot_dsds) +{ + struct scsi_qla_host *ha; + uint16_t avail_dsds; + struct data_seg_a64 *cur_dsd; + struct scsi_cmnd *cmd; + + cmd = srb->cmd; + ha = srb->ha; + + if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { + /* No data being transferred */ + cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0); + return; + } + + avail_dsds = COMMAND_SEG; + cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); + + /* Load data segments */ + if (cmd->use_sg) { + struct scatterlist *cur_seg; + struct scatterlist *end_seg; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + end_seg = cur_seg + tot_dsds; + while (cur_seg < end_seg) { + dma_addr_t sle_dma; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + struct continuation_t1_entry *cont_entry; + + cont_entry = qla4xxx_alloc_cont_entry(ha); + cur_dsd = + (struct data_seg_a64 *) + &cont_entry->dataseg[0]; + avail_dsds = CONTINUE_SEG; + } + + sle_dma = sg_dma_address(cur_seg); + cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma)); + cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma)); + cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg)); + avail_dsds--; + + cur_dsd++; + cur_seg++; + } + } else { + cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle)); + cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle)); + cur_dsd->count = cpu_to_le32(cmd->request_bufflen); + } +} + +/** + * qla4xxx_send_command_to_isp - issues command to HBA + * @ha: pointer to host adapter structure. + * @srb: pointer to SCSI Request Block to be sent to ISP + * + * This routine is called by qla4xxx_queuecommand to build an ISP + * command and pass it to the ISP for execution. + **/ +int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) +{ + struct scsi_cmnd *cmd = srb->cmd; + struct ddb_entry *ddb_entry; + struct command_t3_entry *cmd_entry; + struct scatterlist *sg = NULL; + + uint16_t tot_dsds; + uint16_t req_cnt; + + unsigned long flags; + uint16_t cnt; + uint32_t index; + char tag[2]; + + /* Get real lun and adapter */ + ddb_entry = srb->ddb; + + /* Send marker(s) if needed. */ + if (ha->marker_needed == 1) { + if (qla4xxx_send_marker_iocb(ha, ddb_entry, + cmd->device->lun) != QLA_SUCCESS) + return QLA_ERROR; + + ha->marker_needed = 0; + } + tot_dsds = 0; + + /* Acquire hardware specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + + index = (uint32_t)cmd->request->tag; + + /* Calculate the number of request entries needed. */ + if (cmd->use_sg) { + sg = (struct scatterlist *)cmd->request_buffer; + tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg, + cmd->sc_data_direction); + if (tot_dsds == 0) + goto queuing_error; + } else if (cmd->request_bufflen) { + dma_addr_t req_dma; + + req_dma = pci_map_single(ha->pdev, cmd->request_buffer, + cmd->request_bufflen, + cmd->sc_data_direction); + if (dma_mapping_error(req_dma)) + goto queuing_error; + + srb->dma_handle = req_dma; + tot_dsds = 1; + } + req_cnt = qla4xxx_calc_request_entries(tot_dsds); + + if (ha->req_q_count < (req_cnt + 2)) { + cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); + if (ha->request_in < cnt) + ha->req_q_count = cnt - ha->request_in; + else + ha->req_q_count = REQUEST_QUEUE_DEPTH - + (ha->request_in - cnt); + } + + if (ha->req_q_count < (req_cnt + 2)) + goto queuing_error; + + /* total iocbs active */ + if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH) + goto queuing_error; + + /* Build command packet */ + cmd_entry = (struct command_t3_entry *) ha->request_ptr; + memset(cmd_entry, 0, sizeof(struct command_t3_entry)); + cmd_entry->hdr.entryType = ET_COMMAND; + cmd_entry->handle = cpu_to_le32(index); + cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); + cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id); + + int_to_scsilun(cmd->device->lun, &cmd_entry->lun); + cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn); + cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen); + memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len); + cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds); + cmd_entry->hdr.entryCount = req_cnt; + + /* Set data transfer direction control flags + * NOTE: Look at data_direction bits iff there is data to be + * transferred, as the data direction bit is sometimed filled + * in when there is no data to be transferred */ + cmd_entry->control_flags = CF_NO_DATA; + if (cmd->request_bufflen) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) + cmd_entry->control_flags = CF_WRITE; + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + cmd_entry->control_flags = CF_READ; + } + + /* Set tagged queueing control flags */ + cmd_entry->control_flags |= CF_SIMPLE_TAG; + if (scsi_populate_tag_msg(cmd, tag)) + switch (tag[0]) { + case MSG_HEAD_TAG: + cmd_entry->control_flags |= CF_HEAD_TAG; + break; + case MSG_ORDERED_TAG: + cmd_entry->control_flags |= CF_ORDERED_TAG; + break; + } + + + /* Advance request queue pointer */ + ha->request_in++; + if (ha->request_in == REQUEST_QUEUE_DEPTH) { + ha->request_in = 0; + ha->request_ptr = ha->request_ring; + } else + ha->request_ptr++; + + + qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds); + wmb(); + + /* + * Check to see if adapter is online before placing request on + * request queue. If a reset occurs and a request is in the queue, + * the firmware will still attempt to process the request, retrieving + * garbage for pointers. + */ + if (!test_bit(AF_ONLINE, &ha->flags)) { + DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! " + "Do not issue command.\n", + ha->host_no, __func__)); + goto queuing_error; + } + + srb->cmd->host_scribble = (unsigned char *)srb; + + /* update counters */ + srb->state = SRB_ACTIVE_STATE; + srb->flags |= SRB_DMA_VALID; + + /* Track IOCB used */ + ha->iocb_cnt += req_cnt; + srb->iocb_cnt = req_cnt; + ha->req_q_count -= req_cnt; + + /* Debug print statements */ + writel(ha->request_in, &ha->reg->req_q_in); + readl(&ha->reg->req_q_in); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_SUCCESS; + +queuing_error: + + if (cmd->use_sg && tot_dsds) { + sg = (struct scatterlist *) cmd->request_buffer; + pci_unmap_sg(ha->pdev, sg, cmd->use_sg, + cmd->sc_data_direction); + } else if (tot_dsds) + pci_unmap_single(ha->pdev, srb->dma_handle, + cmd->request_bufflen, cmd->sc_data_direction); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_ERROR; +} + diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c new file mode 100644 index 00000000000..b584317608d --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -0,0 +1,797 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#include "ql4_def.h" + +/** + * qla2x00_process_completed_request() - Process a Fast Post response. + * @ha: SCSI driver HA context + * @index: SRB index + **/ +static void qla4xxx_process_completed_request(struct scsi_qla_host *ha, + uint32_t index) +{ + struct srb *srb; + + srb = qla4xxx_del_from_active_array(ha, index); + if (srb) { + /* Save ISP completion status */ + srb->cmd->result = DID_OK << 16; + qla4xxx_srb_compl(ha, srb); + } else { + DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = " + "%d\n", ha->host_no, index)); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } +} + +/** + * qla4xxx_status_entry - processes status IOCBs + * @ha: Pointer to host adapter structure. + * @sts_entry: Pointer to status entry structure. + **/ +static void qla4xxx_status_entry(struct scsi_qla_host *ha, + struct status_entry *sts_entry) +{ + uint8_t scsi_status; + struct scsi_cmnd *cmd; + struct srb *srb; + struct ddb_entry *ddb_entry; + uint32_t residual; + uint16_t sensebytecnt; + + if (sts_entry->completionStatus == SCS_COMPLETE && + sts_entry->scsiStatus == 0) { + qla4xxx_process_completed_request(ha, + le32_to_cpu(sts_entry-> + handle)); + return; + } + + srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); + if (!srb) { + /* FIXMEdg: Don't we need to reset ISP in this case??? */ + DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid " + "handle 0x%x, sp=%p. This cmd may have already " + "been completed.\n", ha->host_no, __func__, + le32_to_cpu(sts_entry->handle), srb)); + return; + } + + cmd = srb->cmd; + if (cmd == NULL) { + DEBUG2(printk("scsi%ld: %s: Command already returned back to " + "OS pkt->handle=%d srb=%p srb->state:%d\n", + ha->host_no, __func__, sts_entry->handle, + srb, srb->state)); + dev_warn(&ha->pdev->dev, "Command is NULL:" + " already returned to OS (srb=%p)\n", srb); + return; + } + + ddb_entry = srb->ddb; + if (ddb_entry == NULL) { + cmd->result = DID_NO_CONNECT << 16; + goto status_entry_exit; + } + + residual = le32_to_cpu(sts_entry->residualByteCnt); + + /* Translate ISP error to a Linux SCSI error. */ + scsi_status = sts_entry->scsiStatus; + switch (sts_entry->completionStatus) { + case SCS_COMPLETE: + if (scsi_status == 0) { + cmd->result = DID_OK << 16; + break; + } + + if (sts_entry->iscsiFlags & + (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER)) + cmd->resid = residual; + + cmd->result = DID_OK << 16 | scsi_status; + + if (scsi_status != SCSI_CHECK_CONDITION) + break; + + /* Copy Sense Data into sense buffer. */ + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + + sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt); + if (sensebytecnt == 0) + break; + + memcpy(cmd->sense_buffer, sts_entry->senseData, + min(sensebytecnt, + (uint16_t) sizeof(cmd->sense_buffer))); + + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " + "ASC/ASCQ = %02x/%02x\n", ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, __func__, + sts_entry->senseData[2] & 0x0f, + sts_entry->senseData[12], + sts_entry->senseData[13])); + + srb->flags |= SRB_GOT_SENSE; + break; + + case SCS_INCOMPLETE: + /* Always set the status to DID_ERROR, since + * all conditions result in that status anyway */ + cmd->result = DID_ERROR << 16; + break; + + case SCS_RESET_OCCURRED: + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n", + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun, __func__)); + + cmd->result = DID_RESET << 16; + break; + + case SCS_ABORTED: + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n", + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun, __func__)); + + cmd->result = DID_RESET << 16; + break; + + case SCS_TIMEOUT: + DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n", + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun)); + + cmd->result = DID_BUS_BUSY << 16; + + /* + * Mark device missing so that we won't continue to send + * I/O to this device. We should get a ddb state change + * AEN soon. + */ + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + break; + + case SCS_DATA_UNDERRUN: + case SCS_DATA_OVERRUN: + if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) { + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, " + "residual = 0x%x\n", ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, __func__, residual)); + + cmd->result = DID_ERROR << 16; + break; + } + + if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) { + /* + * Firmware detected a SCSI transport underrun + * condition + */ + cmd->resid = residual; + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status " + "detected, xferlen = 0x%x, residual = " + "0x%x\n", + ha->host_no, cmd->device->channel, + cmd->device->id, + cmd->device->lun, __func__, + cmd->request_bufflen, + residual)); + } + + /* + * If there is scsi_status, it takes precedense over + * underflow condition. + */ + if (scsi_status != 0) { + cmd->result = DID_OK << 16 | scsi_status; + + if (scsi_status != SCSI_CHECK_CONDITION) + break; + + /* Copy Sense Data into sense buffer. */ + memset(cmd->sense_buffer, 0, + sizeof(cmd->sense_buffer)); + + sensebytecnt = + le16_to_cpu(sts_entry->senseDataByteCnt); + if (sensebytecnt == 0) + break; + + memcpy(cmd->sense_buffer, sts_entry->senseData, + min(sensebytecnt, + (uint16_t) sizeof(cmd->sense_buffer))); + + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " + "ASC/ASCQ = %02x/%02x\n", ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, __func__, + sts_entry->senseData[2] & 0x0f, + sts_entry->senseData[12], + sts_entry->senseData[13])); + } else { + /* + * If RISC reports underrun and target does not + * report it then we must have a lost frame, so + * tell upper layer to retry it by reporting a + * bus busy. + */ + if ((sts_entry->iscsiFlags & + ISCSI_FLAG_RESIDUAL_UNDER) == 0) { + cmd->result = DID_BUS_BUSY << 16; + } else if ((cmd->request_bufflen - residual) < + cmd->underflow) { + /* + * Handle mid-layer underflow??? + * + * For kernels less than 2.4, the driver must + * return an error if an underflow is detected. + * For kernels equal-to and above 2.4, the + * mid-layer will appearantly handle the + * underflow by detecting the residual count -- + * unfortunately, we do not see where this is + * actually being done. In the interim, we + * will return DID_ERROR. + */ + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " + "Mid-layer Data underrun, " + "xferlen = 0x%x, " + "residual = 0x%x\n", ha->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, __func__, + cmd->request_bufflen, residual)); + + cmd->result = DID_ERROR << 16; + } else { + cmd->result = DID_OK << 16; + } + } + break; + + case SCS_DEVICE_LOGGED_OUT: + case SCS_DEVICE_UNAVAILABLE: + /* + * Mark device missing so that we won't continue to + * send I/O to this device. We should get a ddb + * state change AEN soon. + */ + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + + cmd->result = DID_BUS_BUSY << 16; + break; + + case SCS_QUEUE_FULL: + /* + * SCSI Mid-Layer handles device queue full + */ + cmd->result = DID_OK << 16 | sts_entry->scsiStatus; + DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected " + "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x," + " iResp=%02x\n", ha->host_no, cmd->device->id, + cmd->device->lun, __func__, + sts_entry->completionStatus, + sts_entry->scsiStatus, sts_entry->state_flags, + sts_entry->iscsiFlags, + sts_entry->iscsiResponse)); + break; + + default: + cmd->result = DID_ERROR << 16; + break; + } + +status_entry_exit: + + /* complete the request */ + srb->cc_stat = sts_entry->completionStatus; + qla4xxx_srb_compl(ha, srb); +} + +/** + * qla4xxx_process_response_queue - process response queue completions + * @ha: Pointer to host adapter structure. + * + * This routine process response queue completions in interrupt context. + * Hardware_lock locked upon entry + **/ +static void qla4xxx_process_response_queue(struct scsi_qla_host * ha) +{ + uint32_t count = 0; + struct srb *srb = NULL; + struct status_entry *sts_entry; + + /* Process all responses from response queue */ + while ((ha->response_in = + (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) != + ha->response_out) { + sts_entry = (struct status_entry *) ha->response_ptr; + count++; + + /* Advance pointers for next entry */ + if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) { + ha->response_out = 0; + ha->response_ptr = ha->response_ring; + } else { + ha->response_out++; + ha->response_ptr++; + } + + /* process entry */ + switch (sts_entry->hdr.entryType) { + case ET_STATUS: + /* + * Common status - Single completion posted in single + * IOSB. + */ + qla4xxx_status_entry(ha, sts_entry); + break; + + case ET_PASSTHRU_STATUS: + break; + + case ET_STATUS_CONTINUATION: + /* Just throw away the status continuation entries */ + DEBUG2(printk("scsi%ld: %s: Status Continuation entry " + "- ignoring\n", ha->host_no, __func__)); + break; + + case ET_COMMAND: + /* ISP device queue is full. Command not + * accepted by ISP. Queue command for + * later */ + + srb = qla4xxx_del_from_active_array(ha, + le32_to_cpu(sts_entry-> + handle)); + if (srb == NULL) + goto exit_prq_invalid_handle; + + DEBUG2(printk("scsi%ld: %s: FW device queue full, " + "srb %p\n", ha->host_no, __func__, srb)); + + /* ETRY normally by sending it back with + * DID_BUS_BUSY */ + srb->cmd->result = DID_BUS_BUSY << 16; + qla4xxx_srb_compl(ha, srb); + break; + + case ET_CONTINUE: + /* Just throw away the continuation entries */ + DEBUG2(printk("scsi%ld: %s: Continuation entry - " + "ignoring\n", ha->host_no, __func__)); + break; + + default: + /* + * Invalid entry in response queue, reset RISC + * firmware. + */ + DEBUG2(printk("scsi%ld: %s: Invalid entry %x in " + "response queue \n", ha->host_no, + __func__, + sts_entry->hdr.entryType)); + goto exit_prq_error; + } + } + + /* + * Done with responses, update the ISP For QLA4010, this also clears + * the interrupt. + */ + writel(ha->response_out, &ha->reg->rsp_q_out); + readl(&ha->reg->rsp_q_out); + + return; + +exit_prq_invalid_handle: + DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n", + ha->host_no, __func__, srb, sts_entry->hdr.entryType, + sts_entry->completionStatus)); + +exit_prq_error: + writel(ha->response_out, &ha->reg->rsp_q_out); + readl(&ha->reg->rsp_q_out); + + set_bit(DPC_RESET_HA, &ha->dpc_flags); +} + +/** + * qla4xxx_isr_decode_mailbox - decodes mailbox status + * @ha: Pointer to host adapter structure. + * @mailbox_status: Mailbox status. + * + * This routine decodes the mailbox status during the ISR. + * Hardware_lock locked upon entry. runs in interrupt context. + **/ +static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, + uint32_t mbox_status) +{ + int i; + + if ((mbox_status == MBOX_STS_BUSY) || + (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || + (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) { + ha->mbox_status[0] = mbox_status; + + if (test_bit(AF_MBOX_COMMAND, &ha->flags)) { + /* + * Copy all mailbox registers to a temporary + * location and set mailbox command done flag + */ + for (i = 1; i < ha->mbox_status_count; i++) + ha->mbox_status[i] = + readl(&ha->reg->mailbox[i]); + + set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + wake_up(&ha->mailbox_wait_queue); + } + } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { + /* Immediately process the AENs that don't require much work. + * Only queue the database_changed AENs */ + switch (mbox_status) { + case MBOX_ASTS_SYSTEM_ERROR: + /* Log Mailbox registers */ + if (ql4xdontresethba) { + DEBUG2(printk("%s:Dont Reset HBA\n", + __func__)); + } else { + set_bit(AF_GET_CRASH_RECORD, &ha->flags); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + break; + + case MBOX_ASTS_REQUEST_TRANSFER_ERROR: + case MBOX_ASTS_RESPONSE_TRANSFER_ERROR: + case MBOX_ASTS_NVRAM_INVALID: + case MBOX_ASTS_IP_ADDRESS_CHANGED: + case MBOX_ASTS_DHCP_LEASE_EXPIRED: + DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " + "Reset HA\n", ha->host_no, mbox_status)); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + break; + + case MBOX_ASTS_LINK_UP: + DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n", + ha->host_no, mbox_status)); + set_bit(AF_LINK_UP, &ha->flags); + break; + + case MBOX_ASTS_LINK_DOWN: + DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n", + ha->host_no, mbox_status)); + clear_bit(AF_LINK_UP, &ha->flags); + break; + + case MBOX_ASTS_HEARTBEAT: + ha->seconds_since_last_heartbeat = 0; + break; + + case MBOX_ASTS_DHCP_LEASE_ACQUIRED: + DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE " + "ACQUIRED\n", ha->host_no, mbox_status)); + set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); + break; + + case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM: + case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target + * mode + * only */ + case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */ + case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR: + case MBOX_ASTS_SUBNET_STATE_CHANGE: + /* No action */ + DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no, + mbox_status)); + break; + + case MBOX_ASTS_MAC_ADDRESS_CHANGED: + case MBOX_ASTS_DNS: + /* No action */ + DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, " + "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n", + ha->host_no, mbox_status, + readl(&ha->reg->mailbox[1]), + readl(&ha->reg->mailbox[2]))); + break; + + case MBOX_ASTS_SELF_TEST_FAILED: + case MBOX_ASTS_LOGIN_FAILED: + /* No action */ + DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, " + "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n", + ha->host_no, mbox_status, + readl(&ha->reg->mailbox[1]), + readl(&ha->reg->mailbox[2]), + readl(&ha->reg->mailbox[3]))); + break; + + case MBOX_ASTS_DATABASE_CHANGED: + /* Queue AEN information and process it in the DPC + * routine */ + if (ha->aen_q_count > 0) { + /* advance pointer */ + if (ha->aen_in == (MAX_AEN_ENTRIES - 1)) + ha->aen_in = 0; + else + ha->aen_in++; + + /* decrement available counter */ + ha->aen_q_count--; + + for (i = 1; i < MBOX_AEN_REG_COUNT; i++) + ha->aen_q[ha->aen_in].mbox_sts[i] = + readl(&ha->reg->mailbox[i]); + + ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status; + + /* print debug message */ + DEBUG2(printk("scsi%ld: AEN[%d] %04x queued" + " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n", + ha->host_no, ha->aen_in, + mbox_status, + ha->aen_q[ha->aen_in].mbox_sts[1], + ha->aen_q[ha->aen_in].mbox_sts[2], + ha->aen_q[ha->aen_in].mbox_sts[3], + ha->aen_q[ha->aen_in]. mbox_sts[4])); + + /* The DPC routine will process the aen */ + set_bit(DPC_AEN, &ha->dpc_flags); + } else { + DEBUG2(printk("scsi%ld: %s: aen %04x, queue " + "overflowed! AEN LOST!!\n", + ha->host_no, __func__, + mbox_status)); + + DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n", + ha->host_no)); + + for (i = 0; i < MAX_AEN_ENTRIES; i++) { + DEBUG2(printk("AEN[%d] %04x %04x %04x " + "%04x\n", i, + ha->aen_q[i].mbox_sts[0], + ha->aen_q[i].mbox_sts[1], + ha->aen_q[i].mbox_sts[2], + ha->aen_q[i].mbox_sts[3])); + } + } + break; + + default: + DEBUG2(printk(KERN_WARNING + "scsi%ld: AEN %04x UNKNOWN\n", + ha->host_no, mbox_status)); + break; + } + } else { + DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n", + ha->host_no, mbox_status)); + + ha->mbox_status[0] = mbox_status; + } +} + +/** + * qla4xxx_interrupt_service_routine - isr + * @ha: pointer to host adapter structure. + * + * This is the main interrupt service routine. + * hardware_lock locked upon entry. runs in interrupt context. + **/ +void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, + uint32_t intr_status) +{ + /* Process response queue interrupt. */ + if (intr_status & CSR_SCSI_COMPLETION_INTR) + qla4xxx_process_response_queue(ha); + + /* Process mailbox/asynch event interrupt.*/ + if (intr_status & CSR_SCSI_PROCESSOR_INTR) { + qla4xxx_isr_decode_mailbox(ha, + readl(&ha->reg->mailbox[0])); + + /* Clear Mailbox Interrupt */ + writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } +} + +/** + * 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) +{ + struct scsi_qla_host *ha; + uint32_t intr_status; + unsigned long flags = 0; + uint8_t reqs_count = 0; + + ha = (struct scsi_qla_host *) dev_id; + if (!ha) { + DEBUG2(printk(KERN_INFO + "qla4xxx: Interrupt with NULL host ptr\n")); + return IRQ_NONE; + } + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* + * Repeatedly service interrupts up to a maximum of + * MAX_REQS_SERVICED_PER_INTR + */ + while (1) { + /* + * Read interrupt status + */ + if (le32_to_cpu(ha->shadow_regs->rsp_q_in) != + ha->response_out) + intr_status = CSR_SCSI_COMPLETION_INTR; + else + intr_status = readl(&ha->reg->ctrl_status); + + if ((intr_status & + (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == + 0) { + if (reqs_count == 0) + ha->spurious_int_count++; + break; + } + + if (intr_status & CSR_FATAL_ERROR) { + DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, " + "Status 0x%04x\n", ha->host_no, + readl(isp_port_error_status (ha)))); + + /* Issue Soft Reset to clear this error condition. + * This will prevent the RISC from repeatedly + * interrupting the driver; thus, allowing the DPC to + * get scheduled to continue error recovery. + * NOTE: Disabling RISC interrupts does not work in + * this case, as CSR_FATAL_ERROR overrides + * CSR_SCSI_INTR_ENABLE */ + if ((readl(&ha->reg->ctrl_status) & + CSR_SCSI_RESET_INTR) == 0) { + writel(set_rmask(CSR_SOFT_RESET), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } + + writel(set_rmask(CSR_FATAL_ERROR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + + __qla4xxx_disable_intrs(ha); + + set_bit(DPC_RESET_HA, &ha->dpc_flags); + + break; + } else if (intr_status & CSR_SCSI_RESET_INTR) { + clear_bit(AF_ONLINE, &ha->flags); + __qla4xxx_disable_intrs(ha); + + writel(set_rmask(CSR_SCSI_RESET_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + + set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); + + break; + } else if (intr_status & INTR_PENDING) { + qla4xxx_interrupt_service_routine(ha, intr_status); + ha->total_io_count++; + if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) + break; + + intr_status = 0; + } + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return IRQ_HANDLED; +} + +/** + * qla4xxx_process_aen - processes AENs generated by firmware + * @ha: pointer to host adapter structure. + * @process_aen: type of AENs to process + * + * Processes specific types of Asynchronous Events generated by firmware. + * The type of AENs to process is specified by process_aen and can be + * PROCESS_ALL_AENS 0 + * FLUSH_DDB_CHANGED_AENS 1 + * RELOGIN_DDB_CHANGED_AENS 2 + **/ +void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) +{ + uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; + struct aen *aen; + int i; + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + while (ha->aen_out != ha->aen_in) { + /* Advance pointers for next entry */ + if (ha->aen_out == (MAX_AEN_ENTRIES - 1)) + ha->aen_out = 0; + else + ha->aen_out++; + + ha->aen_q_count++; + aen = &ha->aen_q[ha->aen_out]; + + /* copy aen information to local structure */ + for (i = 0; i < MBOX_AEN_REG_COUNT; i++) + mbox_sts[i] = aen->mbox_sts[i]; + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x " + "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out, + mbox_sts[0], mbox_sts[2], mbox_sts[3], + mbox_sts[1], mbox_sts[4])); + + switch (mbox_sts[0]) { + case MBOX_ASTS_DATABASE_CHANGED: + if (process_aen == FLUSH_DDB_CHANGED_AENS) { + DEBUG2(printk("scsi%ld: AEN[%d] %04x, index " + "[%d] state=%04x FLUSHED!\n", + ha->host_no, ha->aen_out, + mbox_sts[0], mbox_sts[2], + mbox_sts[3])); + break; + } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) { + /* for use during init time, we only want to + * relogin non-active ddbs */ + struct ddb_entry *ddb_entry; + + ddb_entry = + /* FIXME: name length? */ + qla4xxx_lookup_ddb_by_fw_index(ha, + mbox_sts[2]); + if (!ddb_entry) + break; + + ddb_entry->dev_scan_wait_to_complete_relogin = + 0; + ddb_entry->dev_scan_wait_to_start_relogin = + jiffies + + ((ddb_entry->default_time2wait + + 4) * HZ); + + DEBUG2(printk("scsi%ld: ddb index [%d] initate" + " RELOGIN after %d seconds\n", + ha->host_no, + ddb_entry->fw_ddb_index, + ddb_entry->default_time2wait + + 4)); + break; + } + + if (mbox_sts[1] == 0) { /* Global DB change. */ + qla4xxx_reinitialize_ddb_list(ha); + } else if (mbox_sts[1] == 1) { /* Specific device. */ + qla4xxx_process_ddb_changed(ha, mbox_sts[2], + mbox_sts[3]); + } + break; + } + spin_lock_irqsave(&ha->hardware_lock, flags); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + +} + diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c new file mode 100644 index 00000000000..ed977f70b2d --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -0,0 +1,930 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#include "ql4_def.h" + + +/** + * qla4xxx_mailbox_command - issues mailbox commands + * @ha: Pointer to host adapter structure. + * @inCount: number of mailbox registers to load. + * @outCount: number of mailbox registers to return. + * @mbx_cmd: data pointer for mailbox in registers. + * @mbx_sts: data pointer for mailbox out registers. + * + * This routine sssue mailbox commands and waits for completion. + * If outCount is 0, this routine completes successfully WITHOUT waiting + * for the mailbox command to complete. + **/ +int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, + uint32_t *mbx_sts) +{ + int status = QLA_ERROR; + uint8_t i; + u_long wait_count; + uint32_t intr_status; + unsigned long flags = 0; + DECLARE_WAITQUEUE(wait, current); + + mutex_lock(&ha->mbox_sem); + + /* Mailbox code active */ + set_bit(AF_MBOX_COMMAND, &ha->flags); + + /* Make sure that pointers are valid */ + if (!mbx_cmd || !mbx_sts) { + DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " + "pointer\n", ha->host_no, __func__)); + goto mbox_exit; + } + + /* To prevent overwriting mailbox registers for a command that has + * not yet been serviced, check to see if a previously issued + * mailbox command is interrupting. + * ----------------------------------------------------------------- + */ + spin_lock_irqsave(&ha->hardware_lock, flags); + intr_status = readl(&ha->reg->ctrl_status); + if (intr_status & CSR_SCSI_PROCESSOR_INTR) { + /* Service existing interrupt */ + qla4xxx_interrupt_service_routine(ha, intr_status); + clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + } + + /* Send the mailbox command to the firmware */ + ha->mbox_status_count = outCount; + for (i = 0; i < outCount; i++) + ha->mbox_status[i] = 0; + + /* Load all mailbox registers, except mailbox 0. */ + for (i = 1; i < inCount; i++) + writel(mbx_cmd[i], &ha->reg->mailbox[i]); + + /* Wakeup firmware */ + writel(mbx_cmd[0], &ha->reg->mailbox[0]); + readl(&ha->reg->mailbox[0]); + writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* Wait for completion */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&ha->mailbox_wait_queue, &wait); + + /* + * If we don't want status, don't wait for the mailbox command to + * complete. For example, MBOX_CMD_RESET_FW doesn't return status, + * you must poll the inbound Interrupt Mask for completion. + */ + if (outCount == 0) { + status = QLA_SUCCESS; + set_current_state(TASK_RUNNING); + remove_wait_queue(&ha->mailbox_wait_queue, &wait); + goto mbox_exit; + } + /* Wait for command to complete */ + wait_count = jiffies + MBOX_TOV * HZ; + while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { + if (time_after_eq(jiffies, wait_count)) + break; + + spin_lock_irqsave(&ha->hardware_lock, flags); + intr_status = readl(&ha->reg->ctrl_status); + if (intr_status & INTR_PENDING) { + /* + * Service the interrupt. + * The ISR will save the mailbox status registers + * to a temporary storage location in the adapter + * structure. + */ + ha->mbox_status_count = outCount; + qla4xxx_interrupt_service_routine(ha, intr_status); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + msleep(10); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&ha->mailbox_wait_queue, &wait); + + /* Check for mailbox timeout. */ + if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { + DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...," + " Scheduling Adapter Reset\n", ha->host_no, + mbx_cmd[0])); + ha->mailbox_timeout_count++; + mbx_sts[0] = (-1); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + goto mbox_exit; + } + + /* + * Copy the mailbox out registers to the caller's mailbox in/out + * structure. + */ + spin_lock_irqsave(&ha->hardware_lock, flags); + for (i = 0; i < outCount; i++) + mbx_sts[i] = ha->mbox_status[i]; + + /* Set return status and error flags (if applicable). */ + switch (ha->mbox_status[0]) { + case MBOX_STS_COMMAND_COMPLETE: + status = QLA_SUCCESS; + break; + + case MBOX_STS_INTERMEDIATE_COMPLETION: + status = QLA_SUCCESS; + break; + + case MBOX_STS_BUSY: + DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n", + ha->host_no, __func__, mbx_cmd[0])); + ha->mailbox_timeout_count++; + break; + + default: + DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, " + "sts = %08X ****\n", ha->host_no, __func__, + mbx_cmd[0], mbx_sts[0])); + break; + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + +mbox_exit: + clear_bit(AF_MBOX_COMMAND, &ha->flags); + clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + mutex_unlock(&ha->mbox_sem); + + return status; +} + + +/** + * qla4xxx_issue_iocb - issue mailbox iocb command + * @ha: adapter state pointer. + * @buffer: buffer pointer. + * @phys_addr: physical address of buffer. + * @size: size of buffer. + * + * Issues iocbs via mailbox commands. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + **/ +int +qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer, + dma_addr_t phys_addr, size_t size) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64; + mbox_cmd[1] = 0; + mbox_cmd[2] = LSDW(phys_addr); + mbox_cmd[3] = MSDW(phys_addr); + status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]); + return status; +} + +int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, + uint16_t fw_ddb_index, + uint16_t connection_id, + uint16_t option) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; + mbox_cmd[1] = fw_ddb_index; + mbox_cmd[2] = connection_id; + mbox_cmd[3] = LOGOUT_OPTION_RELOGIN; + if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " + "option %04x failed sts %04X %04X", + ha->host_no, __func__, + option, mbox_sts[0], mbox_sts[1])); + if (mbox_sts[0] == 0x4005) + DEBUG2(printk("%s reason %04X\n", __func__, + mbox_sts[1])); + } + return QLA_SUCCESS; +} + +int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, + uint16_t fw_ddb_index) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY; + mbox_cmd[1] = fw_ddb_index; + if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) + return QLA_ERROR; + + return QLA_SUCCESS; +} + +/** + * qla4xxx_initialize_fw_cb - initializes firmware control block. + * @ha: Pointer to host adapter structure. + **/ +int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) +{ + struct init_fw_ctrl_blk *init_fw_cb; + dma_addr_t init_fw_cb_dma; + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status = QLA_ERROR; + + init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct init_fw_ctrl_blk), + &init_fw_cb_dma, GFP_KERNEL); + if (init_fw_cb == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", + ha->host_no, __func__)); + return 10; + } + memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); + + /* Get Initialize Firmware Control Block. */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; + mbox_cmd[2] = LSDW(init_fw_cb_dma); + mbox_cmd[3] = MSDW(init_fw_cb_dma); + if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + dma_free_coherent(&ha->pdev->dev, + sizeof(struct init_fw_ctrl_blk), + init_fw_cb, init_fw_cb_dma); + return status; + } + + /* Initialize request and response queues. */ + qla4xxx_init_rings(ha); + + /* Fill in the request and response queue information. */ + init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out); + init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in); + init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); + init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); + init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma)); + init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma)); + init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma)); + init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma)); + init_fw_cb->ShadowRegBufAddrLo = + cpu_to_le32(LSDW(ha->shadow_regs_dma)); + init_fw_cb->ShadowRegBufAddrHi = + cpu_to_le32(MSDW(ha->shadow_regs_dma)); + + /* Set up required options. */ + init_fw_cb->FwOptions |= + __constant_cpu_to_le16(FWOPT_SESSION_MODE | + FWOPT_INITIATOR_MODE); + init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); + + /* Save some info in adapter structure. */ + ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions); + ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions); + ha->heartbeat_interval = init_fw_cb->HeartbeatInterval; + memcpy(ha->ip_address, init_fw_cb->IPAddr, + min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr))); + memcpy(ha->subnet_mask, init_fw_cb->SubnetMask, + min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask))); + memcpy(ha->gateway, init_fw_cb->GatewayIPAddr, + min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr))); + memcpy(ha->name_string, init_fw_cb->iSCSINameString, + min(sizeof(ha->name_string), + sizeof(init_fw_cb->iSCSINameString))); + memcpy(ha->alias, init_fw_cb->Alias, + min(sizeof(ha->alias), sizeof(init_fw_cb->Alias))); + + /* Save Command Line Paramater info */ + ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout); + ha->discovery_wait = ql4xdiscoverywait; + + /* Send Initialize Firmware Control Block. */ + mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; + mbox_cmd[1] = 0; + mbox_cmd[2] = LSDW(init_fw_cb_dma); + mbox_cmd[3] = MSDW(init_fw_cb_dma); + if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) == + QLA_SUCCESS) + status = QLA_SUCCESS; + else { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE " + "failed w/ status %04X\n", ha->host_no, __func__, + mbox_sts[0])); + } + dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), + init_fw_cb, init_fw_cb_dma); + + return status; +} + +/** + * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP + * @ha: Pointer to host adapter structure. + **/ +int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) +{ + struct init_fw_ctrl_blk *init_fw_cb; + dma_addr_t init_fw_cb_dma; + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct init_fw_ctrl_blk), + &init_fw_cb_dma, GFP_KERNEL); + if (init_fw_cb == NULL) { + printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, + __func__); + return 10; + } + + /* Get Initialize Firmware Control Block. */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); + mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; + mbox_cmd[2] = LSDW(init_fw_cb_dma); + mbox_cmd[3] = MSDW(init_fw_cb_dma); + + if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", + ha->host_no, __func__)); + dma_free_coherent(&ha->pdev->dev, + sizeof(struct init_fw_ctrl_blk), + init_fw_cb, init_fw_cb_dma); + return QLA_ERROR; + } + + /* Save IP Address. */ + memcpy(ha->ip_address, init_fw_cb->IPAddr, + min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr))); + memcpy(ha->subnet_mask, init_fw_cb->SubnetMask, + min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask))); + memcpy(ha->gateway, init_fw_cb->GatewayIPAddr, + min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr))); + + dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), + init_fw_cb, init_fw_cb_dma); + + return QLA_SUCCESS; +} + +/** + * qla4xxx_get_firmware_state - gets firmware state of HBA + * @ha: Pointer to host adapter structure. + **/ +int qla4xxx_get_firmware_state(struct scsi_qla_host * ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Get firmware version */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_GET_FW_STATE; + if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ " + "status %04X\n", ha->host_no, __func__, + mbox_sts[0])); + return QLA_ERROR; + } + ha->firmware_state = mbox_sts[1]; + ha->board_id = mbox_sts[2]; + ha->addl_fw_state = mbox_sts[3]; + DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n", + ha->host_no, __func__, ha->firmware_state);) + + return QLA_SUCCESS; +} + +/** + * qla4xxx_get_firmware_status - retrieves firmware status + * @ha: Pointer to host adapter structure. + **/ +int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Get firmware version */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS; + if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ " + "status %04X\n", ha->host_no, __func__, + mbox_sts[0])); + return QLA_ERROR; + } + + /* High-water mark of IOCBs */ + ha->iocb_hiwat = mbox_sts[2]; + if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION) + ha->iocb_hiwat -= IOCB_HIWAT_CUSHION; + else + dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d " + "firmare IOCBs available (%d).\n", + IOCB_HIWAT_CUSHION, ha->iocb_hiwat); + + return QLA_SUCCESS; +} + +/** + * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry + * @ha: Pointer to host adapter structure. + * @fw_ddb_index: Firmware's device database index + * @fw_ddb_entry: Pointer to firmware's device database entry structure + * @num_valid_ddb_entries: Pointer to number of valid ddb entries + * @next_ddb_index: Pointer to next valid device database index + * @fw_ddb_device_state: Pointer to device state + **/ +int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, + uint16_t fw_ddb_index, + struct dev_db_entry *fw_ddb_entry, + dma_addr_t fw_ddb_entry_dma, + uint32_t *num_valid_ddb_entries, + uint32_t *next_ddb_index, + uint32_t *fw_ddb_device_state, + uint32_t *conn_err_detail, + uint16_t *tcp_source_port_num, + uint16_t *connection_id) +{ + int status = QLA_ERROR; + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Make sure the device index is valid */ + if (fw_ddb_index >= MAX_DDB_ENTRIES) { + DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n", + ha->host_no, __func__, fw_ddb_index)); + goto exit_get_fwddb; + } + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; + mbox_cmd[1] = (uint32_t) fw_ddb_index; + mbox_cmd[2] = LSDW(fw_ddb_entry_dma); + mbox_cmd[3] = MSDW(fw_ddb_entry_dma); + if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) == + QLA_ERROR) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed" + " with status 0x%04X\n", ha->host_no, __func__, + mbox_sts[0])); + goto exit_get_fwddb; + } + if (fw_ddb_index != mbox_sts[1]) { + DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n", + ha->host_no, __func__, fw_ddb_index, + mbox_sts[1])); + goto exit_get_fwddb; + } + if (fw_ddb_entry) { + dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " + "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", + fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], + mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0], + fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2], + fw_ddb_entry->ipAddr[3], + le16_to_cpu(fw_ddb_entry->portNumber), + fw_ddb_entry->iscsiName); + } + if (num_valid_ddb_entries) + *num_valid_ddb_entries = mbox_sts[2]; + if (next_ddb_index) + *next_ddb_index = mbox_sts[3]; + if (fw_ddb_device_state) + *fw_ddb_device_state = mbox_sts[4]; + + /* + * RA: This mailbox has been changed to pass connection error and + * details. Its true for ISP4010 as per Version E - Not sure when it + * was changed. Get the time2wait from the fw_dd_entry field : + * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY + * struct. + */ + if (conn_err_detail) + *conn_err_detail = mbox_sts[5]; + if (tcp_source_port_num) + *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16; + if (connection_id) + *connection_id = (uint16_t) mbox_sts[6] & 0x00FF; + status = QLA_SUCCESS; + +exit_get_fwddb: + return status; +} + +/** + * qla4xxx_set_fwddb_entry - sets a ddb entry. + * @ha: Pointer to host adapter structure. + * @fw_ddb_index: Firmware's device database index + * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL. + * + * This routine initializes or updates the adapter's device database + * entry for the specified device. It also triggers a login for the + * specified device. Therefore, it may also be used as a secondary + * login routine when a NULL pointer is specified for the fw_ddb_entry. + **/ +int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, + dma_addr_t fw_ddb_entry_dma) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Do not wait for completion. The firmware will send us an + * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. + */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY; + mbox_cmd[1] = (uint32_t) fw_ddb_index; + mbox_cmd[2] = LSDW(fw_ddb_entry_dma); + mbox_cmd[3] = MSDW(fw_ddb_entry_dma); + return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]); +} + +int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha, + uint16_t fw_ddb_index) +{ + int status = QLA_ERROR; + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Do not wait for completion. The firmware will send us an + * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. + */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN; + mbox_cmd[1] = (uint32_t) fw_ddb_index; + mbox_cmd[2] = 0; + mbox_cmd[3] = 0; + mbox_cmd[4] = 0; + status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]); + DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n", + __func__, fw_ddb_index, status, mbox_sts[0], + mbox_sts[1]);) + + return status; +} + +/** + * qla4xxx_get_crash_record - retrieves crash record. + * @ha: Pointer to host adapter structure. + * + * This routine retrieves a crash record from the QLA4010 after an 8002h aen. + **/ +void qla4xxx_get_crash_record(struct scsi_qla_host * ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + struct crash_record *crash_record = NULL; + dma_addr_t crash_record_dma = 0; + uint32_t crash_record_size = 0; + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_cmd)); + + /* Get size of crash record. */ + mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; + if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n", + ha->host_no, __func__)); + goto exit_get_crash_record; + } + crash_record_size = mbox_sts[4]; + if (crash_record_size == 0) { + DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n", + ha->host_no, __func__)); + goto exit_get_crash_record; + } + + /* Alloc Memory for Crash Record. */ + crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size, + &crash_record_dma, GFP_KERNEL); + if (crash_record == NULL) + goto exit_get_crash_record; + + /* Get Crash Record. */ + mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; + mbox_cmd[2] = LSDW(crash_record_dma); + mbox_cmd[3] = MSDW(crash_record_dma); + mbox_cmd[4] = crash_record_size; + if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) + goto exit_get_crash_record; + + /* Dump Crash Record. */ + +exit_get_crash_record: + if (crash_record) + dma_free_coherent(&ha->pdev->dev, crash_record_size, + crash_record, crash_record_dma); +} + +/** + * qla4xxx_get_conn_event_log - retrieves connection event log + * @ha: Pointer to host adapter structure. + **/ +void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + struct conn_event_log_entry *event_log = NULL; + dma_addr_t event_log_dma = 0; + uint32_t event_log_size = 0; + uint32_t num_valid_entries; + uint32_t oldest_entry = 0; + uint32_t max_event_log_entries; + uint8_t i; + + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_cmd)); + + /* Get size of crash record. */ + mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; + if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) + goto exit_get_event_log; + + event_log_size = mbox_sts[4]; + if (event_log_size == 0) + goto exit_get_event_log; + + /* Alloc Memory for Crash Record. */ + event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size, + &event_log_dma, GFP_KERNEL); + if (event_log == NULL) + goto exit_get_event_log; + + /* Get Crash Record. */ + mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; + mbox_cmd[2] = LSDW(event_log_dma); + mbox_cmd[3] = MSDW(event_log_dma); + if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event " + "log!\n", ha->host_no, __func__)); + goto exit_get_event_log; + } + + /* Dump Event Log. */ + num_valid_entries = mbox_sts[1]; + + max_event_log_entries = event_log_size / + sizeof(struct conn_event_log_entry); + + if (num_valid_entries > max_event_log_entries) + oldest_entry = num_valid_entries % max_event_log_entries; + + DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", + ha->host_no, num_valid_entries)); + + if (extended_error_logging == 3) { + if (oldest_entry == 0) { + /* Circular Buffer has not wrapped around */ + for (i=0; i < num_valid_entries; i++) { + qla4xxx_dump_buffer((uint8_t *)event_log+ + (i*sizeof(*event_log)), + sizeof(*event_log)); + } + } + else { + /* Circular Buffer has wrapped around - + * display accordingly*/ + for (i=oldest_entry; i < max_event_log_entries; i++) { + qla4xxx_dump_buffer((uint8_t *)event_log+ + (i*sizeof(*event_log)), + sizeof(*event_log)); + } + for (i=0; i < oldest_entry; i++) { + qla4xxx_dump_buffer((uint8_t *)event_log+ + (i*sizeof(*event_log)), + sizeof(*event_log)); + } + } + } + +exit_get_event_log: + if (event_log) + dma_free_coherent(&ha->pdev->dev, event_log_size, event_log, + event_log_dma); +} + +/** + * qla4xxx_reset_lun - issues LUN Reset + * @ha: Pointer to host adapter structure. + * @db_entry: Pointer to device database entry + * @un_entry: Pointer to lun entry structure + * + * This routine performs a LUN RESET on the specified target/lun. + * The caller must ensure that the ddb_entry and lun_entry pointers + * are valid before calling this routine. + **/ +int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, + int lun) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status = QLA_SUCCESS; + + DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, + ddb_entry->os_target_id, lun)); + + /* + * Send lun reset command to ISP, so that the ISP will return all + * outstanding requests with RESET status + */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_LUN_RESET; + mbox_cmd[1] = ddb_entry->fw_ddb_index; + mbox_cmd[2] = lun << 8; + mbox_cmd[5] = 0x01; /* Immediate Command Enable */ + qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]); + if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && + mbox_sts[0] != MBOX_STS_COMMAND_ERROR) + status = QLA_ERROR; + + return status; +} + + +int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, + uint32_t offset, uint32_t len) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_READ_FLASH; + mbox_cmd[1] = LSDW(dma_addr); + mbox_cmd[2] = MSDW(dma_addr); + mbox_cmd[3] = offset; + mbox_cmd[4] = len; + if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ " + "status %04X %04X, offset %08x, len %08x\n", ha->host_no, + __func__, mbox_sts[0], mbox_sts[1], offset, len)); + return QLA_ERROR; + } + return QLA_SUCCESS; +} + +/** + * qla4xxx_get_fw_version - gets firmware version + * @ha: Pointer to host adapter structure. + * + * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may + * hold an address for data. Make sure that we write 0 to those mailboxes, + * if unused. + **/ +int qla4xxx_get_fw_version(struct scsi_qla_host * ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Get firmware version. */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_ABOUT_FW; + if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ " + "status %04X\n", ha->host_no, __func__, mbox_sts[0])); + return QLA_ERROR; + } + + /* Save firmware version information. */ + ha->firmware_version[0] = mbox_sts[1]; + ha->firmware_version[1] = mbox_sts[2]; + ha->patch_number = mbox_sts[3]; + ha->build_number = mbox_sts[4]; + + return QLA_SUCCESS; +} + +int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS; + mbox_cmd[2] = LSDW(dma_addr); + mbox_cmd[3] = MSDW(dma_addr); + + if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: failed status %04X\n", + ha->host_no, __func__, mbox_sts[0])); + return QLA_ERROR; + } + return QLA_SUCCESS; +} + +int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY; + mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES; + + if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) { + *ddb_index = mbox_sts[2]; + } else { + DEBUG2(printk("scsi%ld: %s: failed status %04X\n", + ha->host_no, __func__, mbox_sts[0])); + return QLA_ERROR; + } + } else { + *ddb_index = MAX_PRST_DEV_DB_ENTRIES; + } + + return QLA_SUCCESS; +} + + +int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) +{ + struct dev_db_entry *fw_ddb_entry; + dma_addr_t fw_ddb_entry_dma; + uint32_t ddb_index; + int ret_val = QLA_SUCCESS; + + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, + sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", + ha->host_no, __func__)); + ret_val = QLA_ERROR; + goto qla4xxx_send_tgts_exit; + } + + ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma); + if (ret_val != QLA_SUCCESS) + goto qla4xxx_send_tgts_exit; + + ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index); + if (ret_val != QLA_SUCCESS) + goto qla4xxx_send_tgts_exit; + + memset((void *)fw_ddb_entry->iSCSIAlias, 0, + sizeof(fw_ddb_entry->iSCSIAlias)); + + memset((void *)fw_ddb_entry->iscsiName, 0, + sizeof(fw_ddb_entry->iscsiName)); + + memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr)); + memset((void *)fw_ddb_entry->targetAddr, 0, + sizeof(fw_ddb_entry->targetAddr)); + + fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET); + fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port)); + + fw_ddb_entry->ipAddr[0] = *ip; + fw_ddb_entry->ipAddr[1] = *(ip + 1); + fw_ddb_entry->ipAddr[2] = *(ip + 2); + fw_ddb_entry->ipAddr[3] = *(ip + 3); + + ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma); + +qla4xxx_send_tgts_exit: + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); + return ret_val; +} + diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c new file mode 100644 index 00000000000..e3957ca5b64 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_nvram.c @@ -0,0 +1,224 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#include "ql4_def.h" + +static inline int eeprom_size(struct scsi_qla_host *ha) +{ + return is_qla4022(ha) ? FM93C86A_SIZE_16 : FM93C66A_SIZE_16; +} + +static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha) +{ + return is_qla4022(ha) ? FM93C86A_NO_ADDR_BITS_16 : + FM93C56A_NO_ADDR_BITS_16; +} + +static inline int eeprom_no_data_bits(struct scsi_qla_host *ha) +{ + return FM93C56A_DATA_BITS_16; +} + +static int fm93c56a_select(struct scsi_qla_host * ha) +{ + DEBUG5(printk(KERN_ERR "fm93c56a_select:\n")); + + ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000; + writel(ha->eeprom_cmd_data, isp_nvram(ha)); + readl(isp_nvram(ha)); + return 1; +} + +static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr) +{ + int i; + int mask; + int dataBit; + int previousBit; + + /* Clock in a zero, then do the start bit. */ + writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, isp_nvram(ha)); + writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | + AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); + writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | + AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); + readl(isp_nvram(ha)); + mask = 1 << (FM93C56A_CMD_BITS - 1); + + /* Force the previous data bit to be different. */ + previousBit = 0xffff; + for (i = 0; i < FM93C56A_CMD_BITS; i++) { + dataBit = + (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0; + if (previousBit != dataBit) { + + /* + * If the bit changed, then change the DO state to + * match. + */ + writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha)); + previousBit = dataBit; + } + writel(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); + writel(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); + readl(isp_nvram(ha)); + cmd = cmd << 1; + } + mask = 1 << (eeprom_no_addr_bits(ha) - 1); + + /* Force the previous data bit to be different. */ + previousBit = 0xffff; + for (i = 0; i < eeprom_no_addr_bits(ha); i++) { + dataBit = addr & mask ? AUBURN_EEPROM_DO_1 : + AUBURN_EEPROM_DO_0; + if (previousBit != dataBit) { + /* + * If the bit changed, then change the DO state to + * match. + */ + writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha)); + previousBit = dataBit; + } + writel(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); + writel(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); + readl(isp_nvram(ha)); + addr = addr << 1; + } + return 1; +} + +static int fm93c56a_deselect(struct scsi_qla_host * ha) +{ + ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000; + writel(ha->eeprom_cmd_data, isp_nvram(ha)); + readl(isp_nvram(ha)); + return 1; +} + +static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value) +{ + int i; + int data = 0; + int dataBit; + + /* Read the data bits + * The first bit is a dummy. Clock right over it. */ + for (i = 0; i < eeprom_no_data_bits(ha); i++) { + writel(ha->eeprom_cmd_data | + AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); + writel(ha->eeprom_cmd_data | + AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); + dataBit = + (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0; + data = (data << 1) | dataBit; + } + + *value = data; + return 1; +} + +static int eeprom_readword(int eepromAddr, u16 * value, + struct scsi_qla_host * ha) +{ + fm93c56a_select(ha); + fm93c56a_cmd(ha, FM93C56A_READ, eepromAddr); + fm93c56a_datain(ha, value); + fm93c56a_deselect(ha); + return 1; +} + +/* Hardware_lock must be set before calling */ +u16 rd_nvram_word(struct scsi_qla_host * ha, int offset) +{ + u16 val; + + /* NOTE: NVRAM uses half-word addresses */ + eeprom_readword(offset, &val, ha); + return val; +} + +int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha) +{ + int status = QLA_ERROR; + uint16_t checksum = 0; + uint32_t index; + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (index = 0; index < eeprom_size(ha); index++) + checksum += rd_nvram_word(ha, index); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (checksum == 0) + status = QLA_SUCCESS; + + return status; +} + +/************************************************************************* + * + * Hardware Semaphore routines + * + *************************************************************************/ +int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits) +{ + uint32_t value; + unsigned long flags; + unsigned int seconds = 30; + + DEBUG2(printk("scsi%ld : Trying to get SEM lock - mask= 0x%x, code = " + "0x%x\n", ha->host_no, sem_mask, sem_bits)); + do { + spin_lock_irqsave(&ha->hardware_lock, flags); + writel((sem_mask | sem_bits), isp_semaphore(ha)); + value = readw(isp_semaphore(ha)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if ((value & (sem_mask >> 16)) == sem_bits) { + DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, " + "code = 0x%x\n", ha->host_no, + sem_mask, sem_bits)); + return QLA_SUCCESS; + } + ssleep(1); + } while (--seconds); + return QLA_ERROR; +} + +void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask) +{ + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(sem_mask, isp_semaphore(ha)); + readl(isp_semaphore(ha)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG2(printk("scsi%ld : UNLOCK SEM - mask= 0x%x\n", ha->host_no, + sem_mask)); +} + +int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits) +{ + uint32_t value; + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + writel((sem_mask | sem_bits), isp_semaphore(ha)); + value = readw(isp_semaphore(ha)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if ((value & (sem_mask >> 16)) == sem_bits) { + DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, code = " + "0x%x, sema code=0x%x\n", ha->host_no, + sem_mask, sem_bits, value)); + return 1; + } + return 0; +} diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h new file mode 100644 index 00000000000..08e2aed8c6c --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_nvram.h @@ -0,0 +1,256 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#ifndef _QL4XNVRM_H_ +#define _QL4XNVRM_H_ + +/* + * AM29LV Flash definitions + */ +#define FM93C56A_SIZE_8 0x100 +#define FM93C56A_SIZE_16 0x80 +#define FM93C66A_SIZE_8 0x200 +#define FM93C66A_SIZE_16 0x100/* 4010 */ +#define FM93C86A_SIZE_16 0x400/* 4022 */ + +#define FM93C56A_START 0x1 + +// Commands +#define FM93C56A_READ 0x2 +#define FM93C56A_WEN 0x0 +#define FM93C56A_WRITE 0x1 +#define FM93C56A_WRITE_ALL 0x0 +#define FM93C56A_WDS 0x0 +#define FM93C56A_ERASE 0x3 +#define FM93C56A_ERASE_ALL 0x0 + +/* Command Extentions */ +#define FM93C56A_WEN_EXT 0x3 +#define FM93C56A_WRITE_ALL_EXT 0x1 +#define FM93C56A_WDS_EXT 0x0 +#define FM93C56A_ERASE_ALL_EXT 0x2 + +/* Address Bits */ +#define FM93C56A_NO_ADDR_BITS_16 8 /* 4010 */ +#define FM93C56A_NO_ADDR_BITS_8 9 /* 4010 */ +#define FM93C86A_NO_ADDR_BITS_16 10 /* 4022 */ + +/* Data Bits */ +#define FM93C56A_DATA_BITS_16 16 +#define FM93C56A_DATA_BITS_8 8 + +/* Special Bits */ +#define FM93C56A_READ_DUMMY_BITS 1 +#define FM93C56A_READY 0 +#define FM93C56A_BUSY 1 +#define FM93C56A_CMD_BITS 2 + +/* Auburn Bits */ +#define AUBURN_EEPROM_DI 0x8 +#define AUBURN_EEPROM_DI_0 0x0 +#define AUBURN_EEPROM_DI_1 0x8 +#define AUBURN_EEPROM_DO 0x4 +#define AUBURN_EEPROM_DO_0 0x0 +#define AUBURN_EEPROM_DO_1 0x4 +#define AUBURN_EEPROM_CS 0x2 +#define AUBURN_EEPROM_CS_0 0x0 +#define AUBURN_EEPROM_CS_1 0x2 +#define AUBURN_EEPROM_CLK_RISE 0x1 +#define AUBURN_EEPROM_CLK_FALL 0x0 + +/* */ +/* EEPROM format */ +/* */ +struct bios_params { + uint16_t SpinUpDelay:1; + uint16_t BIOSDisable:1; + uint16_t MMAPEnable:1; + uint16_t BootEnable:1; + uint16_t Reserved0:12; + uint8_t bootID0:7; + uint8_t bootID0Valid:1; + uint8_t bootLUN0[8]; + uint8_t bootID1:7; + uint8_t bootID1Valid:1; + uint8_t bootLUN1[8]; + uint16_t MaxLunsPerTarget; + uint8_t Reserved1[10]; +}; + +struct eeprom_port_cfg { + + /* MTU MAC 0 */ + u16 etherMtu_mac; + + /* Flow Control MAC 0 */ + u16 pauseThreshold_mac; + u16 resumeThreshold_mac; + u16 reserved[13]; +}; + +struct eeprom_function_cfg { + u8 reserved[30]; + + /* MAC ADDR */ + u8 macAddress[6]; + u8 macAddressSecondary[6]; + u16 subsysVendorId; + u16 subsysDeviceId; +}; + +struct eeprom_data { + union { + struct { /* isp4010 */ + u8 asic_id[4]; /* x00 */ + u8 version; /* x04 */ + u8 reserved; /* x05 */ + u16 board_id; /* x06 */ +#define EEPROM_BOARDID_ELDORADO 1 +#define EEPROM_BOARDID_PLACER 2 + +#define EEPROM_SERIAL_NUM_SIZE 16 + u8 serial_number[EEPROM_SERIAL_NUM_SIZE]; /* x08 */ + + /* ExtHwConfig: */ + /* Offset = 24bytes + * + * | SSRAM Size| |ST|PD|SDRAM SZ| W| B| SP | | + * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + u16 ext_hw_conf; /* x18 */ + u8 mac0[6]; /* x1A */ + u8 mac1[6]; /* x20 */ + u8 mac2[6]; /* x26 */ + u8 mac3[6]; /* x2C */ + u16 etherMtu; /* x32 */ + u16 macConfig; /* x34 */ +#define MAC_CONFIG_ENABLE_ANEG 0x0001 +#define MAC_CONFIG_ENABLE_PAUSE 0x0002 + u16 phyConfig; /* x36 */ +#define PHY_CONFIG_PHY_ADDR_MASK 0x1f +#define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20 + u16 topcat; /* x38 */ +#define TOPCAT_PRESENT 0x0100 +#define TOPCAT_MASK 0xFF00 + +#define EEPROM_UNUSED_1_SIZE 2 + u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */ + u16 bufletSize; /* x3C */ + u16 bufletCount; /* x3E */ + u16 bufletPauseThreshold; /* x40 */ + u16 tcpWindowThreshold50; /* x42 */ + u16 tcpWindowThreshold25; /* x44 */ + u16 tcpWindowThreshold0; /* x46 */ + u16 ipHashTableBaseHi; /* x48 */ + u16 ipHashTableBaseLo; /* x4A */ + u16 ipHashTableSize; /* x4C */ + u16 tcpHashTableBaseHi; /* x4E */ + u16 tcpHashTableBaseLo; /* x50 */ + u16 tcpHashTableSize; /* x52 */ + u16 ncbTableBaseHi; /* x54 */ + u16 ncbTableBaseLo; /* x56 */ + u16 ncbTableSize; /* x58 */ + u16 drbTableBaseHi; /* x5A */ + u16 drbTableBaseLo; /* x5C */ + u16 drbTableSize; /* x5E */ + +#define EEPROM_UNUSED_2_SIZE 4 + u8 unused_2[EEPROM_UNUSED_2_SIZE]; /* x60 */ + u16 ipReassemblyTimeout; /* x64 */ + u16 tcpMaxWindowSizeHi; /* x66 */ + u16 tcpMaxWindowSizeLo; /* x68 */ + u32 net_ip_addr0; /* x6A Added for TOE + * functionality. */ + u32 net_ip_addr1; /* x6E */ + u32 scsi_ip_addr0; /* x72 */ + u32 scsi_ip_addr1; /* x76 */ +#define EEPROM_UNUSED_3_SIZE 128 /* changed from 144 to account + * for ip addresses */ + u8 unused_3[EEPROM_UNUSED_3_SIZE]; /* x7A */ + u16 subsysVendorId_f0; /* xFA */ + u16 subsysDeviceId_f0; /* xFC */ + + /* Address = 0x7F */ +#define FM93C56A_SIGNATURE 0x9356 +#define FM93C66A_SIGNATURE 0x9366 + u16 signature; /* xFE */ + +#define EEPROM_UNUSED_4_SIZE 250 + u8 unused_4[EEPROM_UNUSED_4_SIZE]; /* x100 */ + u16 subsysVendorId_f1; /* x1FA */ + u16 subsysDeviceId_f1; /* x1FC */ + u16 checksum; /* x1FE */ + } __attribute__ ((packed)) isp4010; + struct { /* isp4022 */ + u8 asicId[4]; /* x00 */ + u8 version; /* x04 */ + u8 reserved_5; /* x05 */ + u16 boardId; /* x06 */ + u8 boardIdStr[16]; /* x08 */ + u8 serialNumber[16]; /* x18 */ + + /* External Hardware Configuration */ + u16 ext_hw_conf; /* x28 */ + + /* MAC 0 CONFIGURATION */ + struct eeprom_port_cfg macCfg_port0; /* x2A */ + + /* MAC 1 CONFIGURATION */ + struct eeprom_port_cfg macCfg_port1; /* x4A */ + + /* DDR SDRAM Configuration */ + u16 bufletSize; /* x6A */ + u16 bufletCount; /* x6C */ + u16 tcpWindowThreshold50; /* x6E */ + u16 tcpWindowThreshold25; /* x70 */ + u16 tcpWindowThreshold0; /* x72 */ + u16 ipHashTableBaseHi; /* x74 */ + u16 ipHashTableBaseLo; /* x76 */ + u16 ipHashTableSize; /* x78 */ + u16 tcpHashTableBaseHi; /* x7A */ + u16 tcpHashTableBaseLo; /* x7C */ + u16 tcpHashTableSize; /* x7E */ + u16 ncbTableBaseHi; /* x80 */ + u16 ncbTableBaseLo; /* x82 */ + u16 ncbTableSize; /* x84 */ + u16 drbTableBaseHi; /* x86 */ + u16 drbTableBaseLo; /* x88 */ + u16 drbTableSize; /* x8A */ + u16 reserved_142[4]; /* x8C */ + + /* TCP/IP Parameters */ + u16 ipReassemblyTimeout; /* x94 */ + u16 tcpMaxWindowSize; /* x96 */ + u16 ipSecurity; /* x98 */ + u8 reserved_156[294]; /* x9A */ + u16 qDebug[8]; /* QLOGIC USE ONLY x1C0 */ + struct eeprom_function_cfg funcCfg_fn0; /* x1D0 */ + u16 reserved_510; /* x1FE */ + + /* Address = 512 */ + u8 oemSpace[432]; /* x200 */ + struct bios_params sBIOSParams_fn1; /* x3B0 */ + struct eeprom_function_cfg funcCfg_fn1; /* x3D0 */ + u16 reserved_1022; /* x3FE */ + + /* Address = 1024 */ + u8 reserved_1024[464]; /* x400 */ + struct eeprom_function_cfg funcCfg_fn2; /* x5D0 */ + u16 reserved_1534; /* x5FE */ + + /* Address = 1536 */ + u8 reserved_1536[432]; /* x600 */ + struct bios_params sBIOSParams_fn3; /* x7B0 */ + struct eeprom_function_cfg funcCfg_fn3; /* x7D0 */ + u16 checksum; /* x7FE */ + } __attribute__ ((packed)) isp4022; + }; +}; + + +#endif /* _QL4XNVRM_H_ */ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c new file mode 100644 index 00000000000..5036ebf013a --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -0,0 +1,1755 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ +#include + +#include +#include + +#include "ql4_def.h" + +/* + * Driver version + */ +char qla4xxx_version_str[40]; + +/* + * SRB allocation cache + */ +static kmem_cache_t *srb_cachep; + +/* + * Module parameter information and variables + */ +int ql4xdiscoverywait = 60; +module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time"); +int ql4xdontresethba = 0; +module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(ql4xdontresethba, + "Dont reset the HBA when the driver gets 0x8002 AEN " + " default it will reset hba :0" + " set to 1 to avoid resetting HBA"); + +int extended_error_logging = 0; /* 0 = off, 1 = log errors */ +module_param(extended_error_logging, int, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(extended_error_logging, + "Option to enable extended error logging, " + "Default is 0 - no logging, 1 - debug logging"); + +/* + * SCSI host template entry points + */ + +void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); + +/* + * iSCSI template entry points + */ +static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no, + uint32_t enable, struct sockaddr *dst_addr); +static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, + enum iscsi_param param, char *buf); +static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, + enum iscsi_param param, char *buf); +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag); +static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); +static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); + +/* + * SCSI host template entry points + */ +static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)); +static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); +static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); +static int qla4xxx_slave_alloc(struct scsi_device *device); +static int qla4xxx_slave_configure(struct scsi_device *device); +static void qla4xxx_slave_destroy(struct scsi_device *sdev); + +static struct scsi_host_template qla4xxx_driver_template = { + .module = THIS_MODULE, + .name = DRIVER_NAME, + .proc_name = DRIVER_NAME, + .queuecommand = qla4xxx_queuecommand, + + .eh_device_reset_handler = qla4xxx_eh_device_reset, + .eh_host_reset_handler = qla4xxx_eh_host_reset, + + .slave_configure = qla4xxx_slave_configure, + .slave_alloc = qla4xxx_slave_alloc, + .slave_destroy = qla4xxx_slave_destroy, + + .this_id = -1, + .cmd_per_lun = 3, + .use_clustering = ENABLE_CLUSTERING, + .sg_tablesize = SG_ALL, + + .max_sectors = 0xFFFF, +}; + +static struct iscsi_transport qla4xxx_iscsi_transport = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .param_mask = ISCSI_CONN_PORT | + ISCSI_CONN_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, + .sessiondata_size = sizeof(struct ddb_entry), + .host_template = &qla4xxx_driver_template, + + .tgt_dscvr = qla4xxx_tgt_dscvr, + .get_conn_param = qla4xxx_conn_get_param, + .get_session_param = qla4xxx_sess_get_param, + .start_conn = qla4xxx_conn_start, + .stop_conn = qla4xxx_conn_stop, + .session_recovery_timedout = qla4xxx_recovery_timedout, +}; + +static struct scsi_transport_template *qla4xxx_scsi_transport; + +static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) +{ + struct ddb_entry *ddb_entry = session->dd_data; + struct scsi_qla_host *ha = ddb_entry->ha; + + DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) " + "secs exhausted, marking device DEAD.\n", ha->host_no, + __func__, ddb_entry->fw_ddb_index, + ha->port_down_retry_count)); + + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " + "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); +} + +static int qla4xxx_conn_start(struct iscsi_cls_conn *conn) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + iscsi_unblock_session(session); + return 0; +} + +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + if (flag == STOP_CONN_RECOVER) + iscsi_block_session(session); + else + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); +} + +static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, + enum iscsi_param param, char *buf) +{ + struct ddb_entry *ddb_entry = sess->dd_data; + int len; + + switch (param) { + case ISCSI_PARAM_TARGET_NAME: + len = snprintf(buf, PAGE_SIZE - 1, "%s\n", + ddb_entry->iscsi_name); + break; + case ISCSI_PARAM_TPGT: + len = sprintf(buf, "%u\n", ddb_entry->tpgt); + break; + default: + return -ENOSYS; + } + + return len; +} + +static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + int len; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + switch (param) { + case ISCSI_PARAM_CONN_PORT: + len = sprintf(buf, "%hu\n", ddb_entry->port); + break; + case ISCSI_PARAM_CONN_ADDRESS: + /* TODO: what are the ipv6 bits */ + len = sprintf(buf, "%u.%u.%u.%u\n", + NIPQUAD(ddb_entry->ip_addr)); + break; + default: + return -ENOSYS; + } + + return len; +} + +static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no, + uint32_t enable, struct sockaddr *dst_addr) +{ + struct scsi_qla_host *ha; + struct Scsi_Host *shost; + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + int ret = 0; + + shost = scsi_host_lookup(host_no); + if (IS_ERR(shost)) { + printk(KERN_ERR "Could not find host no %u\n", host_no); + return -ENODEV; + } + + ha = (struct scsi_qla_host *) shost->hostdata; + + switch (type) { + case ISCSI_TGT_DSCVR_SEND_TARGETS: + if (dst_addr->sa_family == AF_INET) { + addr = (struct sockaddr_in *)dst_addr; + if (qla4xxx_send_tgts(ha, (char *)&addr->sin_addr, + addr->sin_port) != QLA_SUCCESS) + ret = -EIO; + } else if (dst_addr->sa_family == AF_INET6) { + /* + * TODO: fix qla4xxx_send_tgts + */ + addr6 = (struct sockaddr_in6 *)dst_addr; + if (qla4xxx_send_tgts(ha, (char *)&addr6->sin6_addr, + addr6->sin6_port) != QLA_SUCCESS) + ret = -EIO; + } else + ret = -ENOSYS; + break; + default: + ret = -ENOSYS; + } + + scsi_host_put(shost); + return ret; +} + +void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) +{ + if (!ddb_entry->sess) + return; + + if (ddb_entry->conn) { + iscsi_if_destroy_session_done(ddb_entry->conn); + iscsi_destroy_conn(ddb_entry->conn); + iscsi_remove_session(ddb_entry->sess); + } + iscsi_free_session(ddb_entry->sess); +} + +int qla4xxx_add_sess(struct ddb_entry *ddb_entry) +{ + int err; + + err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); + if (err) { + DEBUG2(printk(KERN_ERR "Could not add session.\n")); + return err; + } + + ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0); + if (!ddb_entry->conn) { + iscsi_remove_session(ddb_entry->sess); + DEBUG2(printk(KERN_ERR "Could not add connection.\n")); + return -ENOMEM; + } + + ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; + iscsi_if_create_session_done(ddb_entry->conn); + return 0; +} + +struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry; + struct iscsi_cls_session *sess; + + sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport); + if (!sess) + return NULL; + + ddb_entry = sess->dd_data; + memset(ddb_entry, 0, sizeof(*ddb_entry)); + ddb_entry->ha = ha; + ddb_entry->sess = sess; + return ddb_entry; +} + +/* + * Timer routines + */ + +static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, + unsigned long interval) +{ + DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", + __func__, ha->host->host_no)); + init_timer(&ha->timer); + ha->timer.expires = jiffies + interval * HZ; + ha->timer.data = (unsigned long)ha; + ha->timer.function = (void (*)(unsigned long))func; + add_timer(&ha->timer); + ha->timer_active = 1; +} + +static void qla4xxx_stop_timer(struct scsi_qla_host *ha) +{ + del_timer_sync(&ha->timer); + ha->timer_active = 0; +} + +/*** + * qla4xxx_mark_device_missing - mark a device as missing. + * @ha: Pointer to host adapter structure. + * @ddb_entry: Pointer to device database entry + * + * This routine marks a device missing and resets the relogin retry count. + **/ +void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + atomic_set(&ddb_entry->state, DDB_STATE_MISSING); + DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", + ha->host_no, ddb_entry->bus, ddb_entry->target, + ddb_entry->fw_ddb_index)); + iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); +} + +static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + struct srb *srb; + + srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); + if (!srb) + return srb; + + atomic_set(&srb->ref_count, 1); + srb->ha = ha; + srb->ddb = ddb_entry; + srb->cmd = cmd; + srb->flags = 0; + cmd->SCp.ptr = (void *)srb; + cmd->scsi_done = done; + + return srb; +} + +static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) +{ + struct scsi_cmnd *cmd = srb->cmd; + + if (srb->flags & SRB_DMA_VALID) { + if (cmd->use_sg) { + pci_unmap_sg(ha->pdev, cmd->request_buffer, + cmd->use_sg, cmd->sc_data_direction); + } else if (cmd->request_bufflen) { + pci_unmap_single(ha->pdev, srb->dma_handle, + cmd->request_bufflen, + cmd->sc_data_direction); + } + srb->flags &= ~SRB_DMA_VALID; + } + cmd->SCp.ptr = NULL; +} + +void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) +{ + struct scsi_cmnd *cmd = srb->cmd; + + qla4xxx_srb_free_dma(ha, srb); + + mempool_free(srb, ha->srb_mempool); + + cmd->scsi_done(cmd); +} + +/** + * qla4xxx_queuecommand - scsi layer issues scsi command to driver. + * @cmd: Pointer to Linux's SCSI command structure + * @done_fn: Function that the driver calls to notify the SCSI mid-layer + * that the command has been processed. + * + * Remarks: + * This routine is invoked by Linux to send a SCSI command to the driver. + * The mid-level driver tries to ensure that queuecommand never gets + * invoked concurrently with itself or the interrupt handler (although + * the interrupt handler may call this routine as part of request- + * completion handling). Unfortunely, it sometimes calls the scheduler + * in interrupt context which is a big NO! NO!. + **/ +static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; + struct srb *srb; + int rval; + + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { + cmd->result = DID_NO_CONNECT << 16; + goto qc_fail_command; + } + goto qc_host_busy; + } + + spin_unlock_irq(ha->host->host_lock); + + srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done); + if (!srb) + goto qc_host_busy_lock; + + rval = qla4xxx_send_command_to_isp(ha, srb); + if (rval != QLA_SUCCESS) + goto qc_host_busy_free_sp; + + spin_lock_irq(ha->host->host_lock); + return 0; + +qc_host_busy_free_sp: + qla4xxx_srb_free_dma(ha, srb); + mempool_free(srb, ha->srb_mempool); + +qc_host_busy_lock: + spin_lock_irq(ha->host->host_lock); + +qc_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; + +qc_fail_command: + done(cmd); + + return 0; +} + +/** + * qla4xxx_mem_free - frees memory allocated to adapter + * @ha: Pointer to host adapter structure. + * + * Frees memory previously allocated by qla4xxx_mem_alloc + **/ +static void qla4xxx_mem_free(struct scsi_qla_host *ha) +{ + if (ha->queues) + dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, + ha->queues_dma); + + ha->queues_len = 0; + ha->queues = NULL; + ha->queues_dma = 0; + ha->request_ring = NULL; + ha->request_dma = 0; + ha->response_ring = NULL; + ha->response_dma = 0; + ha->shadow_regs = NULL; + ha->shadow_regs_dma = 0; + + /* Free srb pool. */ + if (ha->srb_mempool) + mempool_destroy(ha->srb_mempool); + + ha->srb_mempool = NULL; + + /* release io space registers */ + if (ha->reg) + iounmap(ha->reg); + pci_release_regions(ha->pdev); +} + +/** + * qla4xxx_mem_alloc - allocates memory for use by adapter. + * @ha: Pointer to host adapter structure + * + * Allocates DMA memory for request and response queues. Also allocates memory + * for srbs. + **/ +static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) +{ + unsigned long align; + + /* Allocate contiguous block of DMA memory for queues. */ + ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + + (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + + sizeof(struct shadow_regs) + + MEM_ALIGN_VALUE + + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); + ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, + &ha->queues_dma, GFP_KERNEL); + if (ha->queues == NULL) { + dev_warn(&ha->pdev->dev, + "Memory Allocation failed - queues.\n"); + + goto mem_alloc_error_exit; + } + memset(ha->queues, 0, ha->queues_len); + + /* + * As per RISC alignment requirements -- the bus-address must be a + * multiple of the request-ring size (in bytes). + */ + align = 0; + if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) + align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & + (MEM_ALIGN_VALUE - 1)); + + /* Update request and response queue pointers. */ + ha->request_dma = ha->queues_dma + align; + ha->request_ring = (struct queue_entry *) (ha->queues + align); + ha->response_dma = ha->queues_dma + align + + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); + ha->response_ring = (struct queue_entry *) (ha->queues + align + + (REQUEST_QUEUE_DEPTH * + QUEUE_SIZE)); + ha->shadow_regs_dma = ha->queues_dma + align + + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + + (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); + ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + + (REQUEST_QUEUE_DEPTH * + QUEUE_SIZE) + + (RESPONSE_QUEUE_DEPTH * + QUEUE_SIZE)); + + /* Allocate memory for srb pool. */ + ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, + mempool_free_slab, srb_cachep); + if (ha->srb_mempool == NULL) { + dev_warn(&ha->pdev->dev, + "Memory Allocation failed - SRB Pool.\n"); + + goto mem_alloc_error_exit; + } + + return QLA_SUCCESS; + +mem_alloc_error_exit: + qla4xxx_mem_free(ha); + return QLA_ERROR; +} + +/** + * qla4xxx_timer - checks every second for work to do. + * @ha: Pointer to host adapter structure. + **/ +static void qla4xxx_timer(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry, *dtemp; + int start_dpc = 0; + + /* Search for relogin's to time-out and port down retry. */ + list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { + /* Count down time between sending relogins */ + if (adapter_up(ha) && + !test_bit(DF_RELOGIN, &ddb_entry->flags) && + atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + if (atomic_read(&ddb_entry->retry_relogin_timer) != + INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) + == 0) { + atomic_set(&ddb_entry-> + retry_relogin_timer, + INVALID_ENTRY); + set_bit(DPC_RELOGIN_DEVICE, + &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + DEBUG2(printk("scsi%ld: %s: index [%d]" + " login device\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + } else + atomic_dec(&ddb_entry-> + retry_relogin_timer); + } + } + + /* Wait for relogin to timeout */ + if (atomic_read(&ddb_entry->relogin_timer) && + (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { + /* + * If the relogin times out and the device is + * still NOT ONLINE then try and relogin again. + */ + if (atomic_read(&ddb_entry->state) != + DDB_STATE_ONLINE && + ddb_entry->fw_ddb_device_state == + DDB_DS_SESSION_FAILED) { + /* Reset retry relogin timer */ + atomic_inc(&ddb_entry->relogin_retry_count); + DEBUG2(printk("scsi%ld: index[%d] relogin" + " timed out-retrying" + " relogin (%d)\n", + ha->host_no, + ddb_entry->fw_ddb_index, + atomic_read(&ddb_entry-> + relogin_retry_count)) + ); + start_dpc++; + DEBUG(printk("scsi%ld:%d:%d: index [%d] " + "initate relogin after" + " %d seconds\n", + ha->host_no, ddb_entry->bus, + ddb_entry->target, + ddb_entry->fw_ddb_index, + ddb_entry->default_time2wait + 4) + ); + + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + } + } + } + + /* Check for heartbeat interval. */ + if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && + ha->heartbeat_interval != 0) { + ha->seconds_since_last_heartbeat++; + if (ha->seconds_since_last_heartbeat > + ha->heartbeat_interval + 2) + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + + + /* Wakeup the dpc routine for this adapter, if needed. */ + if ((start_dpc || + test_bit(DPC_RESET_HA, &ha->dpc_flags) || + test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || + test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || + test_bit(DPC_AEN, &ha->dpc_flags)) && + ha->dpc_thread) { + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" + " - dpc flags = 0x%lx\n", + ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); + } + + /* Reschedule timer thread to call us back in one second */ + mod_timer(&ha->timer, jiffies + HZ); + + DEBUG2(ha->seconds_since_last_intr++); +} + +/** + * qla4xxx_cmd_wait - waits for all outstanding commands to complete + * @ha: Pointer to host adapter structure. + * + * This routine stalls the driver until all outstanding commands are returned. + * Caller must release the Hardware Lock prior to calling this routine. + **/ +static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) +{ + uint32_t index = 0; + int stat = QLA_SUCCESS; + unsigned long flags; + struct scsi_cmnd *cmd; + int wait_cnt = WAIT_CMD_TOV; /* + * Initialized for 30 seconds as we + * expect all commands to retuned + * ASAP. + */ + + while (wait_cnt) { + spin_lock_irqsave(&ha->hardware_lock, flags); + /* Find a command that hasn't completed. */ + for (index = 0; index < ha->host->can_queue; index++) { + cmd = scsi_host_find_tag(ha->host, index); + if (cmd != NULL) + break; + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* If No Commands are pending, wait is complete */ + if (index == ha->host->can_queue) { + break; + } + + /* If we timed out on waiting for commands to come back + * return ERROR. + */ + wait_cnt--; + if (wait_cnt == 0) + stat = QLA_ERROR; + else { + msleep(1000); + } + } /* End of While (wait_cnt) */ + + return stat; +} + +/** + * qla4010_soft_reset - performs soft reset. + * @ha: Pointer to host adapter structure. + **/ +static int qla4010_soft_reset(struct scsi_qla_host *ha) +{ + uint32_t max_wait_time; + unsigned long flags = 0; + int status = QLA_ERROR; + uint32_t ctrl_status; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* + * If the SCSI Reset Interrupt bit is set, clear it. + * Otherwise, the Soft Reset won't work. + */ + ctrl_status = readw(&ha->reg->ctrl_status); + if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) + writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); + + /* Issue Soft Reset */ + writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* Wait until the Network Reset Intr bit is cleared */ + max_wait_time = RESET_INTR_TOV; + do { + spin_lock_irqsave(&ha->hardware_lock, flags); + ctrl_status = readw(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if ((ctrl_status & CSR_NET_RESET_INTR) == 0) + break; + + msleep(1000); + } while ((--max_wait_time)); + + if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { + DEBUG2(printk(KERN_WARNING + "scsi%ld: Network Reset Intr not cleared by " + "Network function, clearing it now!\n", + ha->host_no)); + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + + /* Wait until the firmware tells us the Soft Reset is done */ + max_wait_time = SOFT_RESET_TOV; + do { + spin_lock_irqsave(&ha->hardware_lock, flags); + ctrl_status = readw(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if ((ctrl_status & CSR_SOFT_RESET) == 0) { + status = QLA_SUCCESS; + break; + } + + msleep(1000); + } while ((--max_wait_time)); + + /* + * Also, make sure that the SCSI Reset Interrupt bit has been cleared + * after the soft reset has taken place. + */ + spin_lock_irqsave(&ha->hardware_lock, flags); + ctrl_status = readw(&ha->reg->ctrl_status); + if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { + writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* If soft reset fails then most probably the bios on other + * function is also enabled. + * Since the initialization is sequential the other fn + * wont be able to acknowledge the soft reset. + * Issue a force soft reset to workaround this scenario. + */ + if (max_wait_time == 0) { + /* Issue Force Soft Reset */ + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Wait until the firmware tells us the Soft Reset is done */ + max_wait_time = SOFT_RESET_TOV; + do { + spin_lock_irqsave(&ha->hardware_lock, flags); + ctrl_status = readw(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { + status = QLA_SUCCESS; + break; + } + + msleep(1000); + } while ((--max_wait_time)); + } + + return status; +} + +/** + * qla4xxx_topcat_reset - performs hard reset of TopCat Chip. + * @ha: Pointer to host adapter structure. + **/ +static int qla4xxx_topcat_reset(struct scsi_qla_host *ha) +{ + unsigned long flags; + + ql4xxx_lock_nvram(ha); + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(set_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha)); + readl(isp_gp_out(ha)); + mdelay(1); + + writel(clr_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha)); + readl(isp_gp_out(ha)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + mdelay(2523); + + ql4xxx_unlock_nvram(ha); + return QLA_SUCCESS; +} + +/** + * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S. + * @ha: Pointer to host adapter structure. + * + * This routine is called just prior to a HARD RESET to return all + * outstanding commands back to the Operating System. + * Caller should make sure that the following locks are released + * before this calling routine: Hardware lock, and io_request_lock. + **/ +static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) +{ + struct srb *srb; + int i; + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (i = 0; i < ha->host->can_queue; i++) { + srb = qla4xxx_del_from_active_array(ha, i); + if (srb != NULL) { + srb->cmd->result = DID_RESET << 16; + qla4xxx_srb_compl(ha, srb); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + +} + +/** + * qla4xxx_hard_reset - performs HBA Hard Reset + * @ha: Pointer to host adapter structure. + **/ +static int qla4xxx_hard_reset(struct scsi_qla_host *ha) +{ + /* The QLA4010 really doesn't have an equivalent to a hard reset */ + qla4xxx_flush_active_srbs(ha); + if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) { + int status = QLA_ERROR; + + if ((qla4010_soft_reset(ha) == QLA_SUCCESS) && + (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) && + (qla4010_soft_reset(ha) == QLA_SUCCESS)) + status = QLA_SUCCESS; + return status; + } else + return qla4010_soft_reset(ha); +} + +/** + * qla4xxx_recover_adapter - recovers adapter after a fatal error + * @ha: Pointer to host adapter structure. + * @renew_ddb_list: Indicates what to do with the adapter's ddb list + * after adapter recovery has completed. + * 0=preserve ddb list, 1=destroy and rebuild ddb list + **/ +static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, + uint8_t renew_ddb_list) +{ + int status; + + /* Stall incoming I/O until we are done */ + clear_bit(AF_ONLINE, &ha->flags); + DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, + __func__)); + + /* Wait for outstanding commands to complete. + * Stalls the driver for max 30 secs + */ + status = qla4xxx_cmd_wait(ha); + + qla4xxx_disable_intrs(ha); + + /* Flush any pending ddb changed AENs */ + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + + /* Reset the firmware. If successful, function + * returns with ISP interrupts enabled. + */ + if (status == QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n", + ha->host_no, __func__)); + status = qla4xxx_soft_reset(ha); + } + /* FIXMEkaren: Do we want to keep interrupts enabled and process + AENs after soft reset */ + + /* If firmware (SOFT) reset failed, or if all outstanding + * commands have not returned, then do a HARD reset. + */ + if (status == QLA_ERROR) { + DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n", + ha->host_no, __func__)); + status = qla4xxx_hard_reset(ha); + } + + /* Flush any pending ddb changed AENs */ + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + + /* Re-initialize firmware. If successful, function returns + * with ISP interrupts enabled */ + if (status == QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n", + ha->host_no, __func__)); + + /* If successful, AF_ONLINE flag set in + * qla4xxx_initialize_adapter */ + status = qla4xxx_initialize_adapter(ha, renew_ddb_list); + } + + /* Failed adapter initialization? + * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */ + if ((test_bit(AF_ONLINE, &ha->flags) == 0) && + (test_bit(DPC_RESET_HA, &ha->dpc_flags))) { + /* Adapter initialization failed, see if we can retry + * resetting the ha */ + if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { + ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; + DEBUG2(printk("scsi%ld: recover adapter - retrying " + "(%d) more times\n", ha->host_no, + ha->retry_reset_ha_cnt)); + set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); + status = QLA_ERROR; + } else { + if (ha->retry_reset_ha_cnt > 0) { + /* Schedule another Reset HA--DPC will retry */ + ha->retry_reset_ha_cnt--; + DEBUG2(printk("scsi%ld: recover adapter - " + "retry remaining %d\n", + ha->host_no, + ha->retry_reset_ha_cnt)); + status = QLA_ERROR; + } + + if (ha->retry_reset_ha_cnt == 0) { + /* Recover adapter retries have been exhausted. + * Adapter DEAD */ + DEBUG2(printk("scsi%ld: recover adapter " + "failed - board disabled\n", + ha->host_no)); + qla4xxx_flush_active_srbs(ha); + clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, + &ha->dpc_flags); + status = QLA_ERROR; + } + } + } else { + clear_bit(DPC_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags); + clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); + } + + ha->adapter_error_count++; + + if (status == QLA_SUCCESS) + qla4xxx_enable_intrs(ha); + + DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no)); + return status; +} + +/** + * qla4xxx_do_dpc - dpc routine + * @data: in our case pointer to adapter structure + * + * This routine is a task that is schedule by the interrupt handler + * to perform the background processing for interrupts. We put it + * on a task queue that is consumed whenever the scheduler runs; that's + * so you can do anything (i.e. put the process to sleep etc). In fact, + * 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) +{ + struct scsi_qla_host *ha = (struct scsi_qla_host *) data; + struct ddb_entry *ddb_entry, *dtemp; + + DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n", + ha->host_no, __func__)); + + DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n", + ha->host_no, __func__, ha->flags)); + DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n", + ha->host_no, __func__, ha->dpc_flags)); + + /* Initialization not yet finished. Don't do anything yet. */ + if (!test_bit(AF_INIT_DONE, &ha->flags)) + return; + + if (adapter_up(ha) || + test_bit(DPC_RESET_HA, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { + if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) + /* + * dg 09/23 Never initialize ddb list + * once we up and running + * qla4xxx_recover_adapter(ha, + * REBUILD_DDB_LIST); + */ + qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); + + if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) + qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); + + if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { + uint8_t wait_time = RESET_INTR_TOV; + unsigned long flags = 0; + + qla4xxx_flush_active_srbs(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + while ((readw(&ha->reg->ctrl_status) & + (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { + if (--wait_time == 0) + break; + + spin_unlock_irqrestore(&ha->hardware_lock, + flags); + + msleep(1000); + + spin_lock_irqsave(&ha->hardware_lock, flags); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (wait_time == 0) + DEBUG2(printk("scsi%ld: %s: SR|FSR " + "bit not cleared-- resetting\n", + ha->host_no, __func__)); + } + } + + /* ---- process AEN? --- */ + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) + qla4xxx_process_aen(ha, PROCESS_ALL_AENS); + + /* ---- Get DHCP IP Address? --- */ + if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) + qla4xxx_get_dhcp_ip_address(ha); + + /* ---- relogin device? --- */ + if (adapter_up(ha) && + test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { + list_for_each_entry_safe(ddb_entry, dtemp, + &ha->ddb_list, list) { + if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && + atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) + qla4xxx_relogin_device(ha, ddb_entry); + + /* + * If mbx cmd times out there is no point + * in continuing further. + * With large no of targets this can hang + * the system. + */ + if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + printk(KERN_WARNING "scsi%ld: %s: " + "need to reset hba\n", + ha->host_no, __func__); + break; + } + } + } +} + +/** + * qla4xxx_free_adapter - release the adapter + * @ha: pointer to adapter structure + **/ +static void qla4xxx_free_adapter(struct scsi_qla_host *ha) +{ + + if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { + /* Turn-off interrupts on the card. */ + qla4xxx_disable_intrs(ha); + } + + /* Kill the kernel thread for this host */ + if (ha->dpc_thread) + destroy_workqueue(ha->dpc_thread); + + /* Issue Soft Reset to put firmware in unknown state */ + qla4xxx_soft_reset(ha); + + /* Remove timer thread, if present */ + if (ha->timer_active) + qla4xxx_stop_timer(ha); + + /* free extra memory */ + qla4xxx_mem_free(ha); + + /* Detach interrupts */ + if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) + free_irq(ha->pdev->irq, ha); + + pci_disable_device(ha->pdev); + +} + +/*** + * qla4xxx_iospace_config - maps registers + * @ha: pointer to adapter structure + * + * This routines maps HBA's registers from the pci address space + * into the kernel virtual address space for memory mapped i/o. + **/ +static int qla4xxx_iospace_config(struct scsi_qla_host *ha) +{ + unsigned long pio, pio_len, pio_flags; + unsigned long mmio, mmio_len, mmio_flags; + + pio = pci_resource_start(ha->pdev, 0); + pio_len = pci_resource_len(ha->pdev, 0); + pio_flags = pci_resource_flags(ha->pdev, 0); + if (pio_flags & IORESOURCE_IO) { + if (pio_len < MIN_IOBASE_LEN) { + dev_warn(&ha->pdev->dev, + "Invalid PCI I/O region size\n"); + pio = 0; + } + } else { + dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n"); + pio = 0; + } + + /* Use MMIO operations for all accesses. */ + mmio = pci_resource_start(ha->pdev, 1); + mmio_len = pci_resource_len(ha->pdev, 1); + mmio_flags = pci_resource_flags(ha->pdev, 1); + + if (!(mmio_flags & IORESOURCE_MEM)) { + dev_err(&ha->pdev->dev, + "region #0 not an MMIO resource, aborting\n"); + + goto iospace_error_exit; + } + if (mmio_len < MIN_IOBASE_LEN) { + dev_err(&ha->pdev->dev, + "Invalid PCI mem region size, aborting\n"); + goto iospace_error_exit; + } + + if (pci_request_regions(ha->pdev, DRIVER_NAME)) { + dev_warn(&ha->pdev->dev, + "Failed to reserve PIO/MMIO regions\n"); + + goto iospace_error_exit; + } + + ha->pio_address = pio; + ha->pio_length = pio_len; + ha->reg = ioremap(mmio, MIN_IOBASE_LEN); + if (!ha->reg) { + dev_err(&ha->pdev->dev, + "cannot remap MMIO, aborting\n"); + + goto iospace_error_exit; + } + + return 0; + +iospace_error_exit: + return -ENOMEM; +} + +/** + * qla4xxx_probe_adapter - callback function to probe HBA + * @pdev: pointer to pci_dev structure + * @pci_device_id: pointer to pci_device entry + * + * This routine will probe for Qlogic 4xxx iSCSI host adapters. + * It returns zero if successful. It also initializes all data necessary for + * the driver. + **/ +static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret = -ENODEV, status; + struct Scsi_Host *host; + struct scsi_qla_host *ha; + struct ddb_entry *ddb_entry, *ddbtemp; + uint8_t init_retry_count = 0; + char buf[34]; + + if (pci_enable_device(pdev)) + return -1; + + host = scsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha)); + if (host == NULL) { + printk(KERN_WARNING + "qla4xxx: Couldn't allocate host from scsi layer!\n"); + goto probe_disable_device; + } + + /* Clear our data area */ + ha = (struct scsi_qla_host *) host->hostdata; + memset(ha, 0, sizeof(*ha)); + + /* Save the information from PCI BIOS. */ + ha->pdev = pdev; + ha->host = host; + ha->host_no = host->host_no; + + /* Configure PCI I/O space. */ + ret = qla4xxx_iospace_config(ha); + if (ret) + goto probe_failed; + + dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n", + pdev->device, pdev->irq, ha->reg); + + qla4xxx_config_dma_addressing(ha); + + /* Initialize lists and spinlocks. */ + INIT_LIST_HEAD(&ha->ddb_list); + INIT_LIST_HEAD(&ha->free_srb_q); + + mutex_init(&ha->mbox_sem); + init_waitqueue_head(&ha->mailbox_wait_queue); + + spin_lock_init(&ha->hardware_lock); + spin_lock_init(&ha->list_lock); + + /* Allocate dma buffers */ + if (qla4xxx_mem_alloc(ha)) { + dev_warn(&ha->pdev->dev, + "[ERROR] Failed to allocate memory for adapter\n"); + + ret = -ENOMEM; + goto probe_failed; + } + + /* + * Initialize the Host adapter request/response queues and + * firmware + * NOTE: interrupts enabled upon successful completion + */ + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); + while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) { + DEBUG2(printk("scsi: %s: retrying adapter initialization " + "(%d)\n", __func__, init_retry_count)); + qla4xxx_soft_reset(ha); + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); + } + if (status == QLA_ERROR) { + dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n"); + + ret = -ENODEV; + goto probe_failed; + } + + host->cmd_per_lun = 3; + host->max_channel = 0; + host->max_lun = MAX_LUNS - 1; + host->max_id = MAX_TARGETS; + host->max_cmd_len = IOCB_MAX_CDB_LEN; + host->can_queue = MAX_SRBS ; + host->transportt = qla4xxx_scsi_transport; + + ret = scsi_init_shared_tag_map(host, MAX_SRBS); + if (ret) { + dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed"); + goto probe_failed; + } + + /* Startup the kernel thread for this host adapter. */ + DEBUG2(printk("scsi: %s: Starting kernel thread for " + "qla4xxx_dpc\n", __func__)); + sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); + ha->dpc_thread = create_singlethread_workqueue(buf); + if (!ha->dpc_thread) { + dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n"); + ret = -ENODEV; + goto probe_failed; + } + INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc, ha); + + ret = request_irq(pdev->irq, qla4xxx_intr_handler, + SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha); + if (ret) { + dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" + " already in use.\n", pdev->irq); + goto probe_failed; + } + set_bit(AF_IRQ_ATTACHED, &ha->flags); + host->irq = pdev->irq; + DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq)); + + qla4xxx_enable_intrs(ha); + + /* Start timer thread. */ + qla4xxx_start_timer(ha, qla4xxx_timer, 1); + + set_bit(AF_INIT_DONE, &ha->flags); + + pci_set_drvdata(pdev, ha); + + ret = scsi_add_host(host, &pdev->dev); + if (ret) + goto probe_failed; + + /* Update transport device information for all devices. */ + list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) + if (qla4xxx_add_sess(ddb_entry)) + goto remove_host; + } + + printk(KERN_INFO + " QLogic iSCSI HBA Driver version: %s\n" + " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", + qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), + ha->host_no, ha->firmware_version[0], ha->firmware_version[1], + ha->patch_number, ha->build_number); + + return 0; + +remove_host: + qla4xxx_free_ddb_list(ha); + scsi_remove_host(host); + +probe_failed: + qla4xxx_free_adapter(ha); + scsi_host_put(ha->host); + +probe_disable_device: + pci_disable_device(pdev); + + return ret; +} + +/** + * qla4xxx_remove_adapter - calback function to remove adapter. + * @pci_dev: PCI device pointer + **/ +static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) +{ + struct scsi_qla_host *ha; + + ha = pci_get_drvdata(pdev); + + /* remove devs from iscsi_sessions to scsi_devices */ + qla4xxx_free_ddb_list(ha); + + scsi_remove_host(ha->host); + + qla4xxx_free_adapter(ha); + + scsi_host_put(ha->host); + + pci_set_drvdata(pdev, NULL); +} + +/** + * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. + * @ha: HA context + * + * At exit, the @ha's flags.enable_64bit_addressing set to indicated + * supported addressing method. + */ +void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) +{ + int retval; + + /* Update our PCI device dma_mask for full 64 bit mask */ + if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) { + if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { + dev_dbg(&ha->pdev->dev, + "Failed to set 64 bit PCI consistent mask; " + "using 32 bit.\n"); + retval = pci_set_consistent_dma_mask(ha->pdev, + DMA_32BIT_MASK); + } + } else + retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); +} + +static int qla4xxx_slave_alloc(struct scsi_device *sdev) +{ + struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); + struct ddb_entry *ddb = sess->dd_data; + + sdev->hostdata = ddb; + sdev->tagged_supported = 1; + scsi_activate_tcq(sdev, sdev->host->can_queue); + return 0; +} + +static int qla4xxx_slave_configure(struct scsi_device *sdev) +{ + sdev->tagged_supported = 1; + return 0; +} + +static void qla4xxx_slave_destroy(struct scsi_device *sdev) +{ + scsi_deactivate_tcq(sdev, 1); +} + +/** + * qla4xxx_del_from_active_array - returns an active srb + * @ha: Pointer to host adapter structure. + * @index: index into to the active_array + * + * This routine removes and returns the srb at the specified index + **/ +struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) +{ + struct srb *srb = NULL; + struct scsi_cmnd *cmd; + + if (!(cmd = scsi_host_find_tag(ha->host, index))) + return srb; + + if (!(srb = (struct srb *)cmd->host_scribble)) + return srb; + + /* update counters */ + if (srb->flags & SRB_DMA_VALID) { + ha->req_q_count += srb->iocb_cnt; + ha->iocb_cnt -= srb->iocb_cnt; + if (srb->cmd) + srb->cmd->host_scribble = NULL; + } + return srb; +} + +/** + * qla4xxx_soft_reset - performs a SOFT RESET of hba. + * @ha: Pointer to host adapter structure. + **/ +int qla4xxx_soft_reset(struct scsi_qla_host *ha) +{ + + DEBUG2(printk(KERN_WARNING "scsi%ld: %s: chip reset!\n", ha->host_no, + __func__)); + if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) { + int status = QLA_ERROR; + + if ((qla4010_soft_reset(ha) == QLA_SUCCESS) && + (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) && + (qla4010_soft_reset(ha) == QLA_SUCCESS) ) + status = QLA_SUCCESS; + return status; + } else + return qla4010_soft_reset(ha); +} + +/** + * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware + * @ha: actual ha whose done queue will contain the comd returned by firmware. + * @cmd: Scsi Command to wait on. + * + * This routine waits for the command to be returned by the Firmware + * for some max time. + **/ +static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, + struct scsi_cmnd *cmd) +{ + int done = 0; + struct srb *rp; + uint32_t max_wait_time = EH_WAIT_CMD_TOV; + + do { + /* Checking to see if its returned to OS */ + rp = (struct srb *) cmd->SCp.ptr; + if (rp == NULL) { + done++; + break; + } + + msleep(2000); + } while (max_wait_time--); + + return done; +} + +/** + * qla4xxx_wait_for_hba_online - waits for HBA to come online + * @ha: Pointer to host adapter structure + **/ +static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) +{ + unsigned long wait_online; + + wait_online = jiffies + (30 * HZ); + while (time_before(jiffies, wait_online)) { + + if (adapter_up(ha)) + return QLA_SUCCESS; + else if (ha->retry_reset_ha_cnt == 0) + return QLA_ERROR; + + msleep(2000); + } + + return QLA_ERROR; +} + +/** + * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. + * @ha: pointer to to HBA + * @t: target id + * @l: lun id + * + * This function waits for all outstanding commands to a lun to complete. It + * returns 0 if all pending commands are returned and 1 otherwise. + **/ +static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, + int t, int l) +{ + int cnt; + int status = 0; + struct scsi_cmnd *cmd; + + /* + * Waiting for all commands for the designated target in the active + * array + */ + for (cnt = 0; cnt < ha->host->can_queue; cnt++) { + cmd = scsi_host_find_tag(ha->host, cnt); + if (cmd && cmd->device->id == t && cmd->device->lun == l) { + if (!qla4xxx_eh_wait_on_command(ha, cmd)) { + status++; + break; + } + } + } + return status; +} + +/** + * qla4xxx_eh_device_reset - callback for target reset. + * @cmd: Pointer to Linux's SCSI command structure + * + * This routine is called by the Linux OS to reset all luns on the + * specified target. + **/ +static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) +{ + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; + struct srb *sp; + int ret = FAILED, stat; + + sp = (struct srb *) cmd->SCp.ptr; + if (!sp || !ddb_entry) + return ret; + + dev_info(&ha->pdev->dev, + "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, + cmd->device->channel, cmd->device->id, cmd->device->lun); + + DEBUG2(printk(KERN_INFO + "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," + "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, + cmd, jiffies, cmd->timeout_per_command / HZ, + ha->dpc_flags, cmd->result, cmd->allowed)); + + /* FIXME: wait for hba to go online */ + stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); + if (stat != QLA_SUCCESS) { + dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat); + goto eh_dev_reset_done; + } + + /* Send marker. */ + ha->marker_needed = 1; + + /* + * If we are coming down the EH path, wait for all commands to complete + * for the device. + */ + if (cmd->device->host->shost_state == SHOST_RECOVERY) { + if (qla4xxx_eh_wait_for_active_target_commands(ha, + cmd->device->id, + cmd->device->lun)){ + dev_info(&ha->pdev->dev, + "DEVICE RESET FAILED - waiting for " + "commands.\n"); + goto eh_dev_reset_done; + } + } + + dev_info(&ha->pdev->dev, + "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", + ha->host_no, cmd->device->channel, cmd->device->id, + cmd->device->lun); + + ret = SUCCESS; + +eh_dev_reset_done: + + return ret; +} + +/** + * qla4xxx_eh_host_reset - kernel callback + * @cmd: Pointer to Linux's SCSI command structure + * + * This routine is invoked by the Linux kernel to perform fatal error + * recovery on the specified adapter. + **/ +static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) +{ + int return_status = FAILED; + struct scsi_qla_host *ha; + + ha = (struct scsi_qla_host *) cmd->device->host->hostdata; + + dev_info(&ha->pdev->dev, + "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, + cmd->device->channel, cmd->device->id, cmd->device->lun); + + if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { + DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " + "DEAD.\n", ha->host_no, cmd->device->channel, + __func__)); + + return FAILED; + } + + if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) { + return_status = SUCCESS; + } + + dev_info(&ha->pdev->dev, "HOST RESET %s.\n", + return_status == FAILED ? "FAILED" : "SUCCEDED"); + + return return_status; +} + + +static struct pci_device_id qla4xxx_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP4010, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP4022, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + {0, 0}, +}; +MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); + +struct pci_driver qla4xxx_pci_driver = { + .name = DRIVER_NAME, + .id_table = qla4xxx_pci_tbl, + .probe = qla4xxx_probe_adapter, + .remove = qla4xxx_remove_adapter, +}; + +static int __init qla4xxx_module_init(void) +{ + int ret; + + /* Allocate cache for SRBs. */ + srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (srb_cachep == NULL) { + printk(KERN_ERR + "%s: Unable to allocate SRB cache..." + "Failing load!\n", DRIVER_NAME); + ret = -ENOMEM; + goto no_srp_cache; + } + + /* Derive version string. */ + strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); + if (extended_error_logging) + strcat(qla4xxx_version_str, "-debug"); + + qla4xxx_scsi_transport = + iscsi_register_transport(&qla4xxx_iscsi_transport); + if (!qla4xxx_scsi_transport){ + ret = -ENODEV; + goto release_srb_cache; + } + + printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); + ret = pci_register_driver(&qla4xxx_pci_driver); + if (ret) + goto unregister_transport; + + printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); + return 0; +unregister_transport: + iscsi_unregister_transport(&qla4xxx_iscsi_transport); +release_srb_cache: + kmem_cache_destroy(srb_cachep); +no_srp_cache: + return ret; +} + +static void __exit qla4xxx_module_exit(void) +{ + pci_unregister_driver(&qla4xxx_pci_driver); + iscsi_unregister_transport(&qla4xxx_iscsi_transport); + kmem_cache_destroy(srb_cachep); +} + +module_init(qla4xxx_module_init); +module_exit(qla4xxx_module_exit); + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA4XXX_DRIVER_VERSION); diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h new file mode 100644 index 00000000000..b3fe7e68988 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -0,0 +1,13 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k" + +#define QL4_DRIVER_MAJOR_VER 5 +#define QL4_DRIVER_MINOR_VER 0 +#define QL4_DRIVER_PATCH_VER 5 +#define QL4_DRIVER_BETA_VER 9 -- GitLab From 27d5bf2a35c0762f1358e9ef39776733cd942121 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 4 Oct 2006 17:26:11 +0200 Subject: [PATCH 0627/1619] [POWERPC] spufs: cell spu problem state mapping updates This patch adds a new "psmap" file to spufs that allows mmap of all of the problem state mapping of SPEs. It is compatible with 64k pages. In addition, it removes mmap ability of individual files when using 64k pages, with the exception of signal1 and signal2 which will both map the entire 64k page holding both registers. It also removes CONFIG_SPUFS_MMAP as there is no point in not building mmap support in spufs. It goes along a separate patch to libspe implementing usage of that new file to access problem state registers. Another patch will follow up to fix races opened up by accessing the 'runcntl' register directly, which is made possible with this patch. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/Kconfig | 5 - arch/powerpc/platforms/cell/spufs/file.c | 130 +++++++++++++++-------- 2 files changed, 84 insertions(+), 51 deletions(-) diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 0c8c7b6ab89..3e430b489bb 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -16,11 +16,6 @@ config SPU_BASE bool default n -config SPUFS_MMAP - bool - depends on SPU_FS && SPARSEMEM - default y - config CBE_RAS bool "RAS features for bare metal Cell BE" default y diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 51fd197ab5d..64f8b0a9b9e 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -36,6 +36,8 @@ #include "spufs.h" +#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) + static int spufs_mem_open(struct inode *inode, struct file *file) @@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const char __user *buffer, return ret; } -#ifdef CONFIG_SPUFS_MMAP static struct page * spufs_mem_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) @@ -133,22 +134,19 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &spufs_mem_mmap_vmops; return 0; } -#endif static struct file_operations spufs_mem_fops = { .open = spufs_mem_open, .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, -#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_mem_mmap, -#endif }; -#ifdef CONFIG_SPUFS_MMAP static struct page *spufs_ps_nopage(struct vm_area_struct *vma, unsigned long address, - int *type, unsigned long ps_offs) + int *type, unsigned long ps_offs, + unsigned long ps_size) { struct page *page = NOPAGE_SIGBUS; int fault_type = VM_FAULT_SIGBUS; @@ -158,7 +156,7 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma, int ret; offset += vma->vm_pgoff << PAGE_SHIFT; - if (offset >= 0x4000) + if (offset >= ps_size) goto out; ret = spu_acquire_runnable(ctx); @@ -179,10 +177,11 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma, return page; } +#if SPUFS_MMAP_4K static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { - return spufs_ps_nopage(vma, address, type, 0x4000); + return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); } static struct vm_operations_struct spufs_cntl_mmap_vmops = { @@ -191,17 +190,12 @@ static struct vm_operations_struct spufs_cntl_mmap_vmops = { /* * mmap support for problem state control area [0x4000 - 0x4fff]. - * Mapping this area requires that the application have CAP_SYS_RAWIO, - * as these registers require special care when read/writing. */ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) { if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - vma->vm_flags |= VM_RESERVED; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -209,7 +203,9 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &spufs_cntl_mmap_vmops; return 0; } -#endif +#else /* SPUFS_MMAP_4K */ +#define spufs_cntl_mmap NULL +#endif /* !SPUFS_MMAP_4K */ static int spufs_cntl_open(struct inode *inode, struct file *file) { @@ -242,9 +238,7 @@ static struct file_operations spufs_cntl_fops = { .open = spufs_cntl_open, .read = spufs_cntl_read, .write = spufs_cntl_write, -#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_cntl_mmap, -#endif }; static int @@ -657,11 +651,19 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, return 4; } -#ifdef CONFIG_SPUFS_MMAP static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { - return spufs_ps_nopage(vma, address, type, 0x14000); +#if PAGE_SIZE == 0x1000 + return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); +#elif PAGE_SIZE == 0x10000 + /* For 64k pages, both signal1 and signal2 can be used to mmap the whole + * signal 1 and 2 area + */ + return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); +#else +#error unsupported page size +#endif } static struct vm_operations_struct spufs_signal1_mmap_vmops = { @@ -680,15 +682,12 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &spufs_signal1_mmap_vmops; return 0; } -#endif static struct file_operations spufs_signal1_fops = { .open = spufs_signal1_open, .read = spufs_signal1_read, .write = spufs_signal1_write, -#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_signal1_mmap, -#endif }; static int spufs_signal2_open(struct inode *inode, struct file *file) @@ -743,11 +742,20 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, return 4; } -#ifdef CONFIG_SPUFS_MMAP +#if SPUFS_MMAP_4K static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { - return spufs_ps_nopage(vma, address, type, 0x1c000); +#if PAGE_SIZE == 0x1000 + return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); +#elif PAGE_SIZE == 0x10000 + /* For 64k pages, both signal1 and signal2 can be used to mmap the whole + * signal 1 and 2 area + */ + return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); +#else +#error unsupported page size +#endif } static struct vm_operations_struct spufs_signal2_mmap_vmops = { @@ -767,15 +775,15 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &spufs_signal2_mmap_vmops; return 0; } -#endif +#else /* SPUFS_MMAP_4K */ +#define spufs_signal2_mmap NULL +#endif /* !SPUFS_MMAP_4K */ static struct file_operations spufs_signal2_fops = { .open = spufs_signal2_open, .read = spufs_signal2_read, .write = spufs_signal2_write, -#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_signal2_mmap, -#endif }; static void spufs_signal1_type_set(void *data, u64 val) @@ -824,11 +832,11 @@ static u64 spufs_signal2_type_get(void *data) DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, spufs_signal2_type_set, "%llu"); -#ifdef CONFIG_SPUFS_MMAP +#if SPUFS_MMAP_4K static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { - return spufs_ps_nopage(vma, address, type, 0x0000); + return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); } static struct vm_operations_struct spufs_mss_mmap_vmops = { @@ -837,17 +845,12 @@ static struct vm_operations_struct spufs_mss_mmap_vmops = { /* * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. - * Mapping this area requires that the application have CAP_SYS_RAWIO, - * as these registers require special care when read/writing. */ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) { if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - vma->vm_flags |= VM_RESERVED; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -855,7 +858,9 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &spufs_mss_mmap_vmops; return 0; } -#endif +#else /* SPUFS_MMAP_4K */ +#define spufs_mss_mmap NULL +#endif /* !SPUFS_MMAP_4K */ static int spufs_mss_open(struct inode *inode, struct file *file) { @@ -867,17 +872,54 @@ static int spufs_mss_open(struct inode *inode, struct file *file) static struct file_operations spufs_mss_fops = { .open = spufs_mss_open, -#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_mss_mmap, -#endif +}; + +static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); +} + +static struct vm_operations_struct spufs_psmap_mmap_vmops = { + .nopage = spufs_psmap_mmap_nopage, +}; + +/* + * mmap support for full problem state area [0x00000 - 0x1ffff]. + */ +static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE | _PAGE_GUARDED); + + vma->vm_ops = &spufs_psmap_mmap_vmops; + return 0; +} + +static int spufs_psmap_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + + file->private_data = i->i_ctx; + return nonseekable_open(inode, file); +} + +static struct file_operations spufs_psmap_fops = { + .open = spufs_psmap_open, + .mmap = spufs_psmap_mmap, }; -#ifdef CONFIG_SPUFS_MMAP +#if SPUFS_MMAP_4K static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { - return spufs_ps_nopage(vma, address, type, 0x3000); + return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); } static struct vm_operations_struct spufs_mfc_mmap_vmops = { @@ -886,17 +928,12 @@ static struct vm_operations_struct spufs_mfc_mmap_vmops = { /* * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. - * Mapping this area requires that the application have CAP_SYS_RAWIO, - * as these registers require special care when read/writing. */ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) { if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - vma->vm_flags |= VM_RESERVED; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -904,7 +941,9 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &spufs_mfc_mmap_vmops; return 0; } -#endif +#else /* SPUFS_MMAP_4K */ +#define spufs_mfc_mmap NULL +#endif /* !SPUFS_MMAP_4K */ static int spufs_mfc_open(struct inode *inode, struct file *file) { @@ -1194,9 +1233,7 @@ static struct file_operations spufs_mfc_fops = { .flush = spufs_mfc_flush, .fsync = spufs_mfc_fsync, .fasync = spufs_mfc_fasync, -#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_mfc_mmap, -#endif }; static void spufs_npc_set(void *data, u64 val) @@ -1368,5 +1405,6 @@ struct tree_descr spufs_dir_contents[] = { { "event_mask", &spufs_event_mask_ops, 0666, }, { "srr0", &spufs_srr0_ops, 0666, }, { "phys-id", &spufs_id_ops, 0666, }, + { "psmap", &spufs_psmap_fops, 0666, }, {}, }; -- GitLab From a68cf983f635930ea35f9e96b27d96598550dea0 Mon Sep 17 00:00:00 2001 From: Mark Nutter Date: Wed, 4 Oct 2006 17:26:12 +0200 Subject: [PATCH 0628/1619] [POWERPC] spufs: scheduler support for NUMA. This patch adds NUMA support to the the spufs scheduler. The new arch/powerpc/platforms/cell/spufs/sched.c is greatly simplified, in an attempt to reduce complexity while adding support for NUMA scheduler domains. SPUs are allocated starting from the calling thread's node, moving to others as supported by current->cpus_allowed. Preemption is gone as it was buggy, but should be re-enabled in another patch when stable. The new arch/powerpc/platforms/cell/spu_base.c maintains idle lists on a per-node basis, and allows caller to specify which node(s) an SPU should be allocated from, while passing -1 tells spu_alloc() that any node is allowed. Since the patch removes the currently implemented preemptive scheduling, it is technically a regression, but practically all users have since migrated to this version, as it is part of the IBM SDK and the yellowdog distribution, so there is not much point holding it back while the new preemptive scheduling patch gets delayed further. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 51 ++- arch/powerpc/platforms/cell/spufs/sched.c | 444 ++++++++-------------- include/asm-powerpc/spu.h | 1 + 3 files changed, 198 insertions(+), 298 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index f78680346e5..5931973845b 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -317,7 +317,7 @@ static void spu_free_irqs(struct spu *spu) free_irq(spu->irqs[2], spu); } -static LIST_HEAD(spu_list); +static struct list_head spu_list[MAX_NUMNODES]; static DEFINE_MUTEX(spu_mutex); static void spu_init_channels(struct spu *spu) @@ -354,32 +354,42 @@ static void spu_init_channels(struct spu *spu) } } -struct spu *spu_alloc(void) +struct spu *spu_alloc_node(int node) { - struct spu *spu; + struct spu *spu = NULL; mutex_lock(&spu_mutex); - if (!list_empty(&spu_list)) { - spu = list_entry(spu_list.next, struct spu, list); + if (!list_empty(&spu_list[node])) { + spu = list_entry(spu_list[node].next, struct spu, list); list_del_init(&spu->list); - pr_debug("Got SPU %x %d\n", spu->isrc, spu->number); - } else { - pr_debug("No SPU left\n"); - spu = NULL; + pr_debug("Got SPU %x %d %d\n", + spu->isrc, spu->number, spu->node); + spu_init_channels(spu); } mutex_unlock(&spu_mutex); - if (spu) - spu_init_channels(spu); + return spu; +} +EXPORT_SYMBOL_GPL(spu_alloc_node); + +struct spu *spu_alloc(void) +{ + struct spu *spu = NULL; + int node; + + for (node = 0; node < MAX_NUMNODES; node++) { + spu = spu_alloc_node(node); + if (spu) + break; + } return spu; } -EXPORT_SYMBOL_GPL(spu_alloc); void spu_free(struct spu *spu) { mutex_lock(&spu_mutex); - list_add_tail(&spu->list, &spu_list); + list_add_tail(&spu->list, &spu_list[spu->node]); mutex_unlock(&spu_mutex); } EXPORT_SYMBOL_GPL(spu_free); @@ -712,7 +722,7 @@ static int __init create_spu(struct device_node *spe) if (ret) goto out_free_irqs; - list_add(&spu->list, &spu_list); + list_add(&spu->list, &spu_list[spu->node]); mutex_unlock(&spu_mutex); pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n", @@ -745,9 +755,13 @@ static void destroy_spu(struct spu *spu) static void cleanup_spu_base(void) { struct spu *spu, *tmp; + int node; + mutex_lock(&spu_mutex); - list_for_each_entry_safe(spu, tmp, &spu_list, list) - destroy_spu(spu); + for (node = 0; node < MAX_NUMNODES; node++) { + list_for_each_entry_safe(spu, tmp, &spu_list[node], list) + destroy_spu(spu); + } mutex_unlock(&spu_mutex); sysdev_class_unregister(&spu_sysdev_class); } @@ -756,13 +770,16 @@ module_exit(cleanup_spu_base); static int __init init_spu_base(void) { struct device_node *node; - int ret; + int i, ret; /* create sysdev class for spus */ ret = sysdev_class_register(&spu_sysdev_class); if (ret) return ret; + for (i = 0; i < MAX_NUMNODES; i++) + INIT_LIST_HEAD(&spu_list[i]); + ret = -ENODEV; for (node = of_find_node_by_type(NULL, "spe"); node; node = of_find_node_by_type(node, "spe")) { diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 1350294484b..bd4e2c3d5d0 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -3,11 +3,7 @@ * Copyright (C) IBM 2005 * Author: Mark Nutter * - * SPU scheduler, based on Linux thread priority. For now use - * a simple "cooperative" yield model with no preemption. SPU - * scheduling will eventually be preemptive: When a thread with - * a higher static priority gets ready to run, then an active SPU - * context will be preempted and returned to the waitq. + * 2006-03-31 NUMA domains added. * * 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 @@ -37,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -49,125 +47,38 @@ #define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) struct spu_prio_array { - atomic_t nr_blocked; unsigned long bitmap[SPU_BITMAP_SIZE]; wait_queue_head_t waitq[MAX_PRIO]; + struct list_head active_list[MAX_NUMNODES]; + struct mutex active_mutex[MAX_NUMNODES]; }; -/* spu_runqueue - This is the main runqueue data structure for SPUs. */ -struct spu_runqueue { - struct semaphore sem; - unsigned long nr_active; - unsigned long nr_idle; - unsigned long nr_switches; - struct list_head active_list; - struct list_head idle_list; - struct spu_prio_array prio; -}; - -static struct spu_runqueue *spu_runqueues = NULL; - -static inline struct spu_runqueue *spu_rq(void) -{ - /* Future: make this a per-NODE array, - * and use cpu_to_node(smp_processor_id()) - */ - return spu_runqueues; -} - -static inline struct spu *del_idle(struct spu_runqueue *rq) -{ - struct spu *spu; - - BUG_ON(rq->nr_idle <= 0); - BUG_ON(list_empty(&rq->idle_list)); - /* Future: Move SPU out of low-power SRI state. */ - spu = list_entry(rq->idle_list.next, struct spu, sched_list); - list_del_init(&spu->sched_list); - rq->nr_idle--; - return spu; -} - -static inline void del_active(struct spu_runqueue *rq, struct spu *spu) -{ - BUG_ON(rq->nr_active <= 0); - BUG_ON(list_empty(&rq->active_list)); - list_del_init(&spu->sched_list); - rq->nr_active--; -} - -static inline void add_idle(struct spu_runqueue *rq, struct spu *spu) -{ - /* Future: Put SPU into low-power SRI state. */ - list_add_tail(&spu->sched_list, &rq->idle_list); - rq->nr_idle++; -} - -static inline void add_active(struct spu_runqueue *rq, struct spu *spu) -{ - rq->nr_active++; - rq->nr_switches++; - list_add_tail(&spu->sched_list, &rq->active_list); -} - -static void prio_wakeup(struct spu_runqueue *rq) -{ - if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) { - int best = sched_find_first_bit(rq->prio.bitmap); - if (best < MAX_PRIO) { - wait_queue_head_t *wq = &rq->prio.waitq[best]; - wake_up_interruptible_nr(wq, 1); - } - } -} - -static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx, - u64 flags) -{ - int prio = current->prio; - wait_queue_head_t *wq = &rq->prio.waitq[prio]; - DEFINE_WAIT(wait); - - __set_bit(prio, rq->prio.bitmap); - atomic_inc(&rq->prio.nr_blocked); - prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE); - if (!signal_pending(current)) { - up(&rq->sem); - up_write(&ctx->state_sema); - pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__, - current->pid, current->prio); - schedule(); - down_write(&ctx->state_sema); - down(&rq->sem); - } - finish_wait(wq, &wait); - atomic_dec(&rq->prio.nr_blocked); - if (!waitqueue_active(wq)) - __clear_bit(prio, rq->prio.bitmap); -} +static struct spu_prio_array *spu_prio; -static inline int is_best_prio(struct spu_runqueue *rq) +static inline int node_allowed(int node) { - int best_prio; + cpumask_t mask; - best_prio = sched_find_first_bit(rq->prio.bitmap); - return (current->prio < best_prio) ? 1 : 0; + if (!nr_cpus_node(node)) + return 0; + mask = node_to_cpumask(node); + if (!cpus_intersects(mask, current->cpus_allowed)) + return 0; + return 1; } static inline void mm_needs_global_tlbie(struct mm_struct *mm) { + int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1; + /* Global TLBIE broadcast required with SPEs. */ -#if (NR_CPUS > 1) - __cpus_setall(&mm->cpu_vm_mask, NR_CPUS); -#else - __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */ -#endif + __cpus_setall(&mm->cpu_vm_mask, nr); } static inline void bind_context(struct spu *spu, struct spu_context *ctx) { - pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid, - spu->number); + pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, + spu->number, spu->node); spu->ctx = ctx; spu->flags = 0; ctx->flags = 0; @@ -185,12 +96,13 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) spu_unmap_mappings(ctx); spu_restore(&ctx->csa, spu); spu->timestamp = jiffies; + spu_cpu_affinity_set(spu, raw_smp_processor_id()); } static inline void unbind_context(struct spu *spu, struct spu_context *ctx) { - pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__, - spu->pid, spu->number); + pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, + spu->pid, spu->number, spu->node); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); spu->timestamp = jiffies; @@ -209,163 +121,148 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) spu->ctx = NULL; } -static void spu_reaper(void *data) +static inline void spu_add_wq(wait_queue_head_t * wq, wait_queue_t * wait, + int prio) { - struct spu_context *ctx = data; - struct spu *spu; - - down_write(&ctx->state_sema); - spu = ctx->spu; - if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) { - if (atomic_read(&spu->rq->prio.nr_blocked)) { - pr_debug("%s: spu=%d\n", __func__, spu->number); - ctx->ops->runcntl_stop(ctx); - spu_deactivate(ctx); - wake_up_all(&ctx->stop_wq); - } else { - clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags); - } - } - up_write(&ctx->state_sema); - put_spu_context(ctx); + prepare_to_wait_exclusive(wq, wait, TASK_INTERRUPTIBLE); + set_bit(prio, spu_prio->bitmap); } -static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu) +static inline void spu_del_wq(wait_queue_head_t * wq, wait_queue_t * wait, + int prio) { - struct spu_context *ctx = get_spu_context(spu->ctx); - unsigned long now = jiffies; - unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE; - - set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags); - INIT_WORK(&ctx->reap_work, spu_reaper, ctx); - if (time_after(now, expire)) - schedule_work(&ctx->reap_work); - else - schedule_delayed_work(&ctx->reap_work, expire - now); -} + u64 flags; -static void check_preempt_active(struct spu_runqueue *rq) -{ - struct list_head *p; - struct spu *worst = NULL; - - list_for_each(p, &rq->active_list) { - struct spu *spu = list_entry(p, struct spu, sched_list); - struct spu_context *ctx = spu->ctx; - if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) { - if (!worst || (spu->prio > worst->prio)) { - worst = spu; - } - } - } - if (worst && (current->prio < worst->prio)) - schedule_spu_reaper(rq, worst); + __set_current_state(TASK_RUNNING); + + spin_lock_irqsave(&wq->lock, flags); + + remove_wait_queue_locked(wq, wait); + if (list_empty(&wq->task_list)) + clear_bit(prio, spu_prio->bitmap); + + spin_unlock_irqrestore(&wq->lock, flags); } -static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags) +static void spu_prio_wait(struct spu_context *ctx, u64 flags) { - struct spu_runqueue *rq; - struct spu *spu = NULL; + int prio = current->prio; + wait_queue_head_t *wq = &spu_prio->waitq[prio]; + DEFINE_WAIT(wait); - rq = spu_rq(); - down(&rq->sem); - for (;;) { - if (rq->nr_idle > 0) { - if (is_best_prio(rq)) { - /* Fall through. */ - spu = del_idle(rq); - break; - } else { - prio_wakeup(rq); - up(&rq->sem); - yield(); - if (signal_pending(current)) { - return NULL; - } - rq = spu_rq(); - down(&rq->sem); - continue; - } - } else { - check_preempt_active(rq); - prio_wait(rq, ctx, flags); - if (signal_pending(current)) { - prio_wakeup(rq); - spu = NULL; - break; - } - continue; - } + if (ctx->spu) + return; + + spu_add_wq(wq, &wait, prio); + + if (!signal_pending(current)) { + up_write(&ctx->state_sema); + pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__, + current->pid, current->prio); + schedule(); + down_write(&ctx->state_sema); } - up(&rq->sem); - return spu; + + spu_del_wq(wq, &wait, prio); } -static void put_idle_spu(struct spu *spu) +static void spu_prio_wakeup(void) { - struct spu_runqueue *rq = spu->rq; - - down(&rq->sem); - add_idle(rq, spu); - prio_wakeup(rq); - up(&rq->sem); + int best = sched_find_first_bit(spu_prio->bitmap); + if (best < MAX_PRIO) { + wait_queue_head_t *wq = &spu_prio->waitq[best]; + wake_up_interruptible_nr(wq, 1); + } } static int get_active_spu(struct spu *spu) { - struct spu_runqueue *rq = spu->rq; - struct list_head *p; + int node = spu->node; struct spu *tmp; int rc = 0; - down(&rq->sem); - list_for_each(p, &rq->active_list) { - tmp = list_entry(p, struct spu, sched_list); + mutex_lock(&spu_prio->active_mutex[node]); + list_for_each_entry(tmp, &spu_prio->active_list[node], list) { if (tmp == spu) { - del_active(rq, spu); + list_del_init(&spu->list); rc = 1; break; } } - up(&rq->sem); + mutex_unlock(&spu_prio->active_mutex[node]); return rc; } static void put_active_spu(struct spu *spu) { - struct spu_runqueue *rq = spu->rq; + int node = spu->node; + + mutex_lock(&spu_prio->active_mutex[node]); + list_add_tail(&spu->list, &spu_prio->active_list[node]); + mutex_unlock(&spu_prio->active_mutex[node]); +} + +static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags) +{ + struct spu *spu = NULL; + int node = cpu_to_node(raw_smp_processor_id()); + int n; + + for (n = 0; n < MAX_NUMNODES; n++, node++) { + node = (node < MAX_NUMNODES) ? node : 0; + if (!node_allowed(node)) + continue; + spu = spu_alloc_node(node); + if (spu) + break; + } + return spu; +} - down(&rq->sem); - add_active(rq, spu); - up(&rq->sem); +static inline struct spu *spu_get(struct spu_context *ctx, u64 flags) +{ + /* Future: spu_get_idle() if possible, + * otherwise try to preempt an active + * context. + */ + return spu_get_idle(ctx, flags); } -/* Lock order: - * spu_activate() & spu_deactivate() require the - * caller to have down_write(&ctx->state_sema). +/* The three externally callable interfaces + * for the scheduler begin here. * - * The rq->sem is breifly held (inside or outside a - * given ctx lock) for list management, but is never - * held during save/restore. + * spu_activate - bind a context to SPU, waiting as needed. + * spu_deactivate - unbind a context from its SPU. + * spu_yield - yield an SPU if others are waiting. */ int spu_activate(struct spu_context *ctx, u64 flags) { struct spu *spu; + int ret = 0; - if (ctx->spu) - return 0; - spu = get_idle_spu(ctx, flags); - if (!spu) - return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN; - bind_context(spu, ctx); - /* - * We're likely to wait for interrupts on the same - * CPU that we are now on, so send them here. - */ - spu_cpu_affinity_set(spu, raw_smp_processor_id()); - put_active_spu(spu); - return 0; + for (;;) { + if (ctx->spu) + return 0; + spu = spu_get(ctx, flags); + if (spu != NULL) { + if (ctx->spu != NULL) { + spu_free(spu); + spu_prio_wakeup(); + break; + } + bind_context(spu, ctx); + put_active_spu(spu); + break; + } + spu_prio_wait(ctx, flags); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + spu_prio_wakeup(); + break; + } + } + return ret; } void spu_deactivate(struct spu_context *ctx) @@ -378,8 +275,10 @@ void spu_deactivate(struct spu_context *ctx) return; needs_idle = get_active_spu(spu); unbind_context(spu, ctx); - if (needs_idle) - put_idle_spu(spu); + if (needs_idle) { + spu_free(spu); + spu_prio_wakeup(); + } } void spu_yield(struct spu_context *ctx) @@ -387,77 +286,60 @@ void spu_yield(struct spu_context *ctx) struct spu *spu; int need_yield = 0; - down_write(&ctx->state_sema); - spu = ctx->spu; - if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) { - pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number); - spu_deactivate(ctx); - ctx->state = SPU_STATE_SAVED; - need_yield = 1; - } else if (spu) { - spu->prio = MAX_PRIO; + if (down_write_trylock(&ctx->state_sema)) { + if ((spu = ctx->spu) != NULL) { + int best = sched_find_first_bit(spu_prio->bitmap); + if (best < MAX_PRIO) { + pr_debug("%s: yielding SPU %d NODE %d\n", + __FUNCTION__, spu->number, spu->node); + spu_deactivate(ctx); + ctx->state = SPU_STATE_SAVED; + need_yield = 1; + } else { + spu->prio = MAX_PRIO; + } + } + up_write(&ctx->state_sema); } - up_write(&ctx->state_sema); if (unlikely(need_yield)) yield(); } int __init spu_sched_init(void) { - struct spu_runqueue *rq; - struct spu *spu; int i; - rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL); - if (!rq) { - printk(KERN_WARNING "%s: Unable to allocate runqueues.\n", + spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); + if (!spu_prio) { + printk(KERN_WARNING "%s: Unable to allocate priority queue.\n", __FUNCTION__); return 1; } - memset(rq, 0, sizeof(struct spu_runqueue)); - init_MUTEX(&rq->sem); - INIT_LIST_HEAD(&rq->active_list); - INIT_LIST_HEAD(&rq->idle_list); - rq->nr_active = 0; - rq->nr_idle = 0; - rq->nr_switches = 0; - atomic_set(&rq->prio.nr_blocked, 0); for (i = 0; i < MAX_PRIO; i++) { - init_waitqueue_head(&rq->prio.waitq[i]); - __clear_bit(i, rq->prio.bitmap); + init_waitqueue_head(&spu_prio->waitq[i]); + __clear_bit(i, spu_prio->bitmap); } - __set_bit(MAX_PRIO, rq->prio.bitmap); - for (;;) { - spu = spu_alloc(); - if (!spu) - break; - pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number); - add_idle(rq, spu); - spu->rq = rq; - spu->timestamp = jiffies; - } - if (!rq->nr_idle) { - printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__); - kfree(rq); - return 1; + __set_bit(MAX_PRIO, spu_prio->bitmap); + for (i = 0; i < MAX_NUMNODES; i++) { + mutex_init(&spu_prio->active_mutex[i]); + INIT_LIST_HEAD(&spu_prio->active_list[i]); } return 0; } void __exit spu_sched_exit(void) { - struct spu_runqueue *rq = spu_rq(); - struct spu *spu; - - if (!rq) { - printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__); - return; - } - while (rq->nr_idle > 0) { - spu = del_idle(rq); - if (!spu) - break; - spu_free(spu); + struct spu *spu, *tmp; + int node; + + for (node = 0; node < MAX_NUMNODES; node++) { + mutex_lock(&spu_prio->active_mutex[node]); + list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node], + list) { + list_del_init(&spu->list); + spu_free(spu); + } + mutex_unlock(&spu_prio->active_mutex[node]); } - kfree(rq); + kfree(spu_prio); } diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index b42b53c40f5..f6c0a95e820 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -147,6 +147,7 @@ struct spu { }; struct spu *spu_alloc(void); +struct spu *spu_alloc_node(int node); void spu_free(struct spu *spu); int spu_irq_class_0_bottom(struct spu *spu); int spu_irq_class_1_bottom(struct spu *spu); -- GitLab From 28347bce8a837258e737873a55d31f2f424a6ea6 Mon Sep 17 00:00:00 2001 From: HyeonSeung Jang Date: Wed, 4 Oct 2006 17:26:13 +0200 Subject: [PATCH 0629/1619] [POWERPC] spufs: fix context switch during page fault For better explanation, I break down the page fault handling into steps: 1) There is a page fault caused by DMA operation initiated by SPU and DMA is suspended. 2) The interrupt handler 'spu_irq_class_1()/__spu_trap_data_map()' is called and it just wakes up the sleeping spe-manager thread. 3) by PPE scheduler, the corresponding bottom half, spu_irq_class_1_bottom() is called in process context and DMA is restarted. There can be a quite large time gap between 2) and 3) and I found the following problem: Between 2) and 3) If the context becomes unbound, 3) is not executed because when the spe-manager thread is awaken, the context is already saved. (This situation can happen, for example, when a high priority spe thread newly started in that time gap) But the actual problem is that the corresponding SPU context does not work even if it is bound again to a SPU. Besides I can see the following warning in mambo simulator when the context becomes unbound(in save_mfc_cmd()), i.e. when unbind() is called for the context after step 2) before 3) : 'WARNING: 61392752237: SPE2: MFC_CMD_QUEUE channel count of 15 is inconsistent with number of available DMA queue entries of 16' After I go through available documents, I found that the problem is because the suspended DMA is not restarted when it is bound again. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/switch.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 9d9d82dd32b..0f782ca662b 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -1779,6 +1779,15 @@ static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu) */ out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW); eieio(); + /* + * FIXME: this is to restart a DMA that we were processing + * before the save. better remember the fault information + * in the csa instead. + */ + if ((csa->priv2.mfc_control_RW & MFC_CNTL_SUSPEND_DMA_QUEUE_MASK)) { + out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); + eieio(); + } } static inline void enable_user_access(struct spu_state *csa, struct spu *spu) -- GitLab From 9add11daeee2f6d69f6b86237f197824332a4a3b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:14 +0200 Subject: [PATCH 0630/1619] [POWERPC] spufs: implement error event delivery to user space This tries to fix spufs so we have an interface closer to what is specified in the man page for events returned in the third argument of spu_run. Fortunately, libspe has never been using the returned contents of that register, as they were the same as the return code of spu_run (duh!). Unlike the specification that we never implemented correctly, we now require a SPU_CREATE_EVENTS_ENABLED flag passed to spu_create, in order to get the new behavior. When this flag is not passed, spu_run will simply ignore the third argument now. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 6 +-- arch/powerpc/platforms/cell/spufs/inode.c | 9 ++-- arch/powerpc/platforms/cell/spufs/run.c | 48 ++++++++++++++------ arch/powerpc/platforms/cell/spufs/sched.c | 4 +- arch/powerpc/platforms/cell/spufs/spufs.h | 4 +- arch/powerpc/platforms/cell/spufs/syscalls.c | 7 ++- include/asm-powerpc/spu.h | 14 ++++++ 7 files changed, 68 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 5931973845b..bfbd0455d8a 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -46,21 +46,21 @@ EXPORT_SYMBOL_GPL(spu_priv1_ops); static int __spu_trap_invalid_dma(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); - force_sig(SIGBUS, /* info, */ current); + spu->dma_callback(spu, SPE_EVENT_INVALID_DMA); return 0; } static int __spu_trap_dma_align(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); - force_sig(SIGBUS, /* info, */ current); + spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT); return 0; } static int __spu_trap_error(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); - force_sig(SIGILL, /* info, */ current); + spu->dma_callback(spu, SPE_EVENT_SPE_ERROR); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 3950ddccb2c..8cc615ff363 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -224,7 +224,8 @@ struct file_operations spufs_context_fops = { }; static int -spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, + int mode) { int ret; struct inode *inode; @@ -244,6 +245,8 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (!ctx) goto out_iput; + ctx->flags = flags; + inode->i_op = &spufs_dir_inode_operations; inode->i_fop = &simple_dir_operations; ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); @@ -304,7 +307,7 @@ long spufs_create_thread(struct nameidata *nd, goto out; /* all flags are reserved */ - if (flags) + if (flags & (~SPU_CREATE_FLAG_ALL)) goto out; dentry = lookup_create(nd, 1); @@ -317,7 +320,7 @@ long spufs_create_thread(struct nameidata *nd, goto out_dput; mode &= ~current->fs->umask; - ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO); + ret = spufs_mkdir(nd->dentry->d_inode, dentry, flags, mode & S_IRWXUGO); if (ret) goto out_dput; diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 483c8b76232..63df8cf4ba1 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -14,6 +14,26 @@ void spufs_stop_callback(struct spu *spu) wake_up_all(&ctx->stop_wq); } +void spufs_dma_callback(struct spu *spu, int type) +{ + struct spu_context *ctx = spu->ctx; + + if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { + ctx->event_return |= type; + wake_up_all(&ctx->stop_wq); + } else { + switch (type) { + case SPE_EVENT_DMA_ALIGNMENT: + case SPE_EVENT_INVALID_DMA: + force_sig(SIGBUS, /* info, */ current); + break; + case SPE_EVENT_SPE_ERROR: + force_sig(SIGILL, /* info */ current); + break; + } + } +} + static inline int spu_stopped(struct spu_context *ctx, u32 * stat) { struct spu *spu; @@ -28,8 +48,7 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat) return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; } -static inline int spu_run_init(struct spu_context *ctx, u32 * npc, - u32 * status) +static inline int spu_run_init(struct spu_context *ctx, u32 * npc) { int ret; @@ -72,7 +91,7 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, SPU_STATUS_STOPPED_BY_HALT)) { return *status; } - if ((ret = spu_run_init(ctx, npc, status)) != 0) + if ((ret = spu_run_init(ctx, npc)) != 0) return ret; return 0; } @@ -177,46 +196,49 @@ static inline int spu_process_events(struct spu_context *ctx) } long spufs_run_spu(struct file *file, struct spu_context *ctx, - u32 * npc, u32 * status) + u32 *npc, u32 *event) { int ret; + u32 status; if (down_interruptible(&ctx->run_sema)) return -ERESTARTSYS; - ret = spu_run_init(ctx, npc, status); + ctx->event_return = 0; + ret = spu_run_init(ctx, npc); if (ret) goto out; do { - ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); + ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); if (unlikely(ret)) break; - if ((*status & SPU_STATUS_STOPPED_BY_STOP) && - (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { + if ((status & SPU_STATUS_STOPPED_BY_STOP) && + (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { ret = spu_process_callback(ctx); if (ret) break; - *status &= ~SPU_STATUS_STOPPED_BY_STOP; + status &= ~SPU_STATUS_STOPPED_BY_STOP; } if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { - ret = spu_reacquire_runnable(ctx, npc, status); + ret = spu_reacquire_runnable(ctx, npc, &status); if (ret) goto out; continue; } ret = spu_process_events(ctx); - } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | + } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))); ctx->ops->runcntl_stop(ctx); - ret = spu_run_fini(ctx, npc, status); + ret = spu_run_fini(ctx, npc, &status); if (!ret) - ret = *status; + ret = status; spu_yield(ctx); out: + *event = ctx->event_return; up(&ctx->run_sema); return ret; } diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index bd4e2c3d5d0..a824b605116 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -81,7 +81,6 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) spu->number, spu->node); spu->ctx = ctx; spu->flags = 0; - ctx->flags = 0; ctx->spu = spu; ctx->ops = &spu_hw_ops; spu->pid = current->pid; @@ -92,6 +91,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) spu->wbox_callback = spufs_wbox_callback; spu->stop_callback = spufs_stop_callback; spu->mfc_callback = spufs_mfc_callback; + spu->dma_callback = spufs_dma_callback; mb(); spu_unmap_mappings(ctx); spu_restore(&ctx->csa, spu); @@ -111,12 +111,12 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) spu->wbox_callback = NULL; spu->stop_callback = NULL; spu->mfc_callback = NULL; + spu->dma_callback = NULL; spu->mm = NULL; spu->pid = 0; spu->prio = MAX_PRIO; ctx->ops = &spu_backing_ops; ctx->spu = NULL; - ctx->flags = 0; spu->flags = 0; spu->ctx = NULL; } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 4485738e210..2fb6a009911 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -66,7 +66,8 @@ struct spu_context { u32 tagwait; struct spu_context_ops *ops; struct work_struct reap_work; - u64 flags; + unsigned long flags; + unsigned long event_return; }; struct mfc_dma_command { @@ -183,5 +184,6 @@ void spufs_ibox_callback(struct spu *spu); void spufs_wbox_callback(struct spu *spu); void spufs_stop_callback(struct spu *spu); void spufs_mfc_callback(struct spu *spu); +void spufs_dma_callback(struct spu *spu, int type); #endif diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index e6565a949dd..ef33a0ca203 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -38,7 +38,7 @@ static long do_spu_run(struct file *filp, u32 npc, status; ret = -EFAULT; - if (get_user(npc, unpc) || get_user(status, ustatus)) + if (get_user(npc, unpc)) goto out; /* check if this file was created by spu_create */ @@ -49,7 +49,10 @@ static long do_spu_run(struct file *filp, i = SPUFS_I(filp->f_dentry->d_inode); ret = spufs_run_spu(filp, i->i_ctx, &npc, &status); - if (put_user(npc, unpc) || put_user(status, ustatus)) + if (put_user(npc, unpc)) + ret = -EFAULT; + + if (ustatus && put_user(status, ustatus)) ret = -EFAULT; out: return ret; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index f6c0a95e820..87cc21e2194 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -138,6 +138,7 @@ struct spu { void (* ibox_callback)(struct spu *spu); void (* stop_callback)(struct spu *spu); void (* mfc_callback)(struct spu *spu); + void (* dma_callback)(struct spu *spu, int type); char irq_c0[8]; char irq_c1[8]; @@ -169,6 +170,19 @@ extern struct spufs_calls { struct module *owner; } spufs_calls; +/* 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*/ +#define SPE_EVENT_SPE_DATA_SEGMENT 0x0020 /*A DMA segmentation error */ +#define SPE_EVENT_SPE_DATA_STORAGE 0x0040 /*A DMA storage error */ +#define SPE_EVENT_INVALID_DMA 0x0800 /* Invalid MFC DMA */ + +/* + * Flags for sys_spu_create. + */ +#define SPU_CREATE_EVENTS_ENABLED 0x0001 +#define SPU_CREATE_FLAG_ALL 0x0001 /* mask of all valid flags */ + #ifdef CONFIG_SPU_FS_MODULE int register_spu_syscalls(struct spufs_calls *calls); void unregister_spu_syscalls(struct spufs_calls *calls); -- GitLab From 6263203ed6e9ff107129a1ebe613290b342a4465 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:15 +0200 Subject: [PATCH 0631/1619] [POWERPC] spufs: Add infrastructure needed for gang scheduling Add the concept of a gang to spufs as a new type of object. So far, this has no impact whatsover on scheduling, but makes it possible to add that later. A new type of object in spufs is now a spu_gang. It is created with the spu_create system call with the flags argument set to SPU_CREATE_GANG (0x2). Inside of a spu_gang, it is then possible to create spu_context objects, which until now was only possible at the root of spufs. There is a new member in struct spu_context pointing to the spu_gang it belongs to, if any. The spu_gang maintains a list of spu_context structures that are its children. This information can then be used in the scheduler in the future. There is still a bug that needs to be resolved in this basic infrastructure regarding the order in which objects are removed. When the spu_gang file descriptor is closed before the spu_context descriptors, we leak the dentry and inode for the gang. Any ideas how to cleanly solve this are appreciated. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/Makefile | 2 +- arch/powerpc/platforms/cell/spufs/context.c | 6 +- arch/powerpc/platforms/cell/spufs/gang.c | 81 +++++++ arch/powerpc/platforms/cell/spufs/inode.c | 225 ++++++++++++++++--- arch/powerpc/platforms/cell/spufs/spufs.h | 24 +- arch/powerpc/platforms/cell/spufs/syscalls.c | 2 +- include/asm-powerpc/spu.h | 5 +- 7 files changed, 303 insertions(+), 42 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spufs/gang.c diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index bb5dc634272..ecdfbb35f82 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -2,7 +2,7 @@ obj-y += switch.o obj-$(CONFIG_SPU_FS) += spufs.o spufs-y += inode.o file.o context.o syscalls.o -spufs-y += sched.o backing_ops.o hw_ops.o run.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 SPU_CROSS := spu- diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 36439c5e9f2..034cf6af53a 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -27,7 +27,7 @@ #include #include "spufs.h" -struct spu_context *alloc_spu_context(void) +struct spu_context *alloc_spu_context(struct spu_gang *gang) { struct spu_context *ctx; ctx = kzalloc(sizeof *ctx, GFP_KERNEL); @@ -51,6 +51,8 @@ struct spu_context *alloc_spu_context(void) ctx->state = SPU_STATE_SAVED; ctx->ops = &spu_backing_ops; ctx->owner = get_task_mm(current); + if (gang) + spu_gang_add_ctx(gang, ctx); goto out; out_free: kfree(ctx); @@ -67,6 +69,8 @@ void destroy_spu_context(struct kref *kref) spu_deactivate(ctx); up_write(&ctx->state_sema); spu_fini_csa(&ctx->csa); + if (ctx->gang) + spu_gang_remove_ctx(ctx->gang, ctx); kfree(ctx); } diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c new file mode 100644 index 00000000000..212ea78f905 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/gang.c @@ -0,0 +1,81 @@ +/* + * SPU file system + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * 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 "spufs.h" + +struct spu_gang *alloc_spu_gang(void) +{ + struct spu_gang *gang; + + gang = kzalloc(sizeof *gang, GFP_KERNEL); + if (!gang) + goto out; + + kref_init(&gang->kref); + mutex_init(&gang->mutex); + INIT_LIST_HEAD(&gang->list); + +out: + return gang; +} + +static void destroy_spu_gang(struct kref *kref) +{ + struct spu_gang *gang; + gang = container_of(kref, struct spu_gang, kref); + WARN_ON(gang->contexts || !list_empty(&gang->list)); + kfree(gang); +} + +struct spu_gang *get_spu_gang(struct spu_gang *gang) +{ + kref_get(&gang->kref); + return gang; +} + +int put_spu_gang(struct spu_gang *gang) +{ + return kref_put(&gang->kref, &destroy_spu_gang); +} + +void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx) +{ + mutex_lock(&gang->mutex); + ctx->gang = get_spu_gang(gang); + list_add(&ctx->gang_list, &gang->list); + gang->contexts++; + mutex_unlock(&gang->mutex); +} + +void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx) +{ + mutex_lock(&gang->mutex); + WARN_ON(ctx->gang != gang); + list_del_init(&ctx->gang_list); + gang->contexts--; + mutex_unlock(&gang->mutex); + + put_spu_gang(gang); +} diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 8cc615ff363..427d00a4f6a 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -50,6 +50,10 @@ spufs_alloc_inode(struct super_block *sb) ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); if (!ei) return NULL; + + ei->i_gang = NULL; + ei->i_ctx = NULL; + return &ei->vfs_inode; } @@ -128,14 +132,19 @@ out: static void spufs_delete_inode(struct inode *inode) { - if (SPUFS_I(inode)->i_ctx) - put_spu_context(SPUFS_I(inode)->i_ctx); + struct spufs_inode_info *ei = SPUFS_I(inode); + + if (ei->i_ctx) + put_spu_context(ei->i_ctx); + if (ei->i_gang) + put_spu_gang(ei->i_gang); clear_inode(inode); } static void spufs_prune_dir(struct dentry *dir) { struct dentry *dentry, *tmp; + mutex_lock(&dir->d_inode->i_mutex); list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { spin_lock(&dcache_lock); @@ -156,13 +165,13 @@ static void spufs_prune_dir(struct dentry *dir) mutex_unlock(&dir->d_inode->i_mutex); } -/* Caller must hold root->i_mutex */ -static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) +/* Caller must hold parent->i_mutex */ +static int spufs_rmdir(struct inode *parent, struct dentry *dir) { /* remove all entries */ - spufs_prune_dir(dir_dentry); + spufs_prune_dir(dir); - return simple_rmdir(root, dir_dentry); + return simple_rmdir(parent, dir); } static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, @@ -191,17 +200,17 @@ out: static int spufs_dir_close(struct inode *inode, struct file *file) { struct spu_context *ctx; - struct inode *dir; - struct dentry *dentry; + struct inode *parent; + struct dentry *dir; int ret; - dentry = file->f_dentry; - dir = dentry->d_parent->d_inode; - ctx = SPUFS_I(dentry->d_inode)->i_ctx; + dir = file->f_dentry; + parent = dir->d_parent->d_inode; + ctx = SPUFS_I(dir->d_inode)->i_ctx; - mutex_lock(&dir->i_mutex); - ret = spufs_rmdir(dir, dentry); - mutex_unlock(&dir->i_mutex); + mutex_lock(&parent->i_mutex); + ret = spufs_rmdir(parent, dir); + mutex_unlock(&parent->i_mutex); WARN_ON(ret); /* We have to give up the mm_struct */ @@ -240,7 +249,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, inode->i_gid = dir->i_gid; inode->i_mode &= S_ISGID; } - ctx = alloc_spu_context(); + ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */ SPUFS_I(inode)->i_ctx = ctx; if (!ctx) goto out_iput; @@ -292,24 +301,177 @@ out: return ret; } +static int spufs_create_context(struct inode *inode, + struct dentry *dentry, + struct vfsmount *mnt, int flags, int mode) +{ + int ret; + + ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); + if (ret) + goto out_unlock; + + /* + * get references for dget and mntget, will be released + * in error path of *_open(). + */ + ret = spufs_context_open(dget(dentry), mntget(mnt)); + if (ret < 0) { + WARN_ON(spufs_rmdir(inode, dentry)); + mutex_unlock(&inode->i_mutex); + spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); + goto out; + } + +out_unlock: + mutex_unlock(&inode->i_mutex); +out: + dput(dentry); + return ret; +} + +static int spufs_rmgang(struct inode *root, struct dentry *dir) +{ + /* FIXME: this fails if the dir is not empty, + which causes a leak of gangs. */ + return simple_rmdir(root, dir); +} + +static int spufs_gang_close(struct inode *inode, struct file *file) +{ + struct inode *parent; + struct dentry *dir; + int ret; + + dir = file->f_dentry; + parent = dir->d_parent->d_inode; + + ret = spufs_rmgang(parent, dir); + WARN_ON(ret); + + return dcache_dir_close(inode, file); +} + +struct file_operations spufs_gang_fops = { + .open = dcache_dir_open, + .release = spufs_gang_close, + .llseek = dcache_dir_lseek, + .read = generic_read_dir, + .readdir = dcache_readdir, + .fsync = simple_sync_file, +}; + +static int +spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) +{ + int ret; + struct inode *inode; + struct spu_gang *gang; + + ret = -ENOSPC; + inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); + if (!inode) + goto out; + + ret = 0; + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + inode->i_mode &= S_ISGID; + } + gang = alloc_spu_gang(); + SPUFS_I(inode)->i_ctx = NULL; + SPUFS_I(inode)->i_gang = gang; + if (!gang) + goto out_iput; + + inode->i_op = &spufs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + d_instantiate(dentry, inode); + dget(dentry); + dir->i_nlink++; + dentry->d_inode->i_nlink++; + return ret; + +out_iput: + iput(inode); +out: + return ret; +} + +static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) +{ + int ret; + struct file *filp; + + ret = get_unused_fd(); + if (ret < 0) { + dput(dentry); + mntput(mnt); + goto out; + } + + filp = dentry_open(dentry, mnt, O_RDONLY); + if (IS_ERR(filp)) { + put_unused_fd(ret); + ret = PTR_ERR(filp); + goto out; + } + + filp->f_op = &spufs_gang_fops; + fd_install(ret, filp); +out: + return ret; +} + +static int spufs_create_gang(struct inode *inode, + struct dentry *dentry, + struct vfsmount *mnt, int mode) +{ + int ret; + + ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO); + if (ret) + goto out; + + /* + * get references for dget and mntget, will be released + * in error path of *_open(). + */ + ret = spufs_gang_open(dget(dentry), mntget(mnt)); + if (ret < 0) + WARN_ON(spufs_rmgang(inode, dentry)); + +out: + mutex_unlock(&inode->i_mutex); + dput(dentry); + return ret; +} + + static struct file_system_type spufs_type; -long spufs_create_thread(struct nameidata *nd, - unsigned int flags, mode_t mode) +long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) { struct dentry *dentry; int ret; - /* need to be at the root of spufs */ ret = -EINVAL; - if (nd->dentry->d_sb->s_type != &spufs_type || - nd->dentry != nd->dentry->d_sb->s_root) + /* check if we are on spufs */ + if (nd->dentry->d_sb->s_type != &spufs_type) goto out; - /* all flags are reserved */ + /* don't accept undefined flags */ if (flags & (~SPU_CREATE_FLAG_ALL)) goto out; + /* only threads can be underneath a gang */ + if (nd->dentry != nd->dentry->d_sb->s_root) { + if ((flags & SPU_CREATE_GANG) || + !SPUFS_I(nd->dentry->d_inode)->i_gang) + goto out; + } + dentry = lookup_create(nd, 1); ret = PTR_ERR(dentry); if (IS_ERR(dentry)) @@ -320,22 +482,13 @@ long spufs_create_thread(struct nameidata *nd, goto out_dput; mode &= ~current->fs->umask; - ret = spufs_mkdir(nd->dentry->d_inode, dentry, flags, mode & S_IRWXUGO); - if (ret) - goto out_dput; - /* - * get references for dget and mntget, will be released - * in error path of *_open(). - */ - ret = spufs_context_open(dget(dentry), mntget(nd->mnt)); - if (ret < 0) { - WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry)); - mutex_unlock(&nd->dentry->d_inode->i_mutex); - spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); - dput(dentry); - goto out; - } + if (flags & SPU_CREATE_GANG) + return spufs_create_gang(nd->dentry->d_inode, + dentry, nd->mnt, mode); + else + return spufs_create_context(nd->dentry->d_inode, + dentry, nd->mnt, flags, mode); out_dput: dput(dentry); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 2fb6a009911..f6624ceedf7 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -39,6 +39,8 @@ struct spu_context_ops; #define SPU_CONTEXT_PREEMPT 0UL +struct spu_gang; + struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ @@ -68,6 +70,16 @@ struct spu_context { struct work_struct reap_work; unsigned long flags; unsigned long event_return; + + struct list_head gang_list; + struct spu_gang *gang; +}; + +struct spu_gang { + struct list_head list; + struct mutex mutex; + struct kref kref; + int contexts; }; struct mfc_dma_command { @@ -115,6 +127,7 @@ extern struct spu_context_ops spu_backing_ops; struct spufs_inode_info { struct spu_context *i_ctx; + struct spu_gang *i_gang; struct inode vfs_inode; }; #define SPUFS_I(inode) \ @@ -125,12 +138,19 @@ extern struct tree_descr spufs_dir_contents[]; /* system call implementation */ long spufs_run_spu(struct file *file, struct spu_context *ctx, u32 *npc, u32 *status); -long spufs_create_thread(struct nameidata *nd, +long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode); extern struct file_operations spufs_context_fops; +/* gang management */ +struct spu_gang *alloc_spu_gang(void); +struct spu_gang *get_spu_gang(struct spu_gang *gang); +int put_spu_gang(struct spu_gang *gang); +void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); +void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); + /* context management */ -struct spu_context * alloc_spu_context(void); +struct spu_context * alloc_spu_context(struct spu_gang *gang); void destroy_spu_context(struct kref *kref); struct spu_context * get_spu_context(struct spu_context *ctx); int put_spu_context(struct spu_context *ctx); diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index ef33a0ca203..a6d1ae4dc2a 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -90,7 +90,7 @@ asmlinkage long sys_spu_create(const char __user *pathname, ret = path_lookup(tmp, LOOKUP_PARENT| LOOKUP_OPEN|LOOKUP_CREATE, &nd); if (!ret) { - ret = spufs_create_thread(&nd, flags, mode); + ret = spufs_create(&nd, flags, mode); path_release(&nd); } putname(tmp); diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 87cc21e2194..83b6dae48ef 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -181,7 +181,10 @@ extern struct spufs_calls { * Flags for sys_spu_create. */ #define SPU_CREATE_EVENTS_ENABLED 0x0001 -#define SPU_CREATE_FLAG_ALL 0x0001 /* mask of all valid flags */ +#define SPU_CREATE_GANG 0x0002 + +#define SPU_CREATE_FLAG_ALL 0x0003 /* mask of all valid flags */ + #ifdef CONFIG_SPU_FS_MODULE int register_spu_syscalls(struct spufs_calls *calls); -- GitLab From ac91cb8dae061ced64e475d0d70fac4a95298819 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:16 +0200 Subject: [PATCH 0632/1619] [POWERPC] spufs: use correct pg_prot for mapping SPU local store This hopefully fixes a long-standing bug in the spu file system. An spu context comes with local memory that can be either saved in kernel pages or point directly to a physical SPE. When mapping the physical SPE, that mapping needs to be cache-inhibited. For simplicity, we used to map the kernel backing memory that way too, but unfortunately that was not only inefficient, but also incorrect because the same page could then be accessed simultaneously through a cacheable and a cache-inhibited mapping, which is not allowed by the powerpc specification and in our case caused data inconsistency for which we did a really ugly workaround in user space. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 64f8b0a9b9e..514a1d50803 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -102,12 +102,16 @@ spufs_mem_mmap_nopage(struct vm_area_struct *vma, spu_acquire(ctx); - if (ctx->state == SPU_STATE_SAVED) + if (ctx->state == SPU_STATE_SAVED) { + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + & ~(_PAGE_NO_CACHE | _PAGE_GUARDED)); page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); - else + } else { + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE | _PAGE_GUARDED); page = pfn_to_page((ctx->spu->local_store_phys + offset) >> PAGE_SHIFT); - + } spu_release(ctx); if (type) -- GitLab From cdcc89bb1c6e886a55fe00e2de3b9c65d41674c2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:17 +0200 Subject: [PATCH 0633/1619] [POWERPC] spufs: make mailbox functions handle multiple elements Since libspe2 will provide a function that can read/write multiple mailbox elements at once, the kernel should handle that efficiently. read/write on the three mailbox files can now access the spe context multiple times to operate on any number of mailbox data elements. If the spu application keeps writing to its outbound mailbox, the read call will pick up all the data in a single system call. Unfortunately, if the user passes an invalid pointer, we may lose a mailbox element on read, since we can't put it back. This probably impossible to solve, if the user also accesses the mailbox through direct register access. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 154 ++++++++++++++++++----- 1 file changed, 125 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 514a1d50803..b4d38cb65f1 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -354,27 +354,54 @@ static int spufs_pipe_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } +/* + * Read as many bytes from the mailbox as possible, until + * one of the conditions becomes true: + * + * - no more data available in the mailbox + * - end of the user provided buffer + * - end of the mapped area + */ static ssize_t spufs_mbox_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; - u32 mbox_data; - int ret; + u32 mbox_data, __user *udata; + ssize_t count; if (len < 4) return -EINVAL; + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + udata = (void __user *)buf; + spu_acquire(ctx); - ret = ctx->ops->mbox_read(ctx, &mbox_data); + for (count = 0; count <= len; count += 4, udata++) { + int ret; + ret = ctx->ops->mbox_read(ctx, &mbox_data); + if (ret == 0) + break; + + /* + * at the end of the mapped area, we can fault + * but still need to return the data we have + * read successfully so far. + */ + ret = __put_user(mbox_data, udata); + if (ret) { + if (!count) + count = -EFAULT; + break; + } + } spu_release(ctx); - if (!ret) - return -EAGAIN; - - if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) - return -EFAULT; + if (!count) + count = -EAGAIN; - return 4; + return count; } static struct file_operations spufs_mbox_fops = { @@ -430,36 +457,70 @@ void spufs_ibox_callback(struct spu *spu) kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); } +/* + * Read as many bytes from the interrupt mailbox as possible, until + * one of the conditions becomes true: + * + * - no more data available in the mailbox + * - end of the user provided buffer + * - end of the mapped area + * + * If the file is opened without O_NONBLOCK, we wait here until + * any data is available, but return when we have been able to + * read something. + */ static ssize_t spufs_ibox_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; - u32 ibox_data; - ssize_t ret; + u32 ibox_data, __user *udata; + ssize_t count; if (len < 4) return -EINVAL; + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + udata = (void __user *)buf; + spu_acquire(ctx); - ret = 0; + /* wait only for the first element */ + count = 0; if (file->f_flags & O_NONBLOCK) { if (!spu_ibox_read(ctx, &ibox_data)) - ret = -EAGAIN; + count = -EAGAIN; } else { - ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); + count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); } + if (count) + goto out; - spu_release(ctx); + /* if we can't write at all, return -EFAULT */ + count = __put_user(ibox_data, udata); + if (count) + goto out; - if (ret) - return ret; + for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { + int ret; + ret = ctx->ops->ibox_read(ctx, &ibox_data); + if (ret == 0) + break; + /* + * at the end of the mapped area, we can fault + * but still need to return the data we have + * read successfully so far. + */ + ret = __put_user(ibox_data, udata); + if (ret) + break; + } - ret = 4; - if (copy_to_user(buf, &ibox_data, sizeof ibox_data)) - ret = -EFAULT; +out: + spu_release(ctx); - return ret; + return count; } static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) @@ -532,32 +593,67 @@ void spufs_wbox_callback(struct spu *spu) kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); } +/* + * Write as many bytes to the interrupt mailbox as possible, until + * one of the conditions becomes true: + * + * - the mailbox is full + * - end of the user provided buffer + * - end of the mapped area + * + * If the file is opened without O_NONBLOCK, we wait here until + * space is availabyl, but return when we have been able to + * write something. + */ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; - u32 wbox_data; - int ret; + u32 wbox_data, __user *udata; + ssize_t count; if (len < 4) return -EINVAL; - if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) + udata = (void __user *)buf; + if (!access_ok(VERIFY_READ, buf, len)) + return -EFAULT; + + if (__get_user(wbox_data, udata)) return -EFAULT; spu_acquire(ctx); - ret = 0; + /* + * make sure we can at least write one element, by waiting + * in case of !O_NONBLOCK + */ + count = 0; if (file->f_flags & O_NONBLOCK) { if (!spu_wbox_write(ctx, wbox_data)) - ret = -EAGAIN; + count = -EAGAIN; } else { - ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); + count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); } - spu_release(ctx); + if (count) + goto out; - return ret ? ret : sizeof wbox_data; + /* write aÑ• much as possible */ + for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { + int ret; + ret = __get_user(wbox_data, udata); + if (ret) + break; + + ret = spu_wbox_write(ctx, wbox_data); + if (ret == 0) + break; + } + +out: + spu_release(ctx); + return count; } static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) -- GitLab From 772920e594df25f2011ca49abd9c8b85c4820cdc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:18 +0200 Subject: [PATCH 0634/1619] [POWERPC] spufs: remove support for ancient firmware Any firmware that still uses the 'spc' nodes already stopped running for other reasons, so let's get rid of this. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index bfbd0455d8a..d4e4f0f683d 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -791,18 +791,6 @@ static int __init init_spu_base(void) break; } } - /* in some old firmware versions, the spe is called 'spc', so we - look for that as well */ - for (node = of_find_node_by_type(NULL, "spc"); - node; node = of_find_node_by_type(node, "spc")) { - ret = create_spu(node); - if (ret) { - printk(KERN_WARNING "%s: Error initializing %s\n", - __FUNCTION__, node->name); - cleanup_spu_base(); - break; - } - } return ret; } module_init(init_spu_base); -- GitLab From e1dbff2bafa83f839ef15f51904b0cce9fc89387 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:19 +0200 Subject: [PATCH 0635/1619] [POWERPC] spufs: add support for read/write on cntl Writing to cntl can be used to stop execution on the spu and to restart it, reading from cntl gives the contents of the current status register. The access is always in ascii, as for most other files. This was always meant to be there, but we had a little problem with writing to runctl so it was left out so far. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 44 ++++++++++++++---------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index b4d38cb65f1..e2c9d48a680 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -211,37 +211,43 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) #define spufs_cntl_mmap NULL #endif /* !SPUFS_MMAP_4K */ -static int spufs_cntl_open(struct inode *inode, struct file *file) +static u64 spufs_cntl_get(void *data) { - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; + struct spu_context *ctx = data; + u64 val; - file->private_data = ctx; - file->f_mapping = inode->i_mapping; - ctx->cntl = inode->i_mapping; - return 0; + spu_acquire(ctx); + val = ctx->ops->status_read(ctx); + spu_release(ctx); + + return val; } -static ssize_t -spufs_cntl_read(struct file *file, char __user *buffer, - size_t size, loff_t *pos) +static void spufs_cntl_set(void *data, u64 val) { - /* FIXME: read from spu status */ - return -EINVAL; + struct spu_context *ctx = data; + + spu_acquire(ctx); + ctx->ops->runcntl_write(ctx, val); + spu_release(ctx); } -static ssize_t -spufs_cntl_write(struct file *file, const char __user *buffer, - size_t size, loff_t *pos) +static int spufs_cntl_open(struct inode *inode, struct file *file) { - /* FIXME: write to runctl bit */ - return -EINVAL; + struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; + + file->private_data = ctx; + file->f_mapping = inode->i_mapping; + ctx->cntl = inode->i_mapping; + return simple_attr_open(inode, file, spufs_cntl_get, + spufs_cntl_set, "0x%08lx"); } static struct file_operations spufs_cntl_fops = { .open = spufs_cntl_open, - .read = spufs_cntl_read, - .write = spufs_cntl_write, + .read = simple_attr_read, + .write = simple_attr_write, .mmap = spufs_cntl_mmap, }; -- GitLab From 7650f2f2c367242a2092908794b4486876baf6c7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:20 +0200 Subject: [PATCH 0636/1619] [POWERPC] spufs: support new OF device tree format The properties we used traditionally in the device tree are somewhat nonstandard. This adds support for a more conventional format using 'interrupts' and 'reg' properties. The interrupts are specified in three cells (class 0, 1 and 2) and registered at the interrupt-parent. The reg property contains either three or four register areas in the order 'local-store', 'problem', 'priv2', and 'priv1', so the priv1 one can be left out in case of hypervisor driven systems that access these through hcalls. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 99 ++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index d4e4f0f683d..ac5f12662db 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -25,11 +25,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -576,7 +578,7 @@ static void spu_unmap(struct spu *spu) } /* This function shall be abstracted for HV platforms */ -static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) +static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np) { unsigned int isrc; const u32 *tmp; @@ -600,7 +602,7 @@ static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; } -static int __init spu_map_device(struct spu *spu, struct device_node *node) +static int __init spu_map_device_old(struct spu *spu, struct device_node *node) { const char *prop; int ret; @@ -645,6 +647,88 @@ out: return ret; } +static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) +{ + struct of_irq oirq; + int ret; + int i; + + for (i=0; i < 3; i++) { + ret = of_irq_map_one(np, i, &oirq); + if (ret) + goto err; + + ret = -EINVAL; + spu->irqs[i] = irq_create_of_mapping(oirq.controller, + oirq.specifier, oirq.size); + if (spu->irqs[i] == NO_IRQ) + goto err; + } + return 0; + +err: + pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, spu->name); + for (; i >= 0; i--) { + if (spu->irqs[i] != NO_IRQ) + irq_dispose_mapping(spu->irqs[i]); + } + return ret; +} + +static int spu_map_resource(struct device_node *node, int nr, + void __iomem** virt, unsigned long *phys) +{ + struct resource resource = { }; + int ret; + + ret = of_address_to_resource(node, 0, &resource); + if (ret) + goto out; + + if (phys) + *phys = resource.start; + *virt = ioremap(resource.start, resource.end - resource.start); + if (!*virt) + ret = -EINVAL; + +out: + return ret; +} + +static int __init spu_map_device(struct spu *spu, struct device_node *node) +{ + int ret = -ENODEV; + spu->name = get_property(node, "name", NULL); + if (!spu->name) + goto out; + + ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store, + &spu->local_store_phys); + if (ret) + goto out; + ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem, + &spu->problem_phys); + if (ret) + goto out_unmap; + ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2, + NULL); + if (ret) + goto out_unmap; + + if (!firmware_has_feature(FW_FEATURE_LPAR)) + ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1, + NULL); + if (ret) + goto out_unmap; + return 0; + +out_unmap: + spu_unmap(spu); +out: + pr_debug("failed to map spe %s: %d\n", spu->name, ret); + return ret; +} + struct sysdev_class spu_sysdev_class = { set_kset_name("spu") }; @@ -698,6 +782,9 @@ static int __init create_spu(struct device_node *spe) goto out; ret = spu_map_device(spu, spe); + /* try old method */ + if (ret) + ret = spu_map_device_old(spu, spe); if (ret) goto out_free; @@ -706,6 +793,8 @@ static int __init create_spu(struct device_node *spe) if (spu->nid == -1) spu->nid = 0; ret = spu_map_interrupts(spu, spe); + if (ret) + ret = spu_map_interrupts_old(spu, spe); if (ret) goto out_unmap; spin_lock_init(&spu->register_lock); @@ -716,7 +805,7 @@ static int __init create_spu(struct device_node *spe) spu->number = number++; ret = spu_request_irqs(spu); if (ret) - goto out_unmap; + goto out_unlock; ret = spu_create_sysdev(spu); if (ret) @@ -732,9 +821,9 @@ static int __init create_spu(struct device_node *spe) out_free_irqs: spu_free_irqs(spu); - -out_unmap: +out_unlock: mutex_unlock(&spu_mutex); +out_unmap: spu_unmap(spu); out_free: kfree(spu); -- GitLab From 867672777964b9309e4e914fe097648c938b67b2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:21 +0200 Subject: [PATCH 0637/1619] [POWERPC] spufs: add infrastructure for finding elf objects This adds an 'object-id' file that the spe library can use to store a pointer to its ELF object. This was originally meant for use by oprofile, but is now also used by the GNU debugger, if available. In order for oprofile to find the location in an spu-elf binary where an event counter triggered, we need a way to identify the binary in the first place. Unfortunately, that binary itself can be embedded in a powerpc ELF binary. Since we can assume it is mapped into the effective address space of the running process, have that one write the pointer value into a new spufs file. When a context switch occurs, pass the user value to the profiler so that can look at the mapped file (with some care). Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 18 +++++++++++++++++- arch/powerpc/platforms/cell/spufs/sched.c | 22 ++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 1 + include/asm-powerpc/spu.h | 18 ++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index e2c9d48a680..e0d73004526 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -1487,6 +1487,21 @@ 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) +{ + struct spu_context *ctx = data; + return ctx->object_id; +} + +static void spufs_object_id_set(void *data, u64 id) +{ + struct spu_context *ctx = data; + ctx->object_id = id; +} + +DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, + spufs_object_id_set, "0x%llx\n"); + struct tree_descr spufs_dir_contents[] = { { "mem", &spufs_mem_fops, 0666, }, { "regs", &spufs_regs_fops, 0666, }, @@ -1510,7 +1525,8 @@ struct tree_descr spufs_dir_contents[] = { { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, }, { "event_mask", &spufs_event_mask_ops, 0666, }, { "srr0", &spufs_srr0_ops, 0666, }, - { "phys-id", &spufs_id_ops, 0666, }, { "psmap", &spufs_psmap_fops, 0666, }, + { "phys-id", &spufs_id_ops, 0666, }, + { "object-id", &spufs_object_id_ops, 0666, }, {}, }; diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index a824b605116..bd6fe4b7a84 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,25 @@ static inline void mm_needs_global_tlbie(struct mm_struct *mm) __cpus_setall(&mm->cpu_vm_mask, nr); } +static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier); + +static void spu_switch_notify(struct spu *spu, struct spu_context *ctx) +{ + blocking_notifier_call_chain(&spu_switch_notifier, + ctx ? ctx->object_id : 0, spu); +} + +int spu_switch_event_register(struct notifier_block * n) +{ + return blocking_notifier_chain_register(&spu_switch_notifier, n); +} + +int spu_switch_event_unregister(struct notifier_block * n) +{ + return blocking_notifier_chain_unregister(&spu_switch_notifier, n); +} + + static inline void bind_context(struct spu *spu, struct spu_context *ctx) { pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, @@ -97,12 +117,14 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) spu_restore(&ctx->csa, spu); spu->timestamp = jiffies; spu_cpu_affinity_set(spu, raw_smp_processor_id()); + spu_switch_notify(spu, ctx); } static inline void unbind_context(struct spu *spu, struct spu_context *ctx) { pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, spu->pid, spu->number, spu->node); + spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); spu->timestamp = jiffies; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index f6624ceedf7..a0f55ca2d48 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -50,6 +50,7 @@ struct spu_context { struct address_space *cntl; /* 'control' area mappings. */ struct address_space *signal1; /* 'signal1' area mappings. */ struct address_space *signal2; /* 'signal2' area mappings. */ + u64 object_id; /* user space pointer for oprofile */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; struct rw_semaphore state_sema; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 83b6dae48ef..e73ea00efd8 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -200,6 +200,24 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls) #endif /* MODULE */ +/* + * Notifier blocks: + * + * oprofile can get notified when a context switch is performed + * on an spe. The notifer function that gets called is passed + * a pointer to the SPU structure as well as the object-id that + * identifies the binary running on that SPU now. + * + * For a context save, the object-id that is passed is zero, + * identifying that the kernel will run from that moment on. + * + * For a context restore, the object-id is the value written + * to object-id spufs file from user space and the notifer + * function can assume that spu->ctx is valid. + */ +int spu_switch_event_register(struct notifier_block * n); +int spu_switch_event_unregister(struct notifier_block * n); + /* * This defines the Local Store, Problem Area and Privlege Area of an SPU. */ -- GitLab From 68272047c51145a8aa4f3b6ae27edae6986c28cc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:22 +0200 Subject: [PATCH 0638/1619] [POWERPC] Update cell_defconfig This adds defaults for new configuration options added since 2.6.18 and it enables the option for 64kb pages by default. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/configs/cell_defconfig | 60 ++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index 6fd9e7acec2..892d5dd3254 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc6 -# Sun Sep 10 10:20:32 2006 +# Linux kernel version: 2.6.18 +# Wed Oct 4 15:30:50 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_PPC_OF=y CONFIG_PPC_UDBG_16550=y # CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y # CONFIG_DEFAULT_UIMAGE is not set # @@ -52,10 +53,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -CONFIG_SYSCTL=y +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -63,7 +65,9 @@ CONFIG_CPUSETS=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -72,12 +76,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -96,6 +100,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_BLK_DEV_IO_TRACE is not set # @@ -115,12 +120,13 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # Platform support # CONFIG_PPC_MULTIPLATFORM=y -# CONFIG_PPC_ISERIES is not set # CONFIG_EMBEDDED6xx is not set # CONFIG_APUS is not set # CONFIG_PPC_PSERIES is not set +# CONFIG_PPC_ISERIES is not set # CONFIG_PPC_PMAC is not set # CONFIG_PPC_MAPLE is not set +# CONFIG_PPC_PASEMI is not set CONFIG_PPC_CELL=y CONFIG_PPC_CELL_NATIVE=y CONFIG_PPC_IBM_CELL_BLADE=y @@ -142,7 +148,6 @@ CONFIG_MMIO_NVRAM=y # CONFIG_SPU_FS=m CONFIG_SPU_BASE=y -CONFIG_SPUFS_MMAP=y CONFIG_CBE_RAS=y # @@ -158,7 +163,7 @@ CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_BKL=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m -CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_FORCE_MAX_ZONEORDER=9 # CONFIG_IOMMU_VMERGE is not set CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_KEXEC=y @@ -168,6 +173,7 @@ CONFIG_NUMA=y CONFIG_NODES_SHIFT=4 CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_FLATMEM_MANUAL is not set # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -178,12 +184,12 @@ CONFIG_HAVE_MEMORY_PRESENT=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPARSEMEM_EXTREME=y CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y CONFIG_RESOURCES_64BIT=y -CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y CONFIG_ARCH_MEMORY_PROBE=y -# CONFIG_PPC_64K_PAGES is not set +CONFIG_PPC_64K_PAGES=y CONFIG_SCHED_SMT=y CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set @@ -201,6 +207,7 @@ CONFIG_GENERIC_ISA_DMA=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y CONFIG_PCIEPORTBUS=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # @@ -228,6 +235,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -249,7 +257,8 @@ CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # # IP: Virtual Server Configuration @@ -261,11 +270,15 @@ CONFIG_IPV6=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m CONFIG_INET6_XFRM_MODE_TRANSPORT=y CONFIG_INET6_XFRM_MODE_TUNNEL=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -322,7 +335,6 @@ CONFIG_IP_NF_QUEUE=m # 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 @@ -434,6 +446,7 @@ CONFIG_BLK_DEV_AEC62XX=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_IT821X is not set @@ -456,6 +469,12 @@ CONFIG_IDEDMA_AUTO=y # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set # # Multi-device support (RAID and LVM) @@ -470,6 +489,7 @@ CONFIG_MD_RAID1=m # CONFIG_MD_MULTIPATH is not set # CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m @@ -504,7 +524,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set CONFIG_BONDING=y # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_TUN=y # # ARCnet devices @@ -552,7 +572,7 @@ CONFIG_SKGE=m # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set CONFIG_SPIDER_NET=m -# CONFIG_MV643XX_ETH is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -599,6 +619,7 @@ CONFIG_SPIDER_NET=m # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -865,6 +886,7 @@ CONFIG_INFINIBAND_USER_ACCESS=m CONFIG_INFINIBAND_ADDR_TRANS=y CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_MTHCA_DEBUG=y +# CONFIG_INFINIBAND_AMSO1100 is not set CONFIG_INFINIBAND_IPOIB=m CONFIG_INFINIBAND_IPOIB_DEBUG=y CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y @@ -916,7 +938,7 @@ 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_AUTOFS4_FS=m # CONFIG_FUSE_FS is not set # @@ -943,8 +965,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y @@ -1084,6 +1108,7 @@ CONFIG_PLIST=y # Kernel hacking # # CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y @@ -1102,6 +1127,7 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FORCED_INLINING is not set # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUG_STACKOVERFLOW is not set @@ -1123,6 +1149,10 @@ CONFIG_IRQSTACKS=y # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +# CONFIG_CRYPTO_MANAGER is not set CONFIG_CRYPTO_HMAC=y # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set @@ -1132,6 +1162,8 @@ CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_DES=m # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set -- GitLab From f7e2ce788677ca0996d360202b91524db894c7b2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:23 +0200 Subject: [PATCH 0639/1619] [POWERPC] spiderpic: enable new style devtree support This enables support for new firmware test releases. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spider-pic.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 608b1ebc56b..6794de0cc0f 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -244,7 +244,6 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) int imaplen, intsize, unit; struct device_node *iic; -#if 0 /* Enable that when we have a way to retreive the node as well */ /* First, we check wether we have a real "interrupts" in the device * tree in case the device-tree is ever fixed */ @@ -252,9 +251,8 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) { virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size); - goto bail; + return virq; } -#endif /* Now do the horrible hacks */ tmp = get_property(pic->of_node, "#interrupt-cells", NULL); -- GitLab From 43b4f4061cf54aa225a1e94a969450ccf5305cd9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Oct 2006 17:26:24 +0200 Subject: [PATCH 0640/1619] [POWERPC] cell: fix bugs found by sparse - Some long constants should be marked 'ul'. - When using desc->handler_data to pass an __iomem register area, we need to add casts to and from __iomem. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/interrupt.c | 10 +++++++--- arch/powerpc/platforms/cell/iommu.c | 8 ++++---- arch/powerpc/platforms/cell/spider-pic.c | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 6cc59e0b458..8533f13a5ed 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -101,7 +101,7 @@ static void iic_ioexc_eoi(unsigned int irq) static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) { - struct cbe_iic_regs *node_iic = desc->handler_data; + struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data; unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC; unsigned long bits, ack; int cascade; @@ -320,7 +320,7 @@ static int __init setup_iic(void) struct device_node *dn; struct resource r0, r1; unsigned int node, cascade, found = 0; - struct cbe_iic_regs *node_iic; + struct cbe_iic_regs __iomem *node_iic; const u32 *np; for (dn = NULL; @@ -357,7 +357,11 @@ static int __init setup_iic(void) cascade = irq_create_mapping(iic_host, cascade); if (cascade == NO_IRQ) continue; - set_irq_data(cascade, node_iic); + /* + * irq_data is a generic pointer that gets passed back + * to us later, so the forced cast is fine. + */ + set_irq_data(cascade, (void __force *)node_iic); set_irq_chained_handler(cascade , iic_ioexc_cascade); out_be64(&node_iic->iic_ir, (1 << 12) /* priority */ | diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index d2b20eba5b8..aca4c3db0dd 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -345,8 +345,8 @@ static int cell_map_iommu_hardcoded(int num_nodes) /* node 0 */ iommu = &cell_iommus[0]; - iommu->mapped_base = ioremap(0x20000511000, 0x1000); - iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000); + iommu->mapped_base = ioremap(0x20000511000ul, 0x1000); + iommu->mapped_mmio_base = ioremap(0x20000510000ul, 0x1000); enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); @@ -358,8 +358,8 @@ static int cell_map_iommu_hardcoded(int num_nodes) /* node 1 */ iommu = &cell_iommus[1]; - iommu->mapped_base = ioremap(0x30000511000, 0x1000); - iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000); + iommu->mapped_base = ioremap(0x30000511000ul, 0x1000); + iommu->mapped_mmio_base = ioremap(0x30000510000ul, 0x1000); enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 6794de0cc0f..b0e95d594c5 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -367,7 +367,7 @@ void __init spider_init_IRQ(void) } else if (device_is_compatible(dn, "sti,platform-spider-pic") && (chip < 2)) { static long hard_coded_pics[] = - { 0x24000008000, 0x34000008000 }; + { 0x24000008000ul, 0x34000008000ul}; r.start = hard_coded_pics[chip]; } else continue; -- GitLab From ee9f4b5d95d03d1546f0d06cbe384bd4ab97bcba Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 13:08:33 -0600 Subject: [PATCH 0641/1619] [PA-RISC] Fix sba_iommu compilation klist_iter_exit() only takes one parameter. Also fix warning by adding additional brackets. Signed-off-by: Matthew Wilcox --- drivers/parisc/sba_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 294c1117098..f1e7ccd5475 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1320,12 +1320,12 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ** the GART code to handshake on. */ klist_iter_init(&sba->dev.klist_children, &i); - while (dev = next_device(&i)) { + while ((dev = next_device(&i))) { struct parisc_device *lba = to_parisc_device(dev); if (IS_QUICKSILVER(lba)) agp_found = 1; } - klist_iter_exit(&sba->dev.klist_children, &i); + klist_iter_exit(&i); if (agp_found && sba_reserve_agpgart) { printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n", -- GitLab From 17cca07237617a2d712eb44cffd8720055e61291 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 13:16:10 -0600 Subject: [PATCH 0642/1619] [PA-RISC] Fix sys32_sysctl When CONFIG_SYSCTL_SYSCALL isn't defined, do_sysctl doesn't exist and we fail to link. Fix with an ifdef, the same way sparc64 did. Also add some minor changes to be more like sparc64. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/sys_parisc32.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index e3b30bc3645..e0e4e0bfcc6 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -111,13 +111,14 @@ struct __sysctl_args32 { asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) { +#ifndef CONFIG_SYSCTL_SYSCALL + return -ENOSYS; +#else struct __sysctl_args32 tmp; int error; unsigned int oldlen32; - size_t oldlen, *oldlenp = NULL; + size_t oldlen, __user *oldlenp = NULL; unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7; - extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, - void *newval, size_t newlen); DBG(("sysctl32(%p)\n", args)); @@ -144,8 +145,9 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) } lock_kernel(); - error = do_sysctl((int *)(u64)tmp.name, tmp.nlen, (void *)(u64)tmp.oldval, - oldlenp, (void *)(u64)tmp.newval, tmp.newlen); + error = do_sysctl((int __user *)(u64)tmp.name, tmp.nlen, + (void __user *)(u64)tmp.oldval, oldlenp, + (void __user *)(u64)tmp.newval, tmp.newlen); unlock_kernel(); if (oldlenp) { if (!error) { @@ -157,10 +159,11 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) error = -EFAULT; } } - if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused))) + if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused))) error = -EFAULT; } return error; +#endif } #endif /* CONFIG_SYSCTL */ -- GitLab From 15c130c1cde38da528f82efce882e8d7632f4d91 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 13:18:25 -0600 Subject: [PATCH 0643/1619] [PA-RISC] Fix filldir warnings filldir_t now takes a u64, not an ino_t. Signed-off-by: Matthew Wilcox --- arch/parisc/hpux/fs.c | 2 +- arch/parisc/kernel/sys_parisc32.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 2d58b92b57e..4204cd1f3cf 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -73,7 +73,7 @@ struct getdents_callback { #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) static int filldir(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned d_type) + u64 ino, unsigned d_type) { struct hpux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index e0e4e0bfcc6..29be4377aca 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -313,9 +313,8 @@ struct readdir32_callback { #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) -static int -filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, - unsigned int d_type) +static int filldir32 (void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) { struct linux32_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; @@ -377,9 +376,8 @@ out: return error; } -static int -fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, - unsigned int d_type) +static int 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; -- GitLab From ccd6c355e89a21d9047ae19471629758d3a01959 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 13:27:45 -0600 Subject: [PATCH 0644/1619] [PA-RISC] Remove warning from pci.c max() doesn't like comparing an unsigned long and a resource_size_t, so make the local variables resource_size_t too. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index d3b8fc52dfc..199887a61c7 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -290,7 +290,7 @@ EXPORT_SYMBOL(pcibios_bus_to_resource); void pcibios_align_resource(void *data, struct resource *res, resource_size_t size, resource_size_t alignment) { - unsigned long mask, align; + resource_size_t mask, align; DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n", pci_name(((struct pci_dev *) data)), -- GitLab From f64ef295032d07345ca26bf4876a1577c4dccb37 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 13:33:53 -0600 Subject: [PATCH 0645/1619] [PA-RISC] Fix parisc_newuname() The utsname virtualisation broke parisc_newuname compilation. Rewrite the implementation to call sys_newuname() like sparc64 does. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/sys_parisc.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 1db5588ceac..512642d8f70 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -266,30 +266,17 @@ long parisc_personality(unsigned long personality) return err; } -static inline int override_machine(char __user *mach) { -#ifdef CONFIG_COMPAT - if (personality(current->personality) == PER_LINUX32) { - if (__put_user(0, mach + 6) || - __put_user(0, mach + 7)) - return -EFAULT; - } - - return 0; -#else /*!CONFIG_COMPAT*/ - return 0; -#endif /*CONFIG_COMPAT*/ -} - -long parisc_newuname(struct new_utsname __user *utsname) +long parisc_newuname(struct new_utsname __user *name) { - int err = 0; + int err = sys_newuname(name); - down_read(&uts_sem); - if (copy_to_user(utsname, &system_utsname, sizeof(*utsname))) - err = -EFAULT; - up_read(&uts_sem); - - err = override_machine(utsname->machine); +#ifdef CONFIG_COMPAT + if (!err && personality(current->personality) == PER_LINUX32) { + if (__put_user(0, name->machine + 6) || + __put_user(0, name->machine + 7)) + err = -EFAULT; + } +#endif - return (long)err; + return err; } -- GitLab From 1070c9655b90016ec4c9b59c402292e57ee15885 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 13:37:41 -0600 Subject: [PATCH 0646/1619] [PA-RISC] Fix must_check warnings in drivers.c Panic if we can't register the parisc bus or the root parisc device. There's no way we can boot without them, so let the user know ASAP. If we can't register a parisc device, handle the failure gracefully. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/drivers.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 3d569a485a1..2b257e4f17d 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -424,7 +424,10 @@ struct parisc_device * create_tree_node(char id, struct device *parent) /* make the generic dma mask a pointer to the parisc one */ dev->dev.dma_mask = &dev->dma_mask; dev->dev.coherent_dma_mask = dev->dma_mask; - device_register(&dev->dev); + if (!device_register(&dev->dev)) { + kfree(dev); + return NULL; + } return dev; } @@ -850,8 +853,10 @@ static void print_parisc_device(struct parisc_device *dev) */ void init_parisc_bus(void) { - bus_register(&parisc_bus_type); - device_register(&root); + if (!bus_register(&parisc_bus_type)) + panic("Could not register PA-RISC bus type\n"); + if (!device_register(&root)) + panic("Could not register PA-RISC root device\n"); get_device(&root); } -- GitLab From 1604f31895dcdb42edf6511ce7ef0546ff92c8e5 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 15:12:52 -0600 Subject: [PATCH 0647/1619] [PA-RISC] Fix time.c for new do_timer() calling convention do_timer now wants to know how many ticks have elapsed. Now that we have to calculate that, we can eliminate some of the clever code that avoided having to calculate that. Also add some more documentation. I'd like to thank Grant Grundler for helping me with this. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/time.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index b3496b592a2..1d58ce0e37a 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -38,11 +38,28 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */ extern void smp_do_timer(struct pt_regs *regs); #endif +/* + * We keep time on PA-RISC Linux by using the Interval Timer which is + * a pair of registers; one is read-only and one is write-only; both + * accessed through CR16. The read-only register is 32 or 64 bits wide, + * and increments by 1 every CPU clock tick. The architecture only + * guarantees us a rate between 0.5 and 2, but all implementations use a + * rate of 1. The write-only register is 32-bits wide. When the lowest + * 32 bits of the read-only register compare equal to the write-only + * register, it raises a maskable external interrupt. Each processor has + * an Interval Timer of its own and they are not synchronised. + * + * We want to generate an interrupt every 1/HZ seconds. So we program + * CR16 to interrupt every @clocktick cycles. The it_value in cpu_data + * is programmed with the intended time of the next tick. We can be + * held off for an arbitrarily long period of time by interrupts being + * disabled, so we may miss one or more ticks. + */ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long now; unsigned long next_tick; - unsigned long cycles_elapsed; + unsigned long cycles_elapsed, ticks_elapsed; unsigned long cycles_remainder; unsigned int cpu = smp_processor_id(); @@ -67,11 +84,14 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * of the more expensive div/mul method */ cycles_remainder = cycles_elapsed; + ticks_elapsed = 1; while (cycles_remainder > cpt) { cycles_remainder -= cpt; + ticks_elapsed++; } } else { cycles_remainder = cycles_elapsed % cpt; + ticks_elapsed = 1 + cycles_elapsed / cpt; } /* Can we differentiate between "early CR16" (aka Scenario 1) and @@ -81,18 +101,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * cycles after the IT fires. But it's arbitrary how much time passes * before we call it "late". I've picked one second. */ -/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ -#if HZ == 1000 - if (cycles_elapsed > (cpt << 10) ) -#elif HZ == 250 - if (cycles_elapsed > (cpt << 8) ) -#elif HZ == 100 - if (cycles_elapsed > (cpt << 7) ) -#else -#warn WTF is HZ set to anyway? - if (cycles_elapsed > (HZ * cpt) ) -#endif - { + if (ticks_elapsed > HZ) { /* Scenario 3: very long delay? bad in any case */ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" " cycles %lX rem %lX " @@ -136,7 +145,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(ticks_elapsed); write_sequnlock(&xtime_lock); } -- GitLab From 77dc2db6d1d2703ee4e83d4b3dbecf4e06a910e6 Mon Sep 17 00:00:00 2001 From: Mark Assad Date: Thu, 5 Oct 2006 12:25:05 +1000 Subject: [PATCH 0648/1619] [PATCH] itmtouch: fix inverted flag to indicate touch location correctly, correct white space There is a bug in the current version of the itmtouch USB touchscreen driver. The if statment that checks if pressure is being applied to the touch screen is now missing a ! (not), so events are no longer being reported correctly. The original source code for this line was as follows: #define UCP(x) ((unsigned char*)(x)) #define UCOM(x,y,z) ((UCP((x)->transfer_buffer)[y]) & (z)) ... if (!UCOM(urb, 7, 0x20)) { And was cleaned to: unsigned char *data = urb->transfer_buffer; .... if (data[7] & 0x20) { (note the lack of '!') This has been tested on an LG L1510BF and an LG1510SF touch screen. Signed-off-by: Mark Assad Signed-off-by: Linus Torvalds --- drivers/usb/input/itmtouch.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 61966d719ca..f3e3080de5b 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -36,7 +36,11 @@ * * 1.2.1 09/03/2005 (HCE) hc@mivu.no * Code cleanup and adjusting syntax to start matching kernel standards - * + * + * 1.2.2 10/05/2006 (MJA) massad@gmail.com + * Flag for detecting if the screen was being touch was incorrectly + * inverted, so no touch events were being detected. + * *****************************************************************************/ #include @@ -53,7 +57,7 @@ #define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9 #define DRIVER_AUTHOR "Hans-Christian Egtvedt " -#define DRIVER_VERSION "v1.2.1" +#define DRIVER_VERSION "v1.2.2" #define DRIVER_DESC "USB ITM Inc Touch Panel Driver" #define DRIVER_LICENSE "GPL" @@ -108,7 +112,7 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); /* if pressure has been released, then don't report X/Y */ - if (data[7] & 0x20) { + if (!(data[7] & 0x20)) { input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F)); input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F)); } -- GitLab From d223a60106891bfe46febfacf46b20cd8509aaad Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 4 Oct 2006 19:57:05 -0700 Subject: [PATCH 0649/1619] Linux 2.6.19-rc1 Merge window closed.. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index adb2c748e10..274b780029b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 -SUBLEVEL = 18 -EXTRAVERSION = +SUBLEVEL = 19 +EXTRAVERSION =-rc1 NAME=Avast! A bilge rat! # *DOCUMENTATION* -- GitLab From 489b10c1f63fafcb89c330a0603694652068132a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 3 Oct 2006 16:39:12 -0700 Subject: [PATCH 0650/1619] [PATCH] sky2: incorrect length on receive packets The previous change to do fragmented receive (post 2.6.18) introduced a bug where packets are passed up with size set to the size of the receive buffer not the actual received data. IP silently trims this so it didn't show up right away. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 396e7df3c61..68515150ff3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1907,7 +1907,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); re->skb->ip_summed = CHECKSUM_NONE; - __skb_put(skb, length); + skb_put(skb, length); } return skb; } @@ -1970,7 +1970,7 @@ static struct sk_buff *receive_new(struct sky2_port *sky2, if (skb_shinfo(skb)->nr_frags) skb_put_frags(skb, hdr_space, length); else - skb_put(skb, hdr_space); + skb_put(skb, length); return skb; } -- GitLab From bbedefccc6b0da43cfaf785dac89c88bc59cb6ed Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 3 Oct 2006 12:24:23 -0500 Subject: [PATCH 0651/1619] [PATCH] ibmveth: Harden driver initilisation This patch has been floating around for a while now, Santi originally sent it in March: http://www.spinics.net/lists/netdev/msg00471.html After a kexec the ibmveth driver will fail when trying to register with the Hypervisor because the previous kernel has not unregistered. So if the registration fails, we unregister and then try again. We don't unconditionally unregister, because we don't want to disturb the regular code path for 99% of users. Signed-off-by: Michael Ellerman Acked-by: Anton Blanchard Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 767203d35bc..df3a59efa7a 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -437,6 +437,31 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) &adapter->rx_buff_pool[i]); } +static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, + union ibmveth_buf_desc rxq_desc, u64 mac_address) +{ + int rc, try_again = 1; + + /* After a kexec the adapter will still be open, so our attempt to + * open it will fail. So if we get a failure we free the adapter and + * try again, but only once. */ +retry: + rc = h_register_logical_lan(adapter->vdev->unit_address, + adapter->buffer_list_dma, rxq_desc.desc, + adapter->filter_list_dma, mac_address); + + if (rc != H_SUCCESS && try_again) { + do { + rc = h_free_logical_lan(adapter->vdev->unit_address); + } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); + + try_again = 0; + goto retry; + } + + return rc; +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; @@ -502,12 +527,7 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr); ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr); - - lpar_rc = h_register_logical_lan(adapter->vdev->unit_address, - adapter->buffer_list_dma, - rxq_desc.desc, - adapter->filter_list_dma, - mac_address); + lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address); if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc); -- GitLab From 6b4223748895ed5b200c8049231567ea399fc0c2 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:28 -0500 Subject: [PATCH 0652/1619] [PATCH] ibmveth: Add netpoll function This patch adds the net poll controller function to ibmveth to support netconsole and netdump. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index df3a59efa7a..bd79d67c0e9 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -925,6 +925,14 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ibmveth_poll_controller(struct net_device *dev) +{ + ibmveth_replenish_task(dev->priv); + ibmveth_interrupt(dev->irq, dev, NULL); +} +#endif + static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; @@ -997,6 +1005,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = ibmveth_poll_controller; +#endif netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); -- GitLab From 4347ef15f76dca33ae8da769d6900a468253bda2 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:34 -0500 Subject: [PATCH 0653/1619] [PATCH] ibmveth: kdump interrupt fix This patch fixes a race that panics the kernel when opening the device after a kdump. Without this patch there is a window where the hypervisor can send an interrupt before all the structures for the kdump ibmveth module are ready (because the hypervisor is not aware that the partition crashed and that the virtual driver is reloading). We close this window by disabling the interrupts before registering the adapter to the hypervisor. This patch depends on the "ibmveth: Harden driver initilisation" patch. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index bd79d67c0e9..2ec49d25453 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -527,6 +527,8 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr); ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr); + h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); + lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address); if(lpar_rc != H_SUCCESS) { -- GitLab From 03a85d0907b2455c772b8fb179b0c07a66b00ddb Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:39 -0500 Subject: [PATCH 0654/1619] [PATCH] ibmveth: rename proc entry name This patch changes the name of the proc file for each ibmveth adapter from the network device name to the slot number in the virtual bus. The proc file is created when the device is probed, so a change in the name of the device will not be reflected in the name of the proc file giving problems when identifying and removing the adapter. The slot number is a property that does not change through the life of the adapter so we use that instead. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 2ec49d25453..6aff2bc3df5 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1165,7 +1165,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) { struct proc_dir_entry *entry; if (ibmveth_proc_dir) { - entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); if (!entry) { ibmveth_error_printk("Cannot create adapter proc entry"); } else { @@ -1180,7 +1182,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) { if (ibmveth_proc_dir) { - remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + remove_proc_entry(u_addr, ibmveth_proc_dir); } } -- GitLab From 751ae21c6cd1493e3d0a4935b08fb298b9d89773 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:45 -0500 Subject: [PATCH 0655/1619] [PATCH] ibmveth: fix int rollover panic This patch fixes a nasty bug that has been sitting there since the very first versions of the driver, but is generating a panic because we changed the number of 2K buffers for 2.6.16. The consumer_index and producer_index are u32's that get incremented on every buffer emptied and replenished respectively. We use the {producer,consumer}_index mod'ed with the size of the pool to pick out an entry in the free_map. The problem happens when the u32 rolls over and the number of the buffers in the pool is not a perfect divisor of 2^32. i.e. if the number of 2K buffers is 0x300, before the consumer_index rolls over, our index to the free map = 0xffffffff mod 0x300 = 0xff. The next time a buffer is emptied, we want the index to the free map to be 0x100, but 0x0 mod 0x300 is 0x0. This patch assigns the mod'ed result back to the consumer and producer indexes so that they never roll over. The second chunk of the patch covers the unlikely case where the consumer_index has just been reset to 0x0 and the hypervisor is not able to accept that buffer. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 6aff2bc3df5..16f3faa7ea5 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -213,6 +213,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc } free_index = pool->consumer_index++ % pool->size; + pool->consumer_index = free_index; index = pool->free_map[free_index]; ibmveth_assert(index != IBM_VETH_INVALID_MAP); @@ -238,7 +239,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc if(lpar_rc != H_SUCCESS) { pool->free_map[free_index] = index; pool->skbuff[index] = NULL; - pool->consumer_index--; + if (pool->consumer_index == 0) + pool->consumer_index = pool->size - 1; + else + pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -326,6 +330,7 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 DMA_FROM_DEVICE); free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size; + adapter->rx_buff_pool[pool].producer_index = free_index; adapter->rx_buff_pool[pool].free_map[free_index] = index; mb(); -- GitLab From 70fbf32703a9c4d3403663d1fc24fd8afc76d56f Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Tue, 3 Oct 2006 10:27:10 -0700 Subject: [PATCH 0656/1619] [PATCH] mv643xx_eth: Fix ethtool stats Some stats reported by ethtool -S on mv643xx_eth device are cleared between each call. This patch fixes it. Signed-off-by: Maxime Bizon Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7f8e5ad1b70..eccedf3e627 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2156,7 +2156,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp) for (offset = ETH_MIB_BAD_OCTETS_RECEIVED; offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS; offset += 4) - *(u32 *)((char *)p + offset) = read_mib(mp, offset); + *(u32 *)((char *)p + offset) += read_mib(mp, offset); p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW); p->good_octets_sent += @@ -2165,7 +2165,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp) for (offset = ETH_MIB_GOOD_FRAMES_SENT; offset <= ETH_MIB_LATE_COLLISION; offset += 4) - *(u32 *)((char *)p + offset) = read_mib(mp, offset); + *(u32 *)((char *)p + offset) += read_mib(mp, offset); } /* -- GitLab From 0a07bc645e818b88559d99f52ad45e35352e8228 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 19 Sep 2006 14:55:22 +0200 Subject: [PATCH 0657/1619] [PATCH] forcedeth: hardirq lockdep warning BUG: warning at kernel/lockdep.c:1816/trace_hardirqs_on() (Not tainted) Call Trace: show_trace dump_stack trace_hardirqs_on :forcedeth:nv_nic_irq_other handle_IRQ_event __do_IRQ do_IRQ ret_from_intr DWARF2 barf default_idle cpu_idle rest_init start_kernel _sinittext These 3 functions nv_nic_irq_tx(), nv_nic_irq_rx() and nv_nic_irq_other() are reachable from IRQ context and process context. Make use of the irq-save/restore spinlock variant. (Compile tested only, since I do not have the hardware) Signed-off-by: Peter Zijlstra Cc: Jeff Garzik Cc: Ingo Molnar Cc: Arjan van de Ven Cc: Dave Jones Cc: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index eea1d66c530..35467e0ac53 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2497,6 +2497,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name); @@ -2508,16 +2509,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) if (!(events & np->irqmask)) break; - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_tx_done(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); if (events & (NVREG_IRQ_TX_ERR)) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2527,7 +2528,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } @@ -2601,6 +2602,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name); @@ -2614,14 +2616,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) nv_rx_process(dev, dev->weight); if (nv_alloc_rx(dev)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2631,7 +2633,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } } @@ -2648,6 +2650,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name); @@ -2660,14 +2663,14 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) break; if (events & NVREG_IRQ_LINK) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_linkchange(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); np->link_timeout = jiffies + LINK_TIMEOUT; } if (events & (NVREG_IRQ_UNKNOWN)) { @@ -2675,7 +2678,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) dev->name, events); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); pci_push(base); @@ -2685,7 +2688,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } -- GitLab From 46767aeba58ca9357a2309765201bad38d8f5e9b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 29 Sep 2006 18:26:47 +0100 Subject: [PATCH 0658/1619] [PATCH] libata: Don't believe bogus claims in the older PIO mode register Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dce65651d85..ad8e2c64c86 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -870,7 +870,11 @@ static unsigned int ata_id_xfermask(const u16 *id) * the PIO timing number for the maximum. Turn it into * a mask. */ - pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ; + u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF; + if (mode < 5) /* Valid PIO range */ + pio_mask = (2 << mode) - 1; + else + pio_mask = 1; /* But wait.. there's more. Design your standards by * committee and you too can get a free iordy field to -- GitLab From 39984a9fad0c642182f426d7771332d46f222103 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 29 Sep 2006 23:28:42 -0700 Subject: [PATCH 0659/1619] [PATCH] bonding: fix deadlock on high loads in bond_alb_monitor() In bond_alb_monitor the bond->curr_slave_lock write lock is taken and then dev_set_promiscuity maybe called which can take some time, depending on the network HW. If a network IRQ for this card come in the softirq handler maybe try to deliver more packets which end up in a request to the read lock of bond->curr_slave_lock -> deadlock. This issue was found by a test lab during network stress tests, this patch disable the softirq handler for this case and solved the issue. Signed-off-by: Karsten Keil Acked-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_alb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index e83bc825f6a..32923162179 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1433,7 +1433,7 @@ void bond_alb_monitor(struct bonding *bond) * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->curr_slave_lock); + write_lock_bh(&bond->curr_slave_lock); if (bond_info->primary_is_promisc && (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { @@ -1448,7 +1448,7 @@ void bond_alb_monitor(struct bonding *bond) bond_info->primary_is_promisc = 0; } - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; -- GitLab From 2f614fe04f4463ff22234133319067d7361f54e5 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 5 Oct 2006 07:10:38 -0400 Subject: [PATCH 0660/1619] [netdrvr] b44: handle excessive multicast groups If there are more than B44_MCAST_TABLE_SIZE groups in the dev->mc_list, it will only listen to the first B44_MCAST_TABLE_SIZE that it sees. This change makes the driver go into RXCONFIG_ALLMULTI mode if there are more than B44_MCAST_TABLE_SIZE groups being subscribed to, similar to other network drivers. Noticed by Bill Helfinstine Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index e891ea2ecc3..973b8eb37dc 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1706,14 +1706,15 @@ static void __b44_set_rx_mode(struct net_device *dev) __b44_set_mac_addr(bp); - if (dev->flags & IFF_ALLMULTI) + if ((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > B44_MCAST_TABLE_SIZE)) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); - for (; i < 64; i++) { + for (; i < 64; i++) __b44_cam_write(bp, zero, i); - } + bw32(bp, B44_RXCONFIG, val); val = br32(bp, B44_CAM_CTRL); bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); -- GitLab From 57a58a9435aef3e0342ba4b2c97e0ddfea6f2c7f Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 13:06:34 +0100 Subject: [PATCH 0661/1619] 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(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 6f463606c31..b947d46e4b1 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 4cf65f5c6a7..53e9dce6c65 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 "; -- GitLab From da482792a6d1a3fbaaa25fae867b343fb4db3246 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 13:06:34 +0100 Subject: [PATCH 0662/1619] 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(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 1f97e3d9263..19782350dcc 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 92be519eff2..6879202afe9 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); - -- GitLab From 7d12e780e003f93433d49ce78cfedf4b4c52adc5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 14:55:46 +0100 Subject: [PATCH 0663/1619] 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 +- .../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 +- .../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 +- .../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 diff --git a/arch/frv/kernel/dma.c b/arch/frv/kernel/dma.c index f5de6cf7df4..156184e17e5 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 369bc0a7443..ad753c1e9b8 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 a43a2215895..e0983f6926e 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 39c0188a349..c157eeff871 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 5ac041c7c0a..87f360a4ea2 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 44a9aebc4f5..ed588d73d7d 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 90faae5c5d3..7d500da0e63 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 d07ed31f11e..d53eafb6daa 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 3dd2e180151..8cfc7dbec7b 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 1b080ab8a49..31e5c6573aa 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 58a2d558241..3f221f5eb47 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 6bf14a4e995..1a2a979cf6a 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 8355d8d87d1..cbcd61d6120 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 5929f884d79..07097ed4889 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 80b7f2fc4f4..c639d30d8bd 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 856c73fcb7e..d42422fc4af 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 c36b0f5affb..8a2cb4e691f 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 af7171adcd2..0e81f68aaf8 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 d955aaefbb8..a00b0e7ab9b 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 a8340802f2d..d349eb9e4ff 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 7a941ecff3b..66df5ac8f08 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 0e061890f79..3462b0d98de 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 c3f58f2f9f5..5deaab3090b 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 41521b30c3c..c70e20708a1 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 6a9bc9ce54e..35c6309bdb7 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 85b9244a098..d210d0a5006 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 8533f13a5ed..434fb934dd2 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 b0e95d594c5..21a9ebd4978 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 c2c7cf75dd5..bfc4829162f 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 ee3b223ab17..5c6c15c5f9a 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 39f7ddb554e..e93a115961a 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 311ed1993fc..b1d3d161249 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 f82b13e531a..ad9aec2c6fe 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 253972e5479..f6bd2f28515 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 6ee1055b0ff..db0ec3ba3ae 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 3ee03a9a98f..195215560fd 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 708236f3474..5a854f36383 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 6472e321cad..af4a1c71a80 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 506f27c85ca..b8a407fcd5d 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 557e92af7be..1ba5a442ac3 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 1bace29f4b6..7fde8f4daeb 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 20beea778ea..068fe4f100b 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 54e1f38ce30..25929123fff 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 dce65651d85..77138a39eb0 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 81f3d219e70..9021e34d209 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 e6aa1a86d5c..1b8e0eb9e03 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 d09d20a1779..323b6071080 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 15c9437710f..d636ede064a 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 7f6cc3c07de..710909df4ea 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 3d9fa1cc834..ae5edb80ea9 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 a951f40c2f2..169e200a6a7 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 8c74f2ff434..ae7992de4b0 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 273d88fcf98..e654b990b90 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 da599e6e9d3..8ff5c4e5082 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 df359a6c14f..bc1b13c8f5d 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 5f25e5efefc..40ab9b65fae 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 98622130de5..3a7b21ff30a 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 b22a9142b24..c7314a79da0 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 209dba1c70d..33e9ee47392 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 7487f0ad68e..87b17c33b3f 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 f20b0b2c06c..9ed1c60048f 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 b9568e10965..8895f026bea 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 b8036899e56..632ede55276 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 083c5d3f2e1..7df0f373188 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 b3f639fbf22..3e8ab84b944 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 f9217c34bc2..cec539e601f 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 0b80fbb8dbf..706cdc6a69e 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 4030a8fd118..8e41c87b026 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 2641597c654..5d254b71450 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 c39650920bd..14d6b949275 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 36b88f6c5f8..dcccaf2782f 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 ada68e65b5f..570d2f04932 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 629c5769d99..9e6d3a87cbe 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 5537974fb24..688a4fb0dc9 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 fdc8f892eb8..1a65979f1f0 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 dfda796eba5..ed7b06cf3e6 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 c6beee18a07..47d6975268f 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 45a8f402b07..0d5c73f0726 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 cbb9d0f21ac..30f16bd8365 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 ebf3025721d..10cc38783bd 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 71ac2e3dffc..82e090fea95 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 13ba729cdd5..67cdda43f22 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 efcc28ec9d9..31ade991aa9 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 8eebf9ca378..845b8680032 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 e0231dc2cb1..9fca6513562 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 df7bb016df4..3a96a0babc6 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 746ccca97f6..3b29086b7c3 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 0e99def8a1e..e7c800f4c3a 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 0801af4ad2b..7565642a007 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 ccd91c1a84b..2157c58755e 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 9b05ddd2314..e6d8e9edede 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 dcd1ab684f3..60e1978ec0e 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 30ab56258a9..f77ada933ea 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 486f97c3f4e..66086fa2d59 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 10a389dafd6..1f0b752e5de 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 87b2fb51087..e608dadece2 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 695115d7038..2908b72daa6 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 abac18b1871..77f58ed6d59 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 05788c75d7f..15a4ea89632 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 21653244565..bbcf918f056 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 d69f2ad9a67..1aa93a752a9 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 58b0eb58111..091a11cd878 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 4053d1cd393..9902ffad3b1 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 0b89bcde8c5..8728255c946 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 c07dc58d5c1..2cf63e7305a 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 62ef511d143..858ba5432c9 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 b106c45abfc..24825bdca8f 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 accaaf1a6b6..73f759eaa5a 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 ea2bbf80ad3..e9e9bf31c36 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 e2011669c7b..20b6c8b3024 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 63635472265..0afb7ba999c 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 1f0f2b6dae2..22b9905c1e5 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 cc3e54dd723..f282976daaa 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 8253fca8efd..048d91142c1 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 ea1aa7764f8..2d264971d83 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 ddb7b928dcb..c3ebc16ce8a 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 73e32420991..1a0bc30b79d 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 520d2cf82bc..efc485edad1 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 9d134e98d2a..5c9477741a3 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 202a3b0945b..3bea594600d 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 b0ab3f28cc6..be68cfb0ae6 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 656f8c0ca52..abee7a33946 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 65c751d0d64..4217d38caef 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 f4809c8183c..6f13f98e317 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 07e0b75f233..52753e723ea 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 864854c5886..2f56e8c5489 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 d4e434d694b..c084149153d 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 902c48dca3b..6022495571a 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 bd711537ec4..522e88e395c 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 8fd71a5fc61..5fec626598c 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 a4150c4519c..f2864cc6424 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 bdc7cb248b8..d4334c79f8d 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 6eb75dcd796..3e932b68137 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 6b4d4d1e343..4c0e0868570 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 d2c5ba4e83b..2444a0e24b3 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 ee7ac6f43c6..483f3f60013 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 c2ca31eb850..0cdbaa70cf9 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 8116a47b80f..8e794930517 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 4f4269754c4..e228d6e173c 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 02d336ace50..3404a9c67f0 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 77662cb0ac4..bda45334d80 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 b36a04ae9ab..68b1ca976d5 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 13f23f4a223..517fbd8643f 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 89a249e23fd..e4cf661dc89 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 74d8cf836e1..ce1261c5cbc 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 dbd4d6c3698..f3bf1e230bc 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 3b07e0ca81c..b09dfc78e5a 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 2b75edc5859..a6b1ae256e1 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 caa8e5c8bfb..a591fe685f0 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 80d4ba1bdfe..781a99c1647 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 4436c89be58..d108ab4974c 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 559a62b04ee..f7d71869b3b 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 155a986de51..ee65aa1be13 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 eacbaf745b6..bbc8e3a7ff5 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 3e276e958ef..f28a76d1c0a 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 81d87d2c2a2..dec04da0455 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 d9b4ddbad7e..407840b6a26 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 cd4ad98ad51..81050d3c9b2 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 0ebec3c1a54..8764df06f51 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 9ebe429a0a0..4ca6de209b8 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 182f0495346..ccdf3e90862 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 6a757821717..60bef94cd25 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 ba6039b55b4..2614f41b507 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 4ab93114567..b1d5291531b 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 d655da74914..b1730d7e414 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 8fd0030475b..dea13525df8 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 b4f146f2c95..0a7412e27eb 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 9e9120f3601..dc1ebeac35c 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 2a65b5be197..048cc443d1e 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 85bf1fe16fe..be579cc0adf 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 6bee53ce5f3..d9079ee1203 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 d7540b71b45..7c436697d0e 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 a29b1b6d82b..e284e0613a9 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 7249d324297..650acf3a30b 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 8632d47a7fb..808f05932a6 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 64a78c51548..ca08f45c204 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 fe79d158456..105112fb7b5 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 947df273984..ffaeaefa1a4 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 168b1061a03..e3d19444ba2 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 7a19ee05297..2a9808cf826 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 3e2782e7983..c4db0247c5f 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 011ec4858e1..1ffb0322331 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 076f237d965..49085df2d63 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 f9c1a03214e..35edea1ab95 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 f1f9db9d282..8abdbd0ee8f 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 40244d4ce0f..b6ef9eaad1d 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 1e03153b9bc..cb70970625b 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 2e4abdc2636..c9b0b8978cd 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 d22c7c62429..54bc569db4b 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 5174224cadb..708d5a1bc3d 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 83906f80ba2..fd33c9cc327 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 40a3f551247..9282e4e082b 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 d436287d1d2..5680a6d95b2 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 e385710233f..8b18c009e3e 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 04c54c57f25..e60937d17b1 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 9dbd7b85686..cac4781103c 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 0821d53cf0c..8c11dc93545 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 805b636e73d..105c6fc2782 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 450b68a619f..4e71a66fc7f 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 c8b2cc9f184..599a7b2dc51 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 69f02178c52..402b057e986 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 50f1fed10be..e1252fa9a10 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 5e9d2506751..c57e8853b94 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 9c7ce38806d..8e9c2f3d69a 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 7972eecbcfe..8a4f862709e 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 d284ea71215..8c075aa7223 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 9fb7eb6b0f7..6f9b2c7cc9c 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 4d9107fba6a..1b74cae8a55 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 872b30bf7aa..ea046856961 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 680b3235388..2a272c5daf0 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 392108c436b..49ac696d6cf 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 47edcfd022b..ffdb50eee93 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 3df5eedf8f3..5a7b49c3553 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 bc6e87add09..0d35018c23a 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 cde036a9216..081fdc3c773 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 a10348bb25e..ba7b920347e 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 1bb0c76a925..09b06e605b5 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 f08a5d0cd5f..558200e96d0 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 a5c1fb3a4a5..688610e86a3 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 fb727c66525..ea5e3c6ddb6 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 d3827c5fe11..cb89aff2e16 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 513d37fc1ac..49f84315cb3 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 ebd9976fc81..559508795af 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 3e76ad71c9a..960fae3c3ce 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 71a8eea816c..ba2a2035d64 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 54a680cc704..e1a3a79ab3f 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 66e411badf7..f56d6a0f062 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 9b66271d3ba..ca79b224619 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 ab565335ee4..913e1b73bb0 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 b769b21973b..817c2198933 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 e2b91001877..d9e61ee05ea 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 ee6c2f40cdf..e31c6c55b2e 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 3226830eea0..4cbcaa6a71e 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 8647a905df8..3b4c61664b6 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 f7370109d43..6c7d0c2c76c 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 1c89fa53865..c74f74e57af 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 a7b4c755958..9911820fa2f 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 bc98d77c5ec..3014495b7ff 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 5cfbe6a3801..0c937325a1b 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 6e05d9d4a51..4ffa9eb1c28 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 3b431723c7c..d964f07e4a5 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 0c7061d5502..da272924771 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 a4beeb46c85..ddd47cdfdb1 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 6c3d5f5f1f4..2a3eb38f0eb 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 5a2f854d55b..e47c60b0a8e 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 8ab8027f33c..ffa2afa77c2 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 b7dadba13e8..dae2e83dd5e 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 8ae08c41c85..bec59010bc6 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 93ff941c48f..61e69e9c4aa 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 729e906bdc6..d9028e9b9b8 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 574e252dfa4..c87fa3f9b29 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 369afd3a3a4..b04a178e502 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 87a630128a6..871310d56a6 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 dae090a9a48..34031064534 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 e294fa3918f..7e95f04f13d 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 3b3e318f607..fab3e4ea059 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 76c7d29d1b2..b45de9d408d 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 fe293726777..3efa719b6d2 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 0ca5e66d2f5..d852c9d998b 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 1df60ca9481..93f60b56351 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 b7e8e23be33..954d1536db1 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 6b88ecb5047..7105b043add 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 4e7f472877e..57670dc5034 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 2f9d5118cea..159c5896061 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 881a4165cfb..f6db55a752c 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 2cf7b665609..da706925d54 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 565b7892c26..282f349408b 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 715a1a8cd69..55de0695354 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 39717506c67..252d79de5e5 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 8c82519593a..a81d175d9f6 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 1080508f3c6..4d89d3ea417 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 0945336c28d..e5918c6fe73 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 80025fd890f..c09ffb13533 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 37497162d53..8202cf34eca 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 e76042d323e..150ef68b4ae 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 d943d365890..c99b16690fb 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 8d8e8a29989..9522141f435 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 a49b694eb73..02209500b3b 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 aca2a3954b1..75d0f248e4e 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 98adec44059..1d8c2618366 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 b096b64b025..ff159512204 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 e94dc6f5bd6..0909662b745 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 f94af0930a1..48581335f43 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 5cb712437da..6a5e379e077 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 dca446865f2..d09f6d033f1 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 0595293b865..1655341797a 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 73afebdf80b..160f22fa594 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 ba766930f08..13e7d219d1c 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 0d99da3a3e2..2ac295e1a6e 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 a627e68023f..222ca7c08ba 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 ae6263125ac..cd17de18cb7 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 d56d400b6aa..1ffee7aaff2 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 360f93f6fcd..be0bd34ff6f 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 b7fb367808d..5066e7a8ea9 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 4b08852c35e..57ccc19cbdb 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 c0f9d82e466..ade25b3fbb3 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 7512d1c1520..64a07ccfe36 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 2a2ffe06016..ad4bd579f61 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 0129fcc3b18..789ee52086f 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 4f04fd0956a..e63ea1c1f3c 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 9f4eff1d1a0..98ec915d040 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 b88451e33c0..86cbdbcf9d7 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 eb2e6432c8c..06893243f3d 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 515954f96c9..2853ea1bdaf 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 755822ee6e9..329a51c1856 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 410fa6d620f..ff7d4f56ced 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 572b2d9aa66..78035ee824c 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 2310b2bfed4..8e4ce101eb2 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 234199875f5..60820deb900 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 de077a75719..a1c9fa9919e 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 5c5e682a300..4861799eb43 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 50dde82844e..6e1ddad9f0c 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 f4da0294149..28dc6a1a1e4 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 2ee34a3b928..9da4726eb9b 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 f0340662e07..e4355fdc3b6 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 d6d980774c2..6b23a4e6f66 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 cb0c0eea20f..90e298d074d 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 b9ba95f5e02..b1012e92ee0 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 4350cc75b02..255a47dfb84 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 8992b6e62b9..bc544cc7ccb 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 e278753f8f2..b083338823d 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 5d8cd283fcd..ce4886f1528 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 3484e36b680..368d6e219fa 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 3d8cd0daf6a..f920e0ccacd 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 1e393762546..70aa63eba0c 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 53c4b5790d5..c77b85cf3d8 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 a39e0136ce3..4abf5c03a74 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 09aa62f61af..5c9e63dfbea 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 2e3ba5f3145..bfcb860d14c 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 67987baee77..7aeec574d7c 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 48d138a7c72..3e0ff8a7846 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 5686547ba76..525d81288d5 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 2ba2991a214..87e11300181 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 4eee8be8831..abe21461909 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 56e01b62241..9a26b9484aa 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 13b37c8c0d5..d8b88024bc2 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 d1e04f7c530..6b6dff4d236 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 2912326a5ae..ddce2fb8342 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 1b2be2d2a3e..5b556342442 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 3cbac2e8aed..d9d5020a222 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 f19705cbdb3..37fa86a3408 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 b5ffe53c40d..0cbf564388a 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 29d0635cce1..e5c72719deb 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 dec41cc8993..62f1ac08332 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 2bf32721eb5..149810a084f 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 634d538ccd1..48d5abebfc3 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 47949a2c7e9..a3c589b7cbf 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 0f9e3aa34d0..a40fda6c402 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 e689ee94ac3..bbdba7b37e1 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 a7ed3044618..b1748669e05 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 cb142a66098..494b23fb0a0 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 61268da1395..53ffcbb14a9 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 1b79dd271aa..659d4a822cc 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 2b5a0cc9ea5..828503c4ee6 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 52c9e52e6b7..762fa289589 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 ef350908478..a526698b8c9 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 20711acb012..6d024342b2f 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 88c6f0b129f..ced309b37a8 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 1b82bccd8c7..11d170afa9c 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 39d33247475..c56a2c62f7d 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 ab8230a68be..458cb9cbe91 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 8205a535c5b..aa43563610a 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 b936373ab2a..7ad0a54779c 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 91f2232e605..c307ce66145 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 cf8a0bc3bf3..1c97271112d 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 625e57dc3b4..d516c3225ca 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 df42e28cc80..80bdcf84623 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 db7b19a5cd5..8e996b4a34e 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 5a4990ae373..458dd9f830c 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 dbc5c0b1b96..d02ed51abfc 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 c9e4dca9d41..8236f26ffd4 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 9d34056147a..fa3442cb1a4 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 ca4eb0ccf8c..f44f1220b3a 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 5f7258fea19..d76548e7535 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 71a4f60f732..33c6645455a 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 efb14b9f4d9..8ca8534d70b 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 28855a01ed7..ef65e5917c8 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 643b08cc740..9164d8cd670 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 ae7f828344d..cc1a27ed197 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 d5666c37cb0..2ea44ce4981 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 5a95005253f..4e91dab1f17 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 3aef3c10d56..9dfc09b181c 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 09d5c3f2698..ddd12d44ff2 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 3ecf2cc53a7..b54b857e357 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 d231efa624d..127561c782f 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 312955d07b2..f3478a30e77 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 081074180e6..84686c8a5bc 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 4aeca11f3ee..8620a5b470f 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 92b52138aca..4e3bf6a1f22 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 a1026251b93..3b543614928 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 b6570ca6ada..d79489e4624 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 f2c8e0d5497..062f80e2087 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 ac33b1b9cf4..4873dc610d2 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 e891ea2ecc3..b124eee4eb1 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 4adfe7b7703..4528ce9c4e4 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 6b4edb63c4c..01b76d3aa42 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 7694365092f..521c5b71023 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 5f1b0675346..ad7ff9641a7 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 ddd0bdb498f..9799c12380f 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 6d0d24a6364..91af47bab7b 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 f1501b6f247..966b563e42b 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 e4d50f0de93..4ffc9b44a8e 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 0b930da5d47..d9b006c9e36 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 e4073015dcd..1288e48ba70 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 a18d4d14b66..b6ad0cb5055 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 bbccd741cdb..e179aa1c1ba 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 ae9680552b8..8f514cc0deb 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 af594664df5..f87f6e3dc72 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 d0842527b36..6b1234b09fb 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 7e95cf1a487..9d446a0fe0b 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 a860ebbbf81..3641f3b4a2c 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 26073c34521..27d5d2f0253 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 778ede3c021..773821e4cf5 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 7dca38fba6a..ce0d35fe394 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 09ff9b9418f..aae454aaa1c 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 499e93b31f5..e28bb1e38f8 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 9cb05d99ee1..05ca730fe81 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 263d1c5b3f2..c6b31775e26 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 ba2565ee043..3a6a83d3ee1 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 f16b6a5aaa3..8cc3c331aca 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 75a43f7c70c..c8c41f0a47d 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 191bd429076..38a13f44053 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 55d86bc4c10..6764281b453 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 e17a1449ee1..8e7a56fadfd 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 eea1d66c530..99b7a411db2 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 d01870619a4..cb3958704a8 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 280b114e253..a06d8d1aace 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 c35d47c40c3..9e81a50cf2b 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 5c89ae78a51..c3c0d67fc38 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 9220de9f4fe..1ed9cccd3c1 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 77411a00d1e..5930aeb3501 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 55906c7b4bb..59214e74b9c 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 de95de8983d..3bcc57acbe6 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 c9a46b89942..0f8b9afd55b 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 df4b68142ac..ec9b6d9b6f0 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 f98f5777dfb..3c4455bd466 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 ae8ad4f763b..844c136e992 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 d52e3bd0130..ffeafb28f78 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 c3645908034..92f970d402d 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 af50e7b2e0d..6c0f071e405 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 2a95d72fa59..3f946c81151 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 767203d35bc..4bac3cd8f23 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 87650237dc5..e963dbf816b 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 68d4c418cb9..971e2dee1e6 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 7b2b4135bb2..37914dc5b90 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 33c07d5275d..7a9128181e6 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 383cef1f599..14bda765c2f 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 ba4f3eb988b..6ea78ececca 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 fc89c8c3dd7..4393168347e 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 415ba8dc94c..b32c52ed19d 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 1a723d725c2..b18148cee63 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 7185a4ee3c1..ea12e999814 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 afb19e8d95c..f9a1c88a428 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 8d5a288d797..937372d0039 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 22358ff68c4..31c623381ea 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 12103c93f7e..be8a66e702b 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 d916e1257c4..c3ed9b3067e 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 92d646cc9ed..18c68193bf1 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 7de1afdeec3..b4fb92a7baa 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 984c31d1b3f..0343f12d2ff 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 41b1d08fd57..2284e2ce169 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 cfde7c2569b..e09f575a3a3 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 6eeb965b4d7..a4eccb11d67 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 f349e88e0dd..7afac47e59a 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 da1eedef0b5..8cbd940f0ac 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 0258aaca9ed..b833016f182 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 8472b71641d..e960138011c 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 27c24eaa241..2907cfb12ad 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 696d5513e55..464e4a6f3d5 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 55b1495a70d..c1aa60b9a98 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 07e58f4a291..c9469985bd7 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 7f8e5ad1b70..d26a819a973 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 4330197994d..fdbb0d7213b 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 a925bc9db4a..466b484c9fa 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 d7b241f7d7b..ffa0afd2edd 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 30ed9a5a40e..a53644f6a29 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 383c690eefe..8be0d030d6f 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 e8889235996..26e42f6e9fb 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 fab3c8593ac..340ad0d5388 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 e10da1aa3d3..b0127c71a5b 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 2687e747657..00ca0fdb837 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 2418cdb9d31..04600992852 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 a0e2b01c027..231fa2c9ec6 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 a8891a9000a..e5f36691091 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 d682f30dea6..65f6fdf4372 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 7d5687e9460..e77110e4c28 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 a09c22840f6..0c00d182e7f 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 a2f3a0e2a00..20fcc357620 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 62664c01eb4..f3914f58d67 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 a43e24245b7..c73e2f21077 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 f5aad77288f..3af9fcf76c8 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 d4f54e9798c..c0b333d2917 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 15747184634..ec640f6229a 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 4c47c5b10ba..f1c75751cab 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 6108bac8d56..d81536f90df 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 99451b52339..9f3e050c4dc 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 1bf23e41f58..a231ab7d28d 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 3afd9126a59..72f52dc98f5 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 c479b07be78..c9efad8a917 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 a1789ae5927..dc30dee5537 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 e4c8896b76c..db2324939b6 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 20afdc7f2b9..d9d0a3a3c55 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 f95a5b0223f..a833e7f9757 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 e8f26b79bba..aaba458584f 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 28606e20df1..fb2b5305163 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 99e92627642..d4913c3de2a 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 37b88da1abe..96e06c51b75 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 8e4d18440a5..06ea2626c6f 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 705e9a8fa30..a4a58e4e93a 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 396e7df3c61..459c845d664 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 7986514883a..889ef0d7c37 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 a621b17456e..2c4343395a4 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 5506a0d3efe..c0d13d65091 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 d7e56438b5d..506807fa526 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 fedd1a37bc3..636dbfcdf8c 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 870cf6b0738..cfece9676af 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 7f886e8ae28..7db13e4a7ea 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 1397fc55cf6..46a009085f7 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 3d617e8f54b..7a0aee6c869 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 0605461bc56..d1d1885b029 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 61a832ce7cc..91c76544e4d 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 9e4be86495a..6439b0cef1e 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 6b8f4baf87f..41c503d8bac 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 0975695ae31..253e96e7ad2 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 f05eea53623..45d07faf7b9 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 feb42db10ee..9207e19cac3 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 9202a1c369d..020e7817059 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 60f02650948..81ed82f0b52 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 c25ba273b74..327836b1014 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 8d807bf603a..e14f5a00f65 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 412390ba142..7580bdeacad 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 4470025ff7f..bfe59865b1d 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 bfc8c3eae9a..e999feb8c0b 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 666bbaaae82..ed274d6909d 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 85831484bc4..cd142d0302b 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 85a7f797d34..9bd4cba8787 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 c1925590a0e..c0ab6e44eb1 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 30452c67bb6..2a16078ac3f 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 e1b48bd8664..2cfd9634895 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 fb5fa7d6888..e17f9779ead 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 ccf2c225f08..4dd8a0bae86 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 7f8f5d42a76..e3488d7b8ed 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 25668ddb1f7..ad107f45c7b 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 831919a8191..0aee618f883 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 0b176be51eb..229158e8e4b 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 2fca1ee24f5..002a05e0722 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 629eac64528..61d313049dd 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 312788caa4c..a998c5d0ae9 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 d5c32e9caa9..3bf9e630404 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 700ebd7d145..12cd7b561f3 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 cbebf1b96e9..ebbda1d8f54 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 7d8808ce541..74f894795a1 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 1f95b4864ea..e1bf8b93f95 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 a5e7ce1bd16..12363e056b6 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 af4d4155905..25021a7992a 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 564351aafa4..c45d6a83339 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 dce2bb317b8..8d0a1f2f00e 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 7b5d81deb02..2b54f1bc3a0 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 8d9b959bf15..5823e3bca17 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 fc75bec1902..fc5c0c611ff 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 0ba018f8382..5715d25271f 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 ec68f7dfd93..c7360157433 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 caa48f12fd0..59ddd21c395 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 77e53208045..158aea7b8ea 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 39d09345027..0a33c8a56e1 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 bb6bea4f323..4688e56b69c 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 0fc267d626d..31eed85de60 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 eb65db7393b..bad3452ea89 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 d500012fdc7..ed00ebb6e7f 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 599e2fe7618..4e4eaa2a99c 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 5685d7ba55b..1f742814a01 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 36b5e004305..6714e0dfa8d 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 9e19a963feb..793da5f6934 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 fb5700d6c45..4720fb20d66 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 ab3c5a27efd..ec1c00f19eb 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 5049f37455b..2f7e525d0cf 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 e82548ea609..0b381d77015 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 5b69befdab7..24221e476cd 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 5cb0bc8bb12..72b646c77d5 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 0065f057bb1..cadfe132db8 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 f34a36b0c7b..4d1c4905c74 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 e3ae5f60d5b..a1430352169 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 80af9a9fcbb..30057a335a7 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 5c265ad0485..3faaeb2b7c8 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 a4c4953f136..ac600212d9a 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 656d5a02908..2068a109a86 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 0d96c50ffe9..a0a8fd8d212 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 884965cedec..094562e044f 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 b45aa5c675a..1b3e3fd12d9 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 a3dc456709d..762a1babad6 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 2eb3577a88c..97e9dc066f9 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 4ee26a6d9e2..1fd97f7c8b9 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 83ee095ec6e..ff9f3445353 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 7ff09f0f858..5accaa7bde3 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 5126e74ac2e..a0afaee5ebe 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 78c3f34108b..6ea9929b8c7 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 1850632590f..74f4e9742c6 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 7352104f7b3..a7c5ead9a3d 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 46e06e596d7..e3e19277030 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 b2b8092a2b3..6541cde4df0 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 fe800dc0be9..39c96641bc7 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 fac333b279b..d758c90c86a 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 94dc506b83d..fd9129e424f 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 d5df5871cfa..d06ab404513 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 c74e9e37e76..ea040c32f47 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 ae2dd36efef..3ec2ad7db49 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 6ab3b6cd2b5..703a64a39fe 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 0f9798df470..4d8aee11913 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 0d4ac027d53..04c43ef529a 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 40569f40e90..991e084db2d 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 ad02629c8be..db3c26b5de1 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 2163aa75a25..82715f44895 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 9c14599d067..b0d453303c5 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 1cc2682394b..ea74f98a735 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 9e768eaef17..36fdaa58458 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 61d50b5620d..0964fd76bfe 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 d0f68ab8f04..e070a289676 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 01be47e7273..c8e838c6976 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 c8323399e9e..74cebd42403 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 22c5e7427dd..c83a0a6b158 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 ecaa132fa59..3627e52e0c2 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 65a60671659..2d2f415f80a 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 e076a13db55..e90d8e8c5fd 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 d19a9138135..812f038e9bd 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 1344746381e..26229d9da76 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 5c8ec21e108..a685fbec460 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 c0714da4492..bd61e99540a 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 9647188fee2..78552e6e76a 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 739d1a6e14e..f13daa9feca 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 625dad2eeb4..e301dea57bb 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 439c41aea31..bd4d7d174ef 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 d2ce0c8bb8f..8b6efcc0505 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 58e5ed0aa12..e40322b7193 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 a305d409154..a54b4ac6756 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 d05681f9d81..9859cd17fc5 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 c39ffbb86e3..778844c3544 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 2684150917e..2650a5d0a16 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 08540692860..f77016d31ca 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 7bf46d40b56..1299bc8edef 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 a1d214d770e..dcc8b0ea7a9 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 f906ead239d..511b0a938fb 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 773f02e3b10..83695416b2c 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 fb6a476eb87..e04c2bc1932 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 24f0f546179..d7a61a6bdaa 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 6b35ed8301e..c3c38a7e8d3 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 1faa008b5b8..f8e60486167 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 601340d8441..fb3d4dd5441 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 339b85cb61c..43ab753d273 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 d42a71ee076..a87a4ce090d 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 3eae8062a02..7f0adf9c4c7 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 1d8c5e5f442..3c2d7a37993 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 8498144aa5e..14319d1d680 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 1b637592d5a..7cd63a99688 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 475f978ff8f..086cc97eee8 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 0525d672e1e..9cf902b7a12 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 719af0dcc0e..19edd9c853d 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 dcbb4b2b3fe..3f876fb7546 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 b2c346a4705..ce159c15bc8 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 e397129c90d..0f920c84ac0 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 8d5d2a5da96..cdc710ea00f 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 e1be4a4387c..dfb1bcfae82 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 0ec41f34f46..fec58cc47f1 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 7c9c0366cc0..ea3e4b2b922 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 c6118d99385..81e3ee51d89 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 eb32062f7e6..c29ccbc4469 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 b20b37661d6..60b1b434eba 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 28998326492..fd79068c586 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 a5ff43b1b26..2d38025861a 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 d312633db92..811d8840707 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 5630868c1b2..2c2fe80bc42 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 dde3edf35c0..ef8285c326e 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 b0694dcce24..41b05fc4538 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 0f3eb22b979..4bc14ad92e2 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 18dbe5c27da..2f6c1137a6e 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 28bfb8f9f81..bec83cbee59 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 2be1dc5d852..0e57fb6964d 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 01b8ac641eb..227c0f2f4d7 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 59a4097f125..312190a6938 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 9e10dac61cf..911f2ff4a1f 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 e1fe9494125..2dde821025f 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 9a9ab297cf1..f06a06ae609 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 3d684496acd..1251788ce2a 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 70f4d5a1348..24a1779b9af 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 6422de72bf4..753d88306cd 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 118206d68c6..3586fac9be9 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 b87bef69ba0..86099fde1b2 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 4b75fe619d9..66529f11d23 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 266b3910846..c0edb662d86 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 977b6e8d852..7e4262f2af9 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 683fc7ae4b8..c773e35dace 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 9b991b746d1..1ddd7a11a95 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 c7a12533fb2..73e33b37a3f 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 b28712df0b7..6cc2bc2f62b 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 78818b6684f..cb8b7701431 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 1c624ce8189..7c13f6f4a4c 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 053303d3611..b1d34604952 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 8908b8e5b78..a88714f4c05 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 0b65099acb1..72fe5d055de 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 5c2cdf523c3..a720c9265e6 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 9f33e5946c0..2521d548dd5 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 c37a30aa214..bab33f6d0bd 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 bef7011378c..75138109b13 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 45007ee5806..d3023338628 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 5fa933cda99..626c7178a43 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 418fb7a13a6..1de08002c43 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 b584317608d..1e283321a59 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 52fb2ec3da7..1a7de3bd796 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 4b3df200366..8fd5555c75b 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 5b2f0741a55..ed58bb48988 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 4e6666ceae2..8ff1f2866f7 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 4f1db6f2aae..e81f97a35bc 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 a54e6c1026b..185c270bb04 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 7f9bcef6adf..5ec5af8e337 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 44a99aeb818..e625b4c5833 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 f5742b84b27..e8faab16567 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 8640253d621..32c883f1efa 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 739d3ef46a4..4d78c7e87cc 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 028d5f641cc..0f0ac925d31 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 57449611e71..3de08a15de4 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 0372aa9fa19..107f0fc3494 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 a0b61af48f1..331e1cf159b 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 76d83ade985..6a1a568ca64 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 bac853c5abb..9b8b585513e 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 1b299e8c57c..4e56ec80386 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 cc2a205d423..e34bd03cfce 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 7311d8487c9..4213fabc62b 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 a8d7124e84a..d503625730d 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 955c46da580..391a1f4167a 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 f27d852ce50..59801271488 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 a0d6136deb9..0abb544ae63 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 9851d9eff02..7a24e53546c 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 8a98aae80e2..53662b33b84 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 a3c00a25214..8aa0f641866 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 4a142d6b8f3..ee5c782597d 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 8097cd91f16..2308d26c862 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 5ec4716c99b..98ce88d8020 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 dbf13c03a1b..dca6c1bde8f 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 043f50b1d10..12c934a1f27 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 a5fc589d6ef..8fa31e68989 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 28c9ce6f0bd..c85ac1a7760 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 00d7859c167..aee1b31f1a1 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 dbad0e31e00..039c2fd6d49 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 704243c9f78..8eea69f2998 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 7502109d37f..e92d7e1c22c 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 a3b99caf80e..bf9809ed9c0 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 a720953a404..846089f222d 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 95738a19cde..8dfc2dd058c 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 db3486d3387..d4065266b6f 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 23ddedbaec0..5e1ac356bbb 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 ebd8d2bb17f..2a48289ac72 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 5c025d1190c..266aa325569 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 2f148e5b925..709f93a6c18 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 f851f0f44f9..03941d27d15 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 cfe20f73043..08a7cd6a3a0 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 9b3b9aaa6b9..c577faea60e 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 0da3ebfff82..b11f6dea270 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 f802867c95c..28f3bbff87b 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 6c8b0ea83c3..fd51f8182de 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 6c7e0352d56..3d91b6b9287 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 29aec77f98b..77122edeb20 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 5d92a7e5cb4..ff0b04895db 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 20eb6e95a3a..2ebe1fc4c39 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 622881f2676..7c0fe1dc96a 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 04631dcbabb..3892a9e9aee 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 956b7a1e8af..7c7b507af29 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 465961a26e4..f5434b1cbb1 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 a38701c742c..309073f6433 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 71288295df2..ec4d1d75672 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 9cac11ca1bb..a161d70e1e4 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 3f509beb88e..2c9c9462d89 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 e658089f7b5..afa2dd20332 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 676877c15f8..8f8df0d4382 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 7676690a038..66bff184a30 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 85b1cd18336..fccd1952bad 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 77beba485a8..72f3db99ff9 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 7cf2999e861..a3076da3f4e 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 36db7257937..179259664c1 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 3bda37f9a35..d954daa8e9e 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 8c18df86983..48a09fd89d1 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 f1adcf8b202..f42c00ef0bc 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 5ac91859113..aac6ec5dd7c 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 b2ee13c5851..2012213c0a2 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 08d0472d4f5..35e3fab6fc4 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 7fc25b6bd7d..46327272f61 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 e5e9c653c90..65c402a0fa7 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 61e571782cf..87eca6aeacf 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 a72e041df8e..2718b5dc4ec 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 d1d68c40225..9be6b303e78 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 ec75774abea..6f113596af6 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 e372306ed0d..e08d1a2664e 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 3a586aab393..5fa5647ea09 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 0a315200b33..32c635ecbf3 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 eb4eab98e8b..45ee6920a85 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 16fb72eb6fc..f8347f1a10b 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 431e8f31f1a..06115f22a4f 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 ca6305c1d64..63a84bbc310 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 5f861331932..3038ed0700d 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 d83603ba40a..0096373b5f9 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 b138dae2b05..bf428184608 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 0aa9cc2bfd6..4c213513484 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 3558d7ed99b..f659f3028ad 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 ea71de81ca6..f982a2b4a7f 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 e0fd11605b4..a6738a83ff5 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 4c62afbeb43..9a808a3b4d3 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 b03fd9b075d..9b50effef75 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 a2b419d1374..7dc14d0cacc 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 f3e3080de5b..aac968aab86 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 604ade356ea..fedbcb127c2 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 a9035955157..50aa8108a50 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 5dce951f275..79a85d46cb1 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 f0f8db6810a..0bf91778c40 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 30b9f820e7a..05c0d1ca39a 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 5067a6ae650..c73285cf855 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 0fb792be95e..cbbbea332ed 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 923e22db18d..f26c1cd1129 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 832737b658c..7b3840e378a 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 7c3b52bdd9d..d233c37bd53 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 85d458c98b6..aa31d22d4f0 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 9889b1cda05..cebb6c463bf 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 7291e7a2717..905bf639825 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 d3963199b6e..aecd633fe9f 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 fc6cc147996..6b23a1def9f 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 4fd2110b341..0be9d62d62a 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 c6f2f488a40..0eb26a26115 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 10b640339d8..788a11e6772 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 77c36e63c7b..27089497e71 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 78e419904ab..abb4dcd811a 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 6b59b620d61..5c780cab92e 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 a287836e39f..b99ca9c7982 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 dbaca9f1efa..ada2ebc464a 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 983e104dd45..7c2cbdf81d2 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 4081990b7d1..7e8a0acd52e 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 9c0eacf7055..c73dd224aa7 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 be5f5e142dd..f740325abac 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 3155f25f1d4..a3242be2195 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 544d41fe9b9..957d4ad316f 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 301baa72bac..ce00de8f13a 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 918cf5a77c0..33abbd2176b 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 2364c209938..72171f94ded 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 98a522f1e26..24bd3486ee6 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 2ccd9ded52a..81227550913 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 6e1a84a858d..2c19f19b255 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 70ece9e01ce..8835bb58ca9 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 d954ec34b01..a63c3286caa 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 e1173c1aee3..f2e89a08365 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 9b225183fc7..bdb58100fc1 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 daafe405d86..4ce10a83195 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 e774a27c6c9..d3dc1a15ec6 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 4b1196a8b09..4543152a996 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 21cbaa0fb96..36042937e77 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 c49976c3ad5..91bd3014ef1 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 17c5b1d2311..ee0c921e152 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 cbc725a6c58..6238aff1e77 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 812bc213a96..2a4bb66691a 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 1b348df388e..331bf81556f 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 015ad6cc1bb..53be824eb1b 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 59e777f1e8f..909005107ea 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 2a2f3e2da05..17e205699c2 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 d50dce03495..ff03331e0bc 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 f4d4305c2c0..b7582cc496d 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 95bf57166c5..2306d493e55 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 ac3f8b5d2c4..0610409a656 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 a764ff4e326..bc91d3b726f 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 c856e6f40e2..130afbbd3fc 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 9c18173e33f..bc800c8787a 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 1e07dfad685..30b7ebc8d45 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 ac9b8ee52d4..07400c0c8a8 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 88949f7884c..befe2e11a04 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 6e6c7934be3..4d1cd7aeccd 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 f843a0bcf10..3baf448e300 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 f23514c4e64..47644b5b615 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 1b51d3187a9..296b091cf16 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 f1ba54f4fc3..a4e3fca0589 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 70dd8115a4d..ab34b96acc3 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 5831893bf7a..02c41a626fa 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 b45c9fd1b33..b77b3092392 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 c6a5f0ccc10..dbf4ec3f6d5 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 8c041daa3a1..302174b8e47 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 f887f1efd3f..eeeeff9a09e 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 7acf01c181e..e9b4115fcad 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 78dc59a1751..c7bc80921f1 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 3bc5da4a57c..8a8ae55a740 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 ad3bdd6f1ac..59407343cc7 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 a2e6e7205d7..cd10b18150b 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 8d88e58ed5c..93c43b676e5 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 18d6bb8f84f..683c47d48a5 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 00000000000..d22e83289ad --- /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 7ff525162a7..9a2241b8eb1 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 00000000000..5ae1d07d4a1 --- /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 3a42b7d6fc9..b9529578fc3 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 238cf4275b9..a8c1fca9726 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 359ead60b71..44ef2f55a8e 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 af5d435519d..e47be9a56cc 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 88f02a07356..8806c7e002a 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 00000000000..3dd9c0b7027 --- /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 4182c347ef8..7d606e3364a 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 8db618c5a72..21cd696d4d0 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 099fe9f5c1b..04e69c104a7 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 aaf432dd767..e74c54aa757 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 00000000000..3dd9c0b7027 --- /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 90cba967df3..7ffbddf5306 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 00000000000..3dd9c0b7027 --- /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 2d543735668..30f21df3925 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 89ed545b446..f960f5346f4 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 00000000000..ba94b51a0a7 --- /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 068f119aa29..20ea7c70bc3 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 9e66d32330c..e81d0f289f0 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 32ff5d13271..6ea13c3806f 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 00000000000..3dd9c0b7027 --- /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 c28fc2db217..c181fef786e 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 b7305b17827..64d8878e144 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 231ba090ae3..2f85049cfb3 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 945ba1ad14a..acbdae6d7ae 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 07d8d725541..9c2050293f1 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 5770105471d..c38507ba38b 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 19782350dcc..5b83e7b5962 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 da7c09e4ede..38b286e9a46 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 b947d46e4b1..c64f3cc7e87 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 d1af1dbeaeb..d0a7ad5ed51 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 5bf321e82c9..80682aaa8f1 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 e633004ae05..acce53fd38b 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 b89f0935705..09ff4c3e271 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 b661c19f3f7..463ab953b09 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 c9069310b6a..3a697cc6eca 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 e657e523b9b..9df8833670c 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 190cc1b78fe..5482bfb3303 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 91c983eef89..91b3ea2bbb1 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 60b5b92a131..ab51ce1ba9a 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 892e310c504..3d3c1514cf7 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 68a664ab97f..c49ea57db8c 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 2ae76efc696..e85b90750a5 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 ac504321ea5..8c88267e9be 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 431d06675e3..2dd5c8e5b4f 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 dbca1417061..21739465209 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 53e9dce6c65..11c99697acf 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 4c6cdbaed66..42aa6f1a3f0 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 417e98092cf..543ea2e5ad9 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 7a4144ba3af..f1f900ac316 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 fb660c7d35b..857300a2afe 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 b0361756e22..8e6662bb9c3 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 00000000000..101b1a4f9b1 --- /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 7c26089527f..40eb47eccf9 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 23190aa6bc7..e593a1333fe 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 3049015a04f..5eff30b1020 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 0c69d209be5..ec20ee615d7 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 8435fdd1c87..53675cf4de4 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 599aff8290e..dede954b2c6 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 4938ef10b81..e8cf904b835 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 4bf07ca9b17..3daa9fa56c0 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 e064d6c5685..a9ff391258e 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 ab8d4effcf9..5327c6f841f 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 52afb4bd207..74028b2219c 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 a60168268dd..ed19bc17400 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 fd9b61eda0f..b524e0d9ee4 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 a6fbd5d1d62..666b3bcc19f 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 fbb20176cca..75c7c5f0198 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 7e985d3bc51..a2ab99f2ac3 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 85818200333..2398d2c55fe 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 42db37552ef..537d3cfe41f 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 ac11cae8589..52498c9d411 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 ea69f25506f..5c474b831ed 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 da92bf6c392..419b4ebbf00 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 9d528ae00bf..a1ad39a8cdc 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 d4d65b84265..d4b218726ce 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 f183f1845a3..383911b9e74 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 141400c0142..268ebd34703 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 f17de2bdd9e..c62a9e3d2ae 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 8742fa51749..4fcd0f4e868 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 a8f8d2fa9d7..85db535aea9 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 ff6e6fc198a..8a61a119186 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 29057836c64..caabf31193f 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 257b7536fb1..0ffa9970bf0 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 f56f870b484..09263d72a51 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 324a81fd3a3..6ad38411423 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 43193581f83..6e3c41f530e 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 dc31373069a..285239d64b8 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 9ae659f8243..3bd19c36fcd 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 68e1d8f6c35..90fc058e115 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 e2081f32b0c..b3379dd7ca5 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 d19b464ba01..fb2ce638f01 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 c4ce94d6e10..6c59df7b000 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 a2ffe723dad..2562f4769b9 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 80ab402dae9..7807abac062 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 ddcddc2347f..a48af879b46 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 162d07cc489..58d4a5d05a2 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 84c0e9522ef..0ad1e9ee74f 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 6d7763dae89..d5146790f5e 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 6f7f2f0423e..da9728e1772 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 21e07b5081f..1dade903399 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 7760dddf2b3..44cd1550500 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 4ebb9638746..25f3a22c52e 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 bbe5b7596d0..440537c7260 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 83ff8a71f71..3b3b4da8cfd 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 3edf8d4ac99..471c274c500 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 147c816a1f2..7a363a178af 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 8e18b6e2581..a446b826d5f 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 501d3e654a6..f3f914aa92e 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 2fec42fc348..17837d4b5ed 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 d5b8064dc56..0d1424751ec 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 5f140c7586b..0cd4d6ec986 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 59a2f28eb5a..c5bf363d32c 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 ce73f3eae78..cf603337b32 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 0786d0edaca..cbf8331c3d3 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 74668398eac..13a8cefa774 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 96cfb8ae505..9b16c299f0a 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 9e596f750cb..15fc3929b5f 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 347e25ff073..3e8fc5a0006 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 a89d67c4598..c5dda1bf3d4 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 b1cfc3c79d0..5ccf0b1ec67 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 5299cce583d..4a336eaae9d 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 bac8e9cfd92..692f203d65d 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 97a280a246c..d33a37086df 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 12bbbb6afd2..6fa4a302f7d 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 876b64464b6..1f7e7108306 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 1990430a21c..d54924e60bb 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 4851847180d..16d4ebf2a33 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 64c7826e8b8..2441238f200 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 c3dafa29054..e5e88fe54de 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 da1610a571b..c46905a1117 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 1076af4c366..4f18f7e8bcf 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 a8a601fc781..8cb4fb2412d 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 3ce5a4e7e31..2da988f78ba 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 f3c40385c87..b9d723c7e1d 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 bdfda1997d5..3ec7d7ee04d 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 e9d4cb4d07e..a76a778d0a1 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 dc69392eafa..8a576b78bee 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 71d6aedc074..e9cbfdf3705 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 72dbaedcbdf..f4319b8d464 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 268e2f7241e..6703f5cb556 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 cfea51f4478..398aa10a06e 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 45214b3b81b..05605f474a7 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 406ac3a9d42..d54457317b1 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 1fe2bcfcc57..c919b734756 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 101eee0aa01..b1bbdb9e3b7 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 c40f5906268..0ff8dc36fde 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 e7415d6d182..d9a4ab60987 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 fe210c85344..ec4899147e1 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 2a71499242f..dc8d1302e22 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 f8de7c99701..106110a89a4 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 d3e07de433b..694aa057ed4 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 7d03ae066d5..7055d893855 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 fc15f61ad5d..cf0427b4bfd 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 e5d4def1aa6..f9b8afabda9 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 ebbe12d78d8..0d478871808 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 6db3d4cc4d8..e6990e0bbf2 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 016f9dac253..5ab1cf3d434 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 24f6fc52f89..ebc6da89edf 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 9a14a4f64bd..206e2f5a113 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 7c5f21e45cb..732263e4a43 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 64143063150..c64af55865d 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 cdff53e4a17..2fbe1d183fc 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 be0bd503f01..c899786f30f 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 9a06c3bd694..edeb3d3c4c7 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 5a97be689b4..4ceb09d215d 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 a42acf6d7b6..c82b01c7ad3 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 0dcf78adb99..b7c5e59b229 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 e516d6adbb2..1024c178f5c 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 cfec38d7839..e011fcacce9 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 f6bd0dee563..e662281a751 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 88b72b52590..9acef9d9054 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); } /* -- GitLab From a7441a39a3c62addd6ce10497c101057f4d69184 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH 0664/1619] [PATCH] x86-64: Update defconfig Signed-off-by: Andi Kleen --- arch/x86_64/defconfig | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index 4844b543bed..47bfba6e9dc 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-git7 -# Wed Sep 27 21:53:10 2006 +# Linux kernel version: 2.6.19-rc1 +# Thu Oct 5 13:04:43 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -19,6 +19,7 @@ CONFIG_EARLY_PRINTK=y CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_IOMAP=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_DMI=y CONFIG_AUDIT_ARCH=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -37,9 +38,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -47,9 +50,10 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y -CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -82,6 +86,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y CONFIG_LBD=y # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set @@ -252,9 +257,11 @@ CONFIG_PCI=y CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y CONFIG_PCI_MSI=y # CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set +# CONFIG_HT_IRQ is not set # # PCCARD (PCMCIA/CardBus) support @@ -309,6 +316,7 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_TUNNEL is not set # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -325,6 +333,7 @@ CONFIG_IPV6=y # CONFIG_INET6_TUNNEL is not set # CONFIG_INET6_XFRM_MODE_TRANSPORT is not set # CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_IPV6_SUBTREES is not set @@ -473,6 +482,7 @@ CONFIG_BLK_DEV_ATIIXP=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_IT821X is not set @@ -564,6 +574,7 @@ CONFIG_MEGARAID_SAS=y # CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -605,7 +616,6 @@ CONFIG_SATA_INTEL_COMBINED=y # CONFIG_PATA_HPT3X3 is not set # CONFIG_PATA_IT821X is not set # CONFIG_PATA_JMICRON is not set -# CONFIG_PATA_LEGACY is not set # CONFIG_PATA_TRIFLEX is not set # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set @@ -614,7 +624,6 @@ CONFIG_SATA_INTEL_COMBINED=y # CONFIG_PATA_OPTI is not set # CONFIG_PATA_OPTIDMA is not set # CONFIG_PATA_PDC_OLD is not set -# CONFIG_PATA_QDI is not set # CONFIG_PATA_RADISYS is not set # CONFIG_PATA_RZ1000 is not set # CONFIG_PATA_SC1200 is not set @@ -631,6 +640,7 @@ CONFIG_SATA_INTEL_COMBINED=y CONFIG_MD=y # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set # CONFIG_DM_CRYPT is not set # CONFIG_DM_SNAPSHOT is not set # CONFIG_DM_MIRROR is not set @@ -819,6 +829,7 @@ CONFIG_NET_POLL_CONTROLLER=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -841,6 +852,7 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set @@ -1008,6 +1020,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_K8TEMP is not set # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set @@ -1034,6 +1047,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_SMSC47M192 is not set CONFIG_SENSORS_SMSC47B397=m # CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set # CONFIG_SENSORS_VT8231 is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83791D is not set @@ -1048,12 +1062,12 @@ CONFIG_SENSORS_SMSC47B397=m # Misc devices # # CONFIG_IBM_ASM is not set +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -1159,6 +1173,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_LIBUSUAL is not set # @@ -1181,6 +1196,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set # # USB Imaging devices @@ -1212,6 +1228,7 @@ CONFIG_USB_MON=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set @@ -1219,9 +1236,9 @@ CONFIG_USB_MON=y # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGETKIT is not set -# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set @@ -1313,6 +1330,7 @@ CONFIG_REISERFS_FS_POSIX_ACL=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -1347,8 +1365,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y @@ -1398,6 +1418,7 @@ CONFIG_SUNRPC=y # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # CONFIG_9P_FS is not set +CONFIG_GENERIC_ACL=y # # Partition Types @@ -1449,6 +1470,10 @@ CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=y +# +# Distributed Lock Manager +# + # # Instrumentation Support # @@ -1482,11 +1507,13 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FRAME_POINTER is not set CONFIG_UNWIND_INFO=y CONFIG_STACK_UNWIND=y # CONFIG_FORCED_INLINING is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set # CONFIG_DEBUG_RODATA is not set # CONFIG_IOMMU_DEBUG is not set CONFIG_DEBUG_STACKOVERFLOW=y -- GitLab From 814eadcefe79a2977a11ba135c4763a402112746 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH 0665/1619] [PATCH] i386: Update defconfig Signed-off-by: Andi Kleen --- arch/i386/defconfig | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/arch/i386/defconfig b/arch/i386/defconfig index ee2d79bd8af..60c0c02574f 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-git7 -# Wed Sep 27 21:53:10 2006 +# Linux kernel version: 2.6.19-rc1 +# Thu Oct 5 13:04:53 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -31,9 +31,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -41,9 +43,10 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y -CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -76,6 +79,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y CONFIG_LBD=y # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set @@ -163,6 +167,7 @@ CONFIG_VM86=y # CONFIG_I8K is not set # CONFIG_X86_REBOOTFIXUPS is not set CONFIG_MICROCODE=y +CONFIG_MICROCODE_OLD_INTERFACE=y CONFIG_X86_MSR=y CONFIG_X86_CPUID=y @@ -177,6 +182,7 @@ CONFIG_HIGHMEM4G=y # CONFIG_HIGHMEM64G is not set CONFIG_PAGE_OFFSET=0xC0000000 CONFIG_HIGHMEM=y +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -295,6 +301,7 @@ CONFIG_PCI_MMCONFIG=y CONFIG_PCI_MSI=y # CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set +# CONFIG_HT_IRQ is not set CONFIG_ISA_DMA_API=y # CONFIG_ISA is not set # CONFIG_MCA is not set @@ -354,6 +361,7 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -370,6 +378,7 @@ CONFIG_IPV6=y # CONFIG_INET6_TUNNEL is not set CONFIG_INET6_XFRM_MODE_TRANSPORT=y CONFIG_INET6_XFRM_MODE_TUNNEL=y +# CONFIG_INET6_XFRM_MODE_BEET is not set # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_IPV6_SUBTREES is not set @@ -519,6 +528,7 @@ CONFIG_BLK_DEV_AMD74XX=y # CONFIG_BLK_DEV_CS5535 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_IT821X is not set @@ -615,6 +625,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -658,7 +669,6 @@ CONFIG_SATA_INTEL_COMBINED=y # CONFIG_PATA_HPT3X3 is not set # CONFIG_PATA_IT821X is not set # CONFIG_PATA_JMICRON is not set -# CONFIG_PATA_LEGACY is not set # CONFIG_PATA_TRIFLEX is not set # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set @@ -667,7 +677,6 @@ CONFIG_SATA_INTEL_COMBINED=y # CONFIG_PATA_OPTI is not set # CONFIG_PATA_OPTIDMA is not set # CONFIG_PATA_PDC_OLD is not set -# CONFIG_PATA_QDI is not set # CONFIG_PATA_RADISYS is not set # CONFIG_PATA_RZ1000 is not set # CONFIG_PATA_SC1200 is not set @@ -684,6 +693,7 @@ CONFIG_SATA_INTEL_COMBINED=y CONFIG_MD=y # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set # CONFIG_DM_CRYPT is not set # CONFIG_DM_SNAPSHOT is not set # CONFIG_DM_MIRROR is not set @@ -874,6 +884,7 @@ CONFIG_NET_POLL_CONTROLLER=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -896,6 +907,7 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set @@ -1023,12 +1035,12 @@ CONFIG_HANGCHECK_TIMER=y # Misc devices # # CONFIG_IBM_ASM is not set +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -1134,6 +1146,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_LIBUSUAL is not set # @@ -1156,6 +1169,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set # # USB Imaging devices @@ -1187,6 +1201,7 @@ CONFIG_USB_MON=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set @@ -1194,9 +1209,9 @@ CONFIG_USB_MON=y # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGETKIT is not set -# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set @@ -1281,6 +1296,7 @@ CONFIG_REISERFS_FS_POSIX_ACL=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -1315,8 +1331,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y @@ -1366,6 +1384,7 @@ CONFIG_SUNRPC=y # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # CONFIG_9P_FS is not set +CONFIG_GENERIC_ACL=y # # Partition Types @@ -1417,6 +1436,10 @@ CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=y +# +# Distributed Lock Manager +# + # # Instrumentation Support # @@ -1452,11 +1475,13 @@ CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FRAME_POINTER is not set CONFIG_UNWIND_INFO=y CONFIG_STACK_UNWIND=y # CONFIG_FORCED_INLINING is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set CONFIG_EARLY_PRINTK=y CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_STACK_USAGE is not set -- GitLab From dedc9937e876cb5430bca6a1dccfcc2ff22f8b7c Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH 0666/1619] [PATCH] x86-64: Calgary IOMMU: deobfuscate calgary_init calgary_init's for loop does not correspond to the actual device being checked, which makes its upperbound check for array overflow useless. Changing this to a do-while loop is the correct way of doing this. There should be no possibility of spinning forever in this loop, as pci_get_device states that it will go through all iterations, then return NULL (thus breaking the loop). Signed-off-by: Jon Mason Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index f760045d6d3..1100031528d 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -816,6 +816,8 @@ static int __init calgary_init_one(struct pci_dev *dev) void __iomem *bbar; int ret; + BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM); + address = locate_register_space(dev); /* map entire 1MB of Calgary config space */ bbar = ioremap_nocache(address, 1024 * 1024); @@ -842,10 +844,10 @@ done: static int __init calgary_init(void) { - int i, ret = -ENODEV; + int ret = -ENODEV; struct pci_dev *dev = NULL; - for (i = 0; i < MAX_PHB_BUS_NUM; i++) { + do { dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CALGARY, dev); @@ -861,12 +863,12 @@ static int __init calgary_init(void) ret = calgary_init_one(dev); if (ret) goto error; - } + } while (1); return ret; error: - for (i--; i >= 0; i--) { + do { dev = pci_find_device_reverse(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CALGARY, dev); @@ -882,7 +884,7 @@ error: calgary_disable_translation(dev); calgary_free_bus(dev); pci_dev_put(dev); /* Undo calgary_init_one()'s pci_dev_get() */ - } + } while (1); return ret; } -- GitLab From 76fd231717453e06347ad17b3fc1707c6918d172 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH 0667/1619] [PATCH] x86-64: Calgary IOMMU: Fix off by one when calculating register space location The purpose of the code being modified is to determine the location of the calgary chip address space. This is done by a magical formula of FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase) to find the offset where BIOS puts it. In this formula, OneBasedChassisNumber corresponds to the NUMA node, and rionodeid is always 2 or 3 depending on which chip in the system it is. The problem was that we had an off by one error that caused us to account some busses to the wrong chip and thus give them the wrong address space. Fixes RH bugzilla #203971. Signed-off-by: Jon Mason Signed-off-bu: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index 1100031528d..3c0c7fde09d 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -790,7 +790,16 @@ static inline unsigned int __init locate_register_space(struct pci_dev *dev) int rionodeid; u32 address; - rionodeid = (dev->bus->number % 15 > 4) ? 3 : 2; + /* + * Each Calgary has four busses. The first four busses (first Calgary) + * have RIO node ID 2, then the next four (second Calgary) have RIO + * node ID 3, the next four (third Calgary) have node ID 2 again, etc. + * We use a gross hack - relying on the dev->bus->number ordering, + * modulo 14 - to decide which Calgary a given bus is on. Busses 0, 1, + * 2 and 4 are on the first Calgary (id 2), 6, 8, a and c are on the + * second (id 3), and then it repeats modulo 14. + */ + rionodeid = (dev->bus->number % 14 > 4) ? 3 : 2; /* * register space address calculation as follows: * FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase) @@ -798,7 +807,7 @@ static inline unsigned int __init locate_register_space(struct pci_dev *dev) * RioNodeId is 2 for first Calgary, 3 for second Calgary */ address = START_ADDRESS - - (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 15)) + + (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 14)) + (0x100000) * (rionodeid - CHASSIS_BASE); return address; } -- GitLab From d8d2bedf6002bf40b07fc5989dd9dbe56609fe3e Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH 0668/1619] [PATCH] x86-64: Calgary IOMMU: Update Jon's contact info Also add copyright for work done after leaving IBM. Signed-off-by: Jon Mason Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- MAINTAINERS | 2 +- arch/x86_64/kernel/pci-calgary.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 17becb9b1a9..84a018ee455 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -641,7 +641,7 @@ CALGARY x86-64 IOMMU P: Muli Ben-Yehuda M: muli@il.ibm.com P: Jon D. Mason -M: jdmason@us.ibm.com +M: jdmason@kudzu.us L: linux-kernel@vger.kernel.org L: discuss@x86-64.org S: Maintained diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index 3c0c7fde09d..c4692b67878 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -2,8 +2,9 @@ * Derived from arch/powerpc/kernel/iommu.c * * Copyright (C) IBM Corporation, 2006 + * Copyright (C) 2006 Jon Mason * - * Author: Jon Mason + * Author: Jon Mason * Author: Muli Ben-Yehuda * This program is free software; you can redistribute it and/or modify -- GitLab From 70d666d6ae9724c0a08434c20f8830c90a635bd3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH 0669/1619] [PATCH] x86-64: Calgary IOMMU: print PCI bus numbers in hex Make the references to the bus number in hex instead of decimal, as that is the way that lspci prints out the bus numbers. Signed-off-by: Jon Mason Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index c4692b67878..b3296cc2f2f 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -715,7 +715,7 @@ static void calgary_watchdog(unsigned long data) /* If no error, the agent ID in the CSR is not valid */ if (val32 & CSR_AGENT_MASK) { - printk(KERN_EMERG "calgary_watchdog: DMA error on bus %d, " + printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, " "CSR = %#x\n", dev->bus->number, val32); writel(0, target); @@ -749,7 +749,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev) val32 = be32_to_cpu(readl(target)); val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE; - printk(KERN_INFO "Calgary: enabling translation on PHB %d\n", busnum); + printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum); printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this " "bus.\n"); @@ -779,7 +779,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev) val32 = be32_to_cpu(readl(target)); val32 &= ~(PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE); - printk(KERN_INFO "Calgary: disabling translation on PHB %d!\n", busnum); + printk(KERN_INFO "Calgary: disabling translation on PHB %#x!\n", busnum); writel(cpu_to_be32(val32), target); readl(target); /* flush */ @@ -1064,7 +1064,7 @@ static int __init calgary_parse_options(char *p) if (bridge < MAX_PHB_BUS_NUM) { printk(KERN_INFO "Calgary: disabling " - "translation for PHB 0x%x\n", bridge); + "translation for PHB %#x\n", bridge); bus_info[bridge].translation_disabled = 1; } } -- GitLab From f015c6c4d733f68cbc1c5d231bb158abaa5c9606 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 5 Oct 2006 18:47:22 +0200 Subject: [PATCH 0670/1619] [PATCH] i386: Fix PCI BIOS config space access Got broken by a earlier change. Also add a printk when no pci config method could be found. Cc: gregkh@suse.de Signed-off-by: Andi Kleen --- arch/i386/pci/direct.c | 2 ++ arch/i386/pci/init.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 5acf0b4743c..431c9a51b15 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -256,6 +256,8 @@ static int __init pci_check_type2(void) void __init pci_direct_init(int type) { + if (type == 0) + return; printk(KERN_INFO "PCI: Using configuration type %d\n", type); if (type == 1) raw_pci_ops = &pci_direct_conf1; diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c index d028e1b05c3..b21b6da8ab1 100644 --- a/arch/i386/pci/init.c +++ b/arch/i386/pci/init.c @@ -28,6 +28,10 @@ static __init int pci_access_init(void) #ifdef CONFIG_PCI_DIRECT pci_direct_init(type); #endif + if (!raw_pci_ops) + printk(KERN_ERR + "PCI: Fatal: No config space access function found\n"); + return 0; } arch_initcall(pci_access_init); -- GitLab From 51ec28e1b2cb267a09a0b8eac1ccf8d61b7268bf Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 5 Oct 2006 18:47:22 +0200 Subject: [PATCH 0671/1619] [PATCH] x86: Terminate the kernel stacks for the unwinder Always make sure RIP/EIP is 0 in the registers stored on the top of the stack of a kernel thread. This makes sure the unwinder code won't try a fallback but knows the stack has ended. AK: this patch is a bit mysterious. in theory they should be terminated anyways, but it seems to fix at least one crash. Anyways double termination probably doesn't hurt. Signed-off-by: Andi Kleen --- arch/i386/kernel/process.c | 6 +++++- arch/x86_64/kernel/entry.S | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index dad02a960e0..b0a07801d9d 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -328,6 +328,7 @@ extern void kernel_thread_helper(void); int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct pt_regs regs; + int err; memset(®s, 0, sizeof(regs)); @@ -342,7 +343,10 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + err = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + if (err == 0) /* terminate kernel stack */ + task_pt_regs(current)->eip = 0; + return err; } EXPORT_SYMBOL(kernel_thread); diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index b8285cf1a9c..ab9b2c4726f 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -978,6 +978,11 @@ ENTRY(kernel_thread) call do_fork movq %rax,RAX(%rsp) xorl %edi,%edi + test %rax,%rax + jnz 1f + /* terminate stack in child */ + movq %rdi,RIP(%rsp) +1: /* * It isn't worth to check for reschedule here, -- GitLab From 0a5ace2ab08d45cd78d7ef0067cdcd5c812ac54f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 5 Oct 2006 18:47:22 +0200 Subject: [PATCH 0672/1619] [PATCH] x86-64: Fix FPU corruption This reverts an earlier patch that was found to cause FPU state corruption. I think the corruption happens because unlazy_fpu() can cause FPU exceptions and when it happens after the current switch some processing would affect the state in the wrong process. Thanks to Douglas Crosher and Tom Hughes for testing. Cc: jbeulich@novell.com Signed-off-by: Andi Kleen --- arch/x86_64/kernel/process.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index de10cb8a2c9..5e95b257ee2 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -615,6 +615,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) prev->gsindex = gsindex; } + /* Must be after DS reload */ + unlazy_fpu(prev_p); + /* * Switch the PDA and FPU contexts. */ @@ -622,10 +625,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) write_pda(oldrsp, next->userrsp); write_pda(pcurrent, next_p); - /* This must be here to ensure both math_state_restore() and - kernel_fpu_begin() work consistently. - And the AMD workaround requires it to be after DS reload. */ - unlazy_fpu(prev_p); write_pda(kernelstack, (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); #ifdef CONFIG_CC_STACKPROTECTOR -- GitLab From 7d0b0e8ddbdda58a852ccff010c0339a38552cc7 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 5 Oct 2006 18:47:22 +0200 Subject: [PATCH 0673/1619] [PATCH] x86-64: Annotate interrupt frame backlink in interrupt handlers Add correct CFI annotation to the backlink on top of the interrupt stack. Signed-off-by: Andi Kleen --- arch/x86_64/kernel/entry.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index ab9b2c4726f..38a7b2d528e 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -535,6 +535,8 @@ END(stub_rt_sigreturn) 1: incl %gs:pda_irqcount cmoveq %gs:pda_irqstackptr,%rsp push %rbp # backlink for old unwinder + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rbp,0 /* * We entered an interrupt context - irqs are off: */ @@ -1174,6 +1176,7 @@ ENTRY(call_softirq) incl %gs:pda_irqcount cmove %gs:pda_irqstackptr,%rsp push %rbp # backlink for old unwinder + CFI_ADJUST_CFA_OFFSET 8 call __do_softirq leaveq CFI_DEF_CFA_REGISTER rsp -- GitLab From 88271e9e43e65537c6390af3718a60c45c787e8f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 5 Oct 2006 18:47:22 +0200 Subject: [PATCH 0674/1619] [PATCH] i386: fix rwsem build bug on CONFIG_M386=y CONFIG_M386 turns on spinlock-based generic rwsems - which surprises the semaphore.S rwsem stubs. Tested both with and without CONFIG_M386. Reported-by: Klaus Knopper Triaged-by: Adrian Bunk Signed-off-by: Ingo Molnar Signed-off-by: Andi Kleen --- arch/i386/lib/semaphore.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S index ef6ad9e1a60..c01eb39c0b4 100644 --- a/arch/i386/lib/semaphore.S +++ b/arch/i386/lib/semaphore.S @@ -152,6 +152,8 @@ ENTRY(__read_lock_failed) #endif +#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM + /* Fix up special calling conventions */ ENTRY(call_rwsem_down_read_failed) CFI_STARTPROC @@ -214,3 +216,4 @@ ENTRY(call_rwsem_downgrade_wake) CFI_ENDPROC END(call_rwsem_downgrade_wake) +#endif -- GitLab From d7a297baa6edea94167163bed808c6a8933bd5aa Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Thu, 5 Oct 2006 20:49:18 +0000 Subject: [PATCH 0675/1619] [PATCH] fix qla{2,4} build error commit 0181944fe647cae18d545ac1167df3d15d393701 adds a 'extended_error_logging' global variable to qla2xxx which is defined by qla4xxx too. Trying to build both drivers results in the following error: LD drivers/scsi/built-in.o drivers/scsi/qla4xxx/built-in.o: In function `qla4xxx_slave_configure': drivers/scsi/qla4xxx/ql4_os.c:1433: multiple definition of `extended_error_logging' drivers/scsi/qla2xxx/built-in.o:drivers/scsi/qla2xxx/qla_os.c:2166: first defined here make[2]: *** [drivers/scsi/built-in.o] Error 1 make[1]: *** [drivers/scsi] Error 2 make: *** [drivers] Error 2 The following patch simply adds a qla2_ (qla4_ respectively) prefix to the variable name. Signed-off-by: Frederik Deweerdt Signed-off-by: Linus Torvalds --- drivers/scsi/qla2xxx/qla_dbg.h | 14 +++++++------- drivers/scsi/qla2xxx/qla_gbl.h | 2 +- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 8 ++++---- drivers/scsi/qla4xxx/ql4_dbg.h | 4 ++-- drivers/scsi/qla4xxx/ql4_glbl.h | 2 +- drivers/scsi/qla4xxx/ql4_mbx.c | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 8 ++++---- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 533425338e0..90dad7e8898 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -38,7 +38,7 @@ * Macros use for debugging the driver. */ -#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG(x) do { if (qla2_extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_1) #define DEBUG1(x) do {x;} while (0) @@ -46,12 +46,12 @@ #define DEBUG1(x) do {} while (0) #endif -#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0) -#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0) -#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0) -#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0) -#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0) -#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2_3(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2_3_11(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2_9_10(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2_11(x) do { if (qla2_extended_error_logging) { x; } } while (0) +#define DEBUG2_13(x) do { if (qla2_extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index bef7011378c..990b897560c 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -60,7 +60,7 @@ extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; extern int ql2xallocfwdump; -extern int extended_error_logging; +extern int qla2_extended_error_logging; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d5d26273c04..833b93085fd 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1644,7 +1644,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) * Set host adapter parameters. */ if (nv->host_p[0] & BIT_7) - extended_error_logging = 1; + qla2_extended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3ba8c239f17..3f20d765563 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -61,9 +61,9 @@ MODULE_PARM_DESC(ql2xallocfwdump, "during HBA initialization. Memory allocation requirements " "vary by ISP type. Default is 1 - allocate memory."); -int extended_error_logging; -module_param(extended_error_logging, int, S_IRUGO|S_IRUSR); -MODULE_PARM_DESC(extended_error_logging, +int qla2_extended_error_logging; +module_param(qla2_extended_error_logging, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(qla2_extended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging. 1 - log errors."); @@ -2697,7 +2697,7 @@ qla2x00_module_init(void) /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); - if (extended_error_logging) + if (qla2_extended_error_logging) strcat(qla2x00_version_str, "-debug"); qla2xxx_transport_template = diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h index 56ddc227f84..3e99dcfd5a9 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.h +++ b/drivers/scsi/qla4xxx/ql4_dbg.h @@ -22,14 +22,14 @@ #endif #if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {if(extended_error_logging == 2) x;} while (0); +#define DEBUG2(x) do {if(qla4_extended_error_logging == 2) x;} while (0); #define DEBUG2_3(x) do {x;} while (0); #else /* */ #define DEBUG2(x) do {} while (0); #endif /* */ #if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {if(extended_error_logging == 3) x;} while (0); +#define DEBUG3(x) do {if(qla4_extended_error_logging == 3) x;} while (0); #else /* */ #define DEBUG3(x) do {} while (0); #if !defined(QL_DEBUG_LEVEL_2) diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 418fb7a13a6..77a997a82cb 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -72,7 +72,7 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, uint32_t fw_ddb_index, uint32_t state); -extern int extended_error_logging; +extern int qla4_extended_error_logging; extern int ql4xdiscoverywait; extern int ql4xdontresethba; #endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index ed977f70b2d..ef82399c085 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -701,7 +701,7 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", ha->host_no, num_valid_entries)); - if (extended_error_logging == 3) { + if (qla4_extended_error_logging == 3) { if (oldest_entry == 0) { /* Circular Buffer has not wrapped around */ for (i=0; i < num_valid_entries; i++) { diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 5036ebf013a..178fcddcfd8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -34,9 +34,9 @@ MODULE_PARM_DESC(ql4xdontresethba, " default it will reset hba :0" " set to 1 to avoid resetting HBA"); -int extended_error_logging = 0; /* 0 = off, 1 = log errors */ -module_param(extended_error_logging, int, S_IRUGO | S_IRUSR); -MODULE_PARM_DESC(extended_error_logging, +int qla4_extended_error_logging = 0; /* 0 = off, 1 = log errors */ +module_param(qla4_extended_error_logging, int, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(qla4_extended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging, 1 - debug logging"); @@ -1714,7 +1714,7 @@ static int __init qla4xxx_module_init(void) /* Derive version string. */ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); - if (extended_error_logging) + if (qla4_extended_error_logging) strcat(qla4xxx_version_str, "-debug"); qla4xxx_scsi_transport = -- GitLab From 4b0ff1a94cba36a35734c84f377e49cacc77f293 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 5 Oct 2006 19:07:26 +0200 Subject: [PATCH 0676/1619] [PATCH] x86-64: Fix compilation without CONFIG_KALLSYMS Include linux/kallsyms.h unconditionally for print_symbol(). Signed-off-by: Randy Dunlap Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 01f2a8d254c..7819022a8db 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -115,7 +116,6 @@ static int call_trace = 1; #endif #ifdef CONFIG_KALLSYMS -# include void printk_address(unsigned long address) { unsigned long offset = 0, symsize; -- GitLab From c1a26e7d40fb814716950122353a1a556844286b Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Thu, 5 Oct 2006 21:17:50 +0200 Subject: [PATCH 0677/1619] [PATCH] UDF: Fix mounting read-write The UDF filesystem can't be mounted in read-write mode any more, because of forgotten braces. Signed-off-by: Peter Osterlund [ Duh! ] Signed-off-by: Linus Torvalds --- fs/udf/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 1d3b5d2070e..1aea6a4f9a4 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1621,9 +1621,10 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) goto error_out; } - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_READ_ONLY) + if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_READ_ONLY) { printk("UDF-fs: Partition marked readonly; forcing readonly mount\n"); sb->s_flags |= MS_RDONLY; + } if ( udf_find_fileset(sb, &fileset, &rootdir) ) { -- GitLab From 49f19ce401edfff937c448dd74c22497da361889 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 5 Oct 2006 20:31:10 -0500 Subject: [PATCH 0678/1619] [PATCH] powerpc: irq change build breaks Fix up some of the buildbreaks from the irq handler changes. Signed-off-by: Olof Johansson Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 2 +- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 2 +- arch/powerpc/platforms/cell/interrupt.c | 2 +- arch/powerpc/platforms/chrp/setup.c | 2 +- arch/powerpc/platforms/powermac/pic.c | 2 +- arch/powerpc/sysdev/qe_lib/qe_ic.c | 4 ++-- arch/powerpc/sysdev/tsi108_pci.c | 2 +- drivers/macintosh/via-cuda.c | 2 +- sound/oss/dmasound/dmasound_awacs.c | 4 ++-- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 28070e7ae50..8af7126fc6b 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -72,7 +72,7 @@ static void cpm2_cascade(unsigned int irq, struct irq_desc *desc, int cascade_irq; while ((cascade_irq = cpm2_get_irq(regs)) >= 0) { - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); } desc->chip->eoi(irq); } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 193a5d7921b..b92fc6976a4 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -138,7 +138,7 @@ static void mpc85xx_8259_cascade(unsigned int irq, struct unsigned int cascade_irq = i8259_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/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index b637e8157f7..8218703babd 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -58,7 +58,7 @@ static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc, { unsigned int cascade_irq = i8259_irq(regs); if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); desc->chip->eoi(irq); } #endif /* CONFIG_PCI */ diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 434fb934dd2..f8768b096f0 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -121,7 +121,7 @@ static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc, irq_linear_revmap(iic_host, base | cascade); if (cirq != NO_IRQ) - generic_handle_irq(cirq, regs); + generic_handle_irq(cirq); } /* post-ack level interrupts */ ack = bits & ~IIC_ISR_EDGE_MASK; diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 488dbd9b51a..35cd7a5f683 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -340,7 +340,7 @@ static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc, { unsigned int cascade_irq = i8259_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/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index e93a115961a..5da677835c0 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -227,7 +227,7 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) continue; irq += __ilog2(bits); spin_unlock_irqrestore(&pmac_pic_lock, flags); - __do_IRQ(irq, regs); + __do_IRQ(irq); spin_lock_irqsave(&pmac_pic_lock, flags); rc = IRQ_HANDLED; } diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index c229d07d495..0dec010bcbb 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -343,7 +343,7 @@ void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc, chip->mask_ack(irq); if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); chip->unmask(irq); } @@ -359,7 +359,7 @@ void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc, chip->mask_ack(irq); if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); chip->unmask(irq); } diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index c28f69bef8e..14f4a1ab6d1 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -410,6 +410,6 @@ void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc, { unsigned int cascade_irq = get_pci_source(); if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); desc->chip->eoi(irq); } diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 64a07ccfe36..df66291b132 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -437,7 +437,7 @@ cuda_poll(void) * disable_irq(), would that work on m68k ? --BenH */ local_irq_save(flags); - cuda_interrupt(0, NULL, NULL); + cuda_interrupt(0, NULL); local_irq_restore(flags); } diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 3bd19c36fcd..37773b1deea 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -465,7 +465,7 @@ tas_dmasound_init(void) val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0); pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80); /* Trigger it */ - headphone_intr(0,NULL,NULL); + headphone_intr(0, NULL); } } if (!gpio_headphone_irq) { @@ -1499,7 +1499,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); msleep(150); tas_leave_sleep(); /* Stub for now */ - headphone_intr(0,NULL,NULL); + headphone_intr(0, NULL); break; case AWACS_DACA: msleep(10); /* Check this !!! */ -- GitLab From 458821452642fd5dc2377b73cd1323fd4a9653e7 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 4 Oct 2006 13:21:45 +0900 Subject: [PATCH 0679/1619] sh: First step at generic timeofday support. At the moment we wrap GENERIC_TIME around our existing timer API. As boards start providing their own clocksources, they're able to select GENERIC_TIME accordingly and optimize out most of the timer API. Once the current timers have been reworked as proper clocksource drivers, the rest of the place holders for the timer API can go away and we can flip on GENERIC_TIME unconditionally. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 4 ++++ arch/sh/kernel/time.c | 2 ++ include/asm-sh/timer.h | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index f6a0c443616..6a461d4caef 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -45,6 +45,9 @@ config GENERIC_CALIBRATE_DELAY config GENERIC_IOMAP bool +config GENERIC_TIME + def_bool n + config ARCH_MAY_HAVE_PC_FDC bool @@ -357,6 +360,7 @@ config CPU_HAS_SR_RB endmenu menu "Timer support" +depends on !GENERIC_TIME config SH_TMU bool "TMU timer support" diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 450c68f1df0..1fbb83c665d 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -47,6 +47,7 @@ unsigned long long __attribute__ ((weak)) sched_clock(void) return (unsigned long long)jiffies * (1000000000 / HZ); } +#ifndef CONFIG_GENERIC_TIME void do_gettimeofday(struct timeval *tv) { unsigned long seq; @@ -99,6 +100,7 @@ int do_settimeofday(struct timespec *tv) return 0; } EXPORT_SYMBOL(do_settimeofday); +#endif /* !CONFIG_GENERIC_TIME */ /* last time the RTC clock got updated */ static long last_rtc_update; diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h index c7ab28095ba..ebc78db1a9e 100644 --- a/include/asm-sh/timer.h +++ b/include/asm-sh/timer.h @@ -8,7 +8,9 @@ struct sys_timer_ops { int (*init)(void); int (*start)(void); int (*stop)(void); +#ifndef CONFIG_GENERIC_TIME unsigned long (*get_offset)(void); +#endif unsigned long (*get_frequency)(void); }; @@ -24,10 +26,12 @@ struct sys_timer { extern struct sys_timer tmu_timer; extern struct sys_timer *sys_timer; +#ifndef CONFIG_GENERIC_TIME static inline unsigned long get_timer_offset(void) { return sys_timer->ops->get_offset(); } +#endif static inline unsigned long get_timer_frequency(void) { -- GitLab From a700f3594d63a85af196ac64984f7375d903afad Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 4 Oct 2006 13:27:32 +0900 Subject: [PATCH 0680/1619] sh: Kill off timer_ops get_frequency(). We're not using this anywhere these days, kill it off. Signed-off-by: Paul Mundt --- arch/sh/kernel/timers/timer-tmu.c | 58 ++----------------------------- include/asm-sh/timer.h | 6 ---- 2 files changed, 2 insertions(+), 62 deletions(-) diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c index 205816fcf0d..badfedb455a 100644 --- a/arch/sh/kernel/timers/timer-tmu.c +++ b/arch/sh/kernel/timers/timer-tmu.c @@ -111,60 +111,6 @@ static struct irqaction tmu_irq = { .mask = CPU_MASK_NONE, }; -/* - * Hah! We'll see if this works (switching from usecs to nsecs). - */ -static unsigned long tmu_timer_get_frequency(void) -{ - u32 freq; - struct timespec ts1, ts2; - unsigned long diff_nsec; - unsigned long factor; - - /* Setup the timer: We don't want to generate interrupts, just - * have it count down at its natural rate. - */ - ctrl_outb(0, TMU_TSTR); -#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760) - ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); -#endif - ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR); - ctrl_outl(0xffffffff, TMU0_TCOR); - ctrl_outl(0xffffffff, TMU0_TCNT); - - rtc_sh_get_time(&ts2); - - do { - rtc_sh_get_time(&ts1); - } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); - - /* actually start the timer */ - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); - - do { - rtc_sh_get_time(&ts2); - } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); - - freq = 0xffffffff - ctrl_inl(TMU0_TCNT); - if (ts2.tv_nsec < ts1.tv_nsec) { - ts2.tv_nsec += 1000000000; - ts2.tv_sec--; - } - - diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec); - - /* this should work well if the RTC has a precision of n Hz, where - * n is an integer. I don't think we have to worry about the other - * cases. */ - factor = (1000000000 + diff_nsec/2) / diff_nsec; - - if (factor * diff_nsec > 1100000000 || - factor * diff_nsec < 900000000) - panic("weird RTC (diff_nsec %ld)", diff_nsec); - - return freq * factor; -} - static void tmu_clk_init(struct clk *clk) { u8 divisor = TMU0_TCR_INIT & 0x7; @@ -232,12 +178,12 @@ struct sys_timer_ops tmu_timer_ops = { .init = tmu_timer_init, .start = tmu_timer_start, .stop = tmu_timer_stop, - .get_frequency = tmu_timer_get_frequency, +#ifndef CONFIG_GENERIC_TIME .get_offset = tmu_timer_get_offset, +#endif }; struct sys_timer tmu_timer = { .name = "tmu", .ops = &tmu_timer_ops, }; - diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h index ebc78db1a9e..341cb71c2f9 100644 --- a/include/asm-sh/timer.h +++ b/include/asm-sh/timer.h @@ -11,7 +11,6 @@ struct sys_timer_ops { #ifndef CONFIG_GENERIC_TIME unsigned long (*get_offset)(void); #endif - unsigned long (*get_frequency)(void); }; struct sys_timer { @@ -33,11 +32,6 @@ static inline unsigned long get_timer_offset(void) } #endif -static inline unsigned long get_timer_frequency(void) -{ - return sys_timer->ops->get_frequency(); -} - /* arch/sh/kernel/timers/timer.c */ struct sys_timer *get_sys_timer(void); -- GitLab From 35f3c5185b1e28e6591aa649db8bf4fa16f1a7f3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 6 Oct 2006 15:31:16 +0900 Subject: [PATCH 0681/1619] sh: Updates for IRQ handler changes. Trivial fixes for build breakage introduced by IRQ handler changes. Signed-off-by: Paul Mundt --- arch/sh/boards/hp6xx/hp6xx_apm.c | 4 ++-- arch/sh/boards/landisk/landisk_pwb.c | 2 +- arch/sh/boards/mpc1211/setup.c | 5 ++--- arch/sh/boards/snapgear/setup.c | 2 +- arch/sh/cchips/hd6446x/hd64461/setup.c | 2 +- arch/sh/cchips/hd6446x/hd64465/gpio.c | 2 +- arch/sh/cchips/hd6446x/hd64465/setup.c | 2 +- arch/sh/cchips/voyagergx/irq.c | 3 +-- arch/sh/drivers/dma/dma-g2.c | 2 +- arch/sh/drivers/dma/dma-pvr2.c | 2 +- arch/sh/drivers/dma/dma-sh.c | 6 +++--- arch/sh/drivers/pci/pci-st40.c | 2 +- arch/sh/kernel/irq.c | 19 +++++++++++++------ arch/sh/kernel/time.c | 7 ++++--- arch/sh/kernel/timers/timer-tmu.c | 5 ++--- drivers/rtc/rtc-sh.c | 6 +++--- drivers/serial/sh-sci.c | 4 ++-- include/asm-sh/hw_irq.h | 4 ++++ include/asm-sh/irq_regs.h | 1 + include/asm-sh/timer.h | 3 +-- 20 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 include/asm-sh/irq_regs.h diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c index 75f91aaae07..219179114f0 100644 --- a/arch/sh/boards/hp6xx/hp6xx_apm.c +++ b/arch/sh/boards/hp6xx/hp6xx_apm.c @@ -83,7 +83,7 @@ static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length) return p - buf; } -static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev) { if (!apm_suspended) apm_queue_event(APM_USER_SUSPEND); @@ -96,7 +96,7 @@ static int __init hp6x0_apm_init(void) int ret; ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt, - SA_INTERRUPT, MODNAME, 0); + IRQF_DISABLED, MODNAME, 0); if (unlikely(ret < 0)) { printk(KERN_ERR MODNAME ": IRQ %d request failed\n", HP680_BTN_IRQ); diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c index 0b7bee1a9ca..e6252497816 100644 --- a/arch/sh/boards/landisk/landisk_pwb.c +++ b/arch/sh/boards/landisk/landisk_pwb.c @@ -135,7 +135,7 @@ static int swdrv_write(struct file *filp, const char *buff, size_t count, return count; } -static irqreturn_t sw_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sw_interrupt(int irq, void *dev_id) { landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS))); disable_irq(IRQ_BUTTON); diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c index 01c10fa5c05..7c3d1d30415 100644 --- a/arch/sh/boards/mpc1211/setup.c +++ b/arch/sh/boards/mpc1211/setup.c @@ -69,7 +69,6 @@ static void __init pci_write_config(unsigned long busNo, static unsigned char m_irq_mask = 0xfb; static unsigned char s_irq_mask = 0xff; -volatile unsigned long irq_err_count; static void disable_mpc1211_irq(unsigned int irq) { @@ -118,7 +117,7 @@ static void mask_and_ack_mpc1211(unsigned int irq) if(irq < 8) { if(m_irq_mask & (1<channel[i].size - \ g2_dma->status[i].size) & 0x0fffffff) -static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t g2_dma_interrupt(int irq, void *dev_id) { int i; diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c index c1b6bc23c10..838fad566ea 100644 --- a/arch/sh/drivers/dma/dma-pvr2.c +++ b/arch/sh/drivers/dma/dma-pvr2.c @@ -21,7 +21,7 @@ static unsigned int xfer_complete; static int count; -static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id) { if (get_dma_residue(PVR2_CASCADE_CHAN)) { printk(KERN_WARNING "DMA: SH DMAC did not complete transfer " diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index cbbe8bce3d6..d8ece20bb2c 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -60,9 +60,9 @@ static inline unsigned int calc_xmit_shift(struct dma_channel *chan) * Besides that it needs to waken any waiting process, which should handle * setting up the next transfer. */ -static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_tei(int irq, void *dev_id) { - struct dma_channel *chan = (struct dma_channel *)dev_id; + struct dma_channel *chan = dev_id; u32 chcr; chcr = ctrl_inl(CHCR[chan->chan]); @@ -228,7 +228,7 @@ static inline int dmaor_reset(void) } #if defined(CONFIG_CPU_SH4) -static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_err(int irq, void *dummy) { dmaor_reset(); disable_irq(irq); diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c index 4ab5ea6b35f..efecb3d5995 100644 --- a/arch/sh/drivers/pci/pci-st40.c +++ b/arch/sh/drivers/pci/pci-st40.c @@ -161,7 +161,7 @@ static char * pci_commands[16]={ "Memory Write-and-Invalidate" }; -static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t st40_pci_irq(int irq, void *dev_instance) { unsigned pci_int, pci_air, pci_cir, pci_aint; static int count=0; diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index c7ebd6aec95..3b93682bf18 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -17,6 +17,8 @@ #include #include +atomic_t irq_err_count; + /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves, it doesn't deserve @@ -47,8 +49,10 @@ int show_interrupts(struct seq_file *p, void *v) if (!action) goto unlock; seq_printf(p, "%3d: ",i); - seq_printf(p, "%10u ", kstat_irqs(i)); - seq_printf(p, " %14s", irq_desc[i].chip->typename); + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); + seq_printf(p, " %14s", irq_desc[i].chip->name); + seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -56,7 +60,9 @@ int show_interrupts(struct seq_file *p, void *v) seq_putc(p, '\n'); unlock: spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } + } else if (i == NR_IRQS) + seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); + return 0; } #endif @@ -78,6 +84,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs regs) { + struct pt_regs *old_regs = set_irq_regs(®s); int irq = r4; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; @@ -139,7 +146,6 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, __asm__ __volatile__ ( "mov %0, r4 \n" - "mov %1, r5 \n" "mov r15, r9 \n" "jsr @%2 \n" /* swith to the irq stack */ @@ -147,17 +153,18 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, /* restore the stack (ring zero) */ "mov r9, r15 \n" : /* no outputs */ - : "r" (irq), "r" (®s), "r" (__do_IRQ), "r" (isp) + : "r" (irq), "r" (generic_handle_irq), "r" (isp) /* XXX: A somewhat excessive clobber list? -PFM */ : "memory", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "t", "pr" ); } else #endif - __do_IRQ(irq, ®s); + generic_handle_irq(irq); irq_exit(); + set_irq_regs(old_regs); return 1; } diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 1fbb83c665d..57e708d7b52 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -109,13 +109,14 @@ static long last_rtc_update; * handle_timer_tick() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -void handle_timer_tick(struct pt_regs *regs) +void handle_timer_tick(void) { do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif - profile_tick(CPU_PROFILING, regs); + if (current->pid) + profile_tick(CPU_PROFILING); #ifdef CONFIG_HEARTBEAT if (sh_mv.mv_heartbeat != NULL) diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c index badfedb455a..24927015dc3 100644 --- a/arch/sh/kernel/timers/timer-tmu.c +++ b/arch/sh/kernel/timers/timer-tmu.c @@ -80,8 +80,7 @@ static unsigned long tmu_timer_get_offset(void) return count; } -static irqreturn_t tmu_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) { unsigned long timer_status; @@ -98,7 +97,7 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dev_id, * locally disabled. -arca */ write_seqlock(&xtime_lock); - handle_timer_tick(regs); + handle_timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 8b6efcc0505..143302a8e79 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -160,7 +160,7 @@ static int sh_rtc_open(struct device *dev) tmp |= RCR1_CIE; writeb(tmp, rtc->regbase + RCR1); - ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT, + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, "sh-rtc period", dev); if (unlikely(ret)) { dev_err(dev, "request period IRQ failed with %d, IRQ %d\n", @@ -168,7 +168,7 @@ static int sh_rtc_open(struct device *dev) return ret; } - ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT, + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, "sh-rtc carry", dev); if (unlikely(ret)) { dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", @@ -177,7 +177,7 @@ static int sh_rtc_open(struct device *dev) goto err_bad_carry; } - ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT, + ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, IRQF_DISABLED, "sh-rtc alarm", dev); if (unlikely(ret)) { dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 266aa325569..cfcc3caf49d 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -808,7 +808,7 @@ static int sci_request_irq(struct sci_port *port) } if (request_irq(port->irqs[0], sci_mpxed_interrupt, - SA_INTERRUPT, "sci", port)) { + IRQF_DISABLED, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } @@ -817,7 +817,7 @@ static int sci_request_irq(struct sci_port *port) if (!port->irqs[i]) continue; if (request_irq(port->irqs[i], handlers[i], - SA_INTERRUPT, desc[i], port)) { + IRQF_DISABLED, desc[i], port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h index fed26616967..80ee1cda749 100644 --- a/include/asm-sh/hw_irq.h +++ b/include/asm-sh/hw_irq.h @@ -1,4 +1,8 @@ #ifndef __ASM_SH_HW_IRQ_H #define __ASM_SH_HW_IRQ_H +#include + +extern atomic_t irq_err_count; + #endif /* __ASM_SH_HW_IRQ_H */ diff --git a/include/asm-sh/irq_regs.h b/include/asm-sh/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-sh/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h index 341cb71c2f9..5df842bcf7b 100644 --- a/include/asm-sh/timer.h +++ b/include/asm-sh/timer.h @@ -36,7 +36,6 @@ static inline unsigned long get_timer_offset(void) struct sys_timer *get_sys_timer(void); /* arch/sh/kernel/time.c */ -void handle_timer_tick(struct pt_regs *); +void handle_timer_tick(void); #endif /* __ASM_SH_TIMER_H */ - -- GitLab From 257440b00ba42a96522255029aa9406ffb7e2f62 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 6 Oct 2006 15:33:00 +0900 Subject: [PATCH 0682/1619] sh: Convert r7780rp IRQ handler to IRQ chip. Simple conversion of the R7780RP IRQ handler to struct irq_chip. Signed-off-by: Paul Mundt --- arch/sh/boards/renesas/r7780rp/irq.c | 105 ++++++--------------------- 1 file changed, 22 insertions(+), 83 deletions(-) diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c index 2d960e9a314..5519d3da6bc 100644 --- a/arch/sh/boards/renesas/r7780rp/irq.c +++ b/arch/sh/boards/renesas/r7780rp/irq.c @@ -1,18 +1,16 @@ /* - * linux/arch/sh/boards/renesas/r7780rp/irq.c - * - * Copyright (C) 2000 Kazumoto Kojima - * * Renesas Solutions Highlander R7780RP-1 Support. * - * Modified for R7780RP-1 by - * Atom Create Engineering Co., Ltd. 2002. + * Copyright (C) 2002 Atom Create Engineering Co., Ltd. + * Copyright (C) 2006 Paul Mundt + * + * 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 #ifdef CONFIG_SH_R7780MP static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0}; @@ -20,71 +18,26 @@ static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0}; static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0}; #endif -static void enable_r7780rp_irq(unsigned int irq); -static void disable_r7780rp_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_r7780rp_irq disable_r7780rp_irq - -static void ack_r7780rp_irq(unsigned int irq); -static void end_r7780rp_irq(unsigned int irq); - -static unsigned int startup_r7780rp_irq(unsigned int irq) -{ - enable_r7780rp_irq(irq); - return 0; /* never anything pending */ -} - -static void disable_r7780rp_irq(unsigned int irq) -{ - unsigned short val; - unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]); - - /* Set the priority in IPR to 0 */ - val = ctrl_inw(IRLCNTR1); - val &= mask; - ctrl_outw(val, IRLCNTR1); -} - static void enable_r7780rp_irq(unsigned int irq) { - unsigned short val; - unsigned short value = (0x0001 << mask_pos[irq]); - /* Set priority in IPR back to original value */ - val = ctrl_inw(IRLCNTR1); - val |= value; - ctrl_outw(val, IRLCNTR1); -} - -static void ack_r7780rp_irq(unsigned int irq) -{ - disable_r7780rp_irq(irq); + ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1); } -static void end_r7780rp_irq(unsigned int irq) +static void disable_r7780rp_irq(unsigned int irq) { - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_r7780rp_irq(irq); + /* Set the priority in IPR to 0 */ + ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])), + IRLCNTR1); } -static struct hw_interrupt_type r7780rp_irq_type = { - .typename = "R7780RP-IRQ", - .startup = startup_r7780rp_irq, - .shutdown = shutdown_r7780rp_irq, - .enable = enable_r7780rp_irq, - .disable = disable_r7780rp_irq, - .ack = ack_r7780rp_irq, - .end = end_r7780rp_irq, +static struct irq_chip r7780rp_irq_chip __read_mostly = { + .name = "r7780rp", + .mask = disable_r7780rp_irq, + .unmask = enable_r7780rp_irq, + .mask_ack = disable_r7780rp_irq, }; -static void make_r7780rp_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].chip = &r7780rp_irq_type; - disable_r7780rp_irq(irq); -} - /* * Initialize IRQ setting */ @@ -92,24 +45,10 @@ void __init init_r7780rp_IRQ(void) { int i; - /* IRL0=PCI Slot #A - * IRL1=PCI Slot #B - * IRL2=PCI Slot #C - * IRL3=PCI Slot #D - * IRL4=CF Card - * IRL5=CF Card Insert - * IRL6=M66596 - * IRL7=SD Card - * IRL8=Touch Panel - * IRL9=SCI - * IRL10=Serial - * IRL11=Extention #A - * IRL11=Extention #B - * IRL12=Debug LAN - * IRL13=Push Switch - * IRL14=ZiggBee IO - */ - - for (i=0; i<15; i++) - make_r7780rp_irq(i); + for (i = 0; i < 15; i++) { + disable_irq_nosync(i); + set_irq_chip_and_handler(i, &r7780rp_irq_chip, + handle_level_irq); + disable_r7780rp_irq(i); + } } -- GitLab From 580410005daecd8e9f0e1baa9ddadbb7f706e7e2 Mon Sep 17 00:00:00 2001 From: Jamie Lenehan Date: Fri, 6 Oct 2006 15:36:15 +0900 Subject: [PATCH 0683/1619] sh: Fix pr_debug statements for sh4 Fix a problem uncovered by the recent change to always check the arguments to pr_debug. The sh7751 was using the wrong name for the PCI IO base address. Signed-off-by: Jamie Lenehan Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/pci-sh7751.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index dbe83788498..85e1ee2e2e7 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -155,7 +155,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) */ pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO, (64 << 10), - SH4_PCI_IO_BASE + PCIBIOS_MIN_IO); + SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO); /* * XXX: For now, leave this board-specific. In the event we have other @@ -163,7 +163,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) */ #ifdef CONFIG_SH_BIGSUR bigsur_port_map(PCIBIOS_MIN_IO, (64 << 10), - SH4_PCI_IO_BASE + PCIBIOS_MIN_IO, 0); + SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO, 0); #endif /* Make sure the MSB's of IO window are set to access PCI space -- GitLab From 525ccc452c79db41874c5edac3f67618a0997d6f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 6 Oct 2006 17:35:48 +0900 Subject: [PATCH 0684/1619] sh: Convert INTC2 IRQ handler to irq_chip. More struct irq_chip conversions, this time the INTC2 handlers. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/irq/intc2.c | 138 ++++++--------------------------- include/asm-sh/irq.h | 14 ++-- 2 files changed, 32 insertions(+), 120 deletions(-) diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c index e30e4b7aa70..d4b2bb7e08c 100644 --- a/arch/sh/kernel/cpu/irq/intc2.c +++ b/arch/sh/kernel/cpu/irq/intc2.c @@ -10,93 +10,32 @@ * These are the "new Hitachi style" interrupts, as present on the * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. */ - #include #include #include #include #include -#include - -struct intc2_data { - unsigned char msk_offset; - unsigned char msk_shift; - - int (*clear_irq) (int); -}; - -static struct intc2_data intc2_data[NR_INTC2_IRQS]; - -static void enable_intc2_irq(unsigned int irq); -static void disable_intc2_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_intc2_irq disable_intc2_irq - -static void mask_and_ack_intc2(unsigned int); -static void end_intc2_irq(unsigned int irq); - -static unsigned int startup_intc2_irq(unsigned int irq) -{ - enable_intc2_irq(irq); - return 0; /* never anything pending */ -} - -static struct hw_interrupt_type intc2_irq_type = { - .typename = "INTC2-IRQ", - .startup = startup_intc2_irq, - .shutdown = shutdown_intc2_irq, - .enable = enable_intc2_irq, - .disable = disable_intc2_irq, - .ack = mask_and_ack_intc2, - .end = end_intc2_irq -}; static void disable_intc2_irq(unsigned int irq) { - int irq_offset = irq - INTC2_FIRST_IRQ; - int msk_shift, msk_offset; - - /* Sanity check */ - if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) - return; - - msk_shift = intc2_data[irq_offset].msk_shift; - msk_offset = intc2_data[irq_offset].msk_offset; - - ctrl_outl(1 << msk_shift, - INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset); + struct intc2_data *p = get_irq_chip_data(irq); + ctrl_outl(1 << p->msk_shift, + INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset); } static void enable_intc2_irq(unsigned int irq) { - int irq_offset = irq - INTC2_FIRST_IRQ; - int msk_shift, msk_offset; - - /* Sanity check */ - if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) - return; - - msk_shift = intc2_data[irq_offset].msk_shift; - msk_offset = intc2_data[irq_offset].msk_offset; - - ctrl_outl(1 << msk_shift, - INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset); -} - -static void mask_and_ack_intc2(unsigned int irq) -{ - disable_intc2_irq(irq); + struct intc2_data *p = get_irq_chip_data(irq); + ctrl_outl(1 << p->msk_shift, + INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset); } -static void end_intc2_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_intc2_irq(irq); - - if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)) - intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq); -} +static struct irq_chip intc2_irq_chip = { + .typename = "intc2", + .mask = disable_intc2_irq, + .unmask = enable_intc2_irq, + .mask_ack = disable_intc2_irq, +}; /* * Setup an INTC2 style interrupt. @@ -108,46 +47,30 @@ static void end_intc2_irq(unsigned int irq) * | | | | * make_intc2_irq(84, 0, 16, 0, 13); */ -void make_intc2_irq(unsigned int irq, - unsigned int ipr_offset, unsigned int ipr_shift, - unsigned int msk_offset, unsigned int msk_shift, - unsigned int priority) +void make_intc2_irq(struct intc2_data *p) { - int irq_offset = irq - INTC2_FIRST_IRQ; unsigned int flags; unsigned long ipr; - if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS)) - return; - - disable_irq_nosync(irq); - - /* Fill the data we need */ - intc2_data[irq_offset].msk_offset = msk_offset; - intc2_data[irq_offset].msk_shift = msk_shift; - intc2_data[irq_offset].clear_irq = NULL; + disable_irq_nosync(p->irq); /* Set the priority level */ local_irq_save(flags); - ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset); - ipr &= ~(0xf << ipr_shift); - ipr |= priority << ipr_shift; - ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset); + ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset); + ipr &= ~(0xf << p->ipr_shift); + ipr |= p->priority << p->ipr_shift; + ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset); local_irq_restore(flags); - irq_desc[irq].chip = &intc2_irq_type; + set_irq_chip_and_handler(p->irq, &intc2_irq_chip, handle_level_irq); + set_irq_chip_data(p->irq, p); - disable_intc2_irq(irq); + enable_intc2_irq(p->irq); } -static struct intc2_init { - unsigned short irq; - unsigned char ipr_offset, ipr_shift; - unsigned char msk_offset, msk_shift; - unsigned char priority; -} intc2_init_data[] __initdata = { +static struct intc2_data intc2_irq_table[] = { #if defined(CONFIG_CPU_SUBTYPE_ST40) {64, 0, 0, 0, 0, 13}, /* PCI serr */ {65, 0, 4, 0, 1, 13}, /* PCI err */ @@ -266,19 +189,6 @@ void __init init_IRQ_intc2(void) { int i; - for (i = 0; i < ARRAY_SIZE(intc2_init_data); i++) { - struct intc2_init *p = intc2_init_data + i; - make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift, - p-> msk_offset, p->msk_shift, p->priority); - } -} - -/* Adds a termination callback to the interrupt */ -void intc2_add_clear_irq(int irq, int (*fn)(int)) -{ - if (unlikely(irq < INTC2_FIRST_IRQ)) - return; - - intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn; + for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++) + make_intc2_irq(intc2_irq_table + i); } - diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index 0e5f365aff7..28996f9c58c 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -697,13 +697,15 @@ extern int ipr_irq_demux(int irq); #define INTC2_INTPRI_OFFSET 0x00 -void make_intc2_irq(unsigned int irq, - unsigned int ipr_offset, unsigned int ipr_shift, - unsigned int msk_offset, unsigned int msk_shift, - unsigned int priority); +struct intc2_data { + unsigned short irq; + unsigned char ipr_offset, ipr_shift; + unsigned char msk_offset, msk_shift; + unsigned char priority; +}; + +void make_intc2_irq(struct intc2_data *); void init_IRQ_intc2(void); -void intc2_add_clear_irq(int irq, int (*fn)(int)); - #endif extern int shmse_irq_demux(int irq); -- GitLab From 0f13804ae9d894c1fbd90bde38ae2aa0f01b0edd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 6 Oct 2006 17:55:25 +0900 Subject: [PATCH 0685/1619] sh: Convert IPR-IRQ to IRQ chip. One more initial conversion.. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/irq/ipr.c | 102 ++++++++++------------------------- 1 file changed, 27 insertions(+), 75 deletions(-) diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index f785822cd5d..8944abdf6e1 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c @@ -1,11 +1,10 @@ /* - * arch/sh/kernel/cpu/irq/ipr.c + * Interrupt handling for IPR-based IRQ. * * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi * Copyright (C) 2000 Kazumoto Kojima - * Copyright (C) 2003 Takashi Kusuda - * - * Interrupt handling for IPR-based IRQ. + * Copyright (C) 2003 Takashi Kusuda + * Copyright (C) 2006 Paul Mundt * * Supported system: * On-chip supporting modules (TMU, RTC, etc.). @@ -13,12 +12,13 @@ * Hitachi SolutionEngine external I/O: * MS7709SE01, MS7709ASE01, and MS7750SE01 * + * 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 @@ -28,93 +28,45 @@ struct ipr_data { int shift; /* Shifts of the 16-bit data */ int priority; /* The priority */ }; -static struct ipr_data ipr_data[NR_IRQS]; - -static void enable_ipr_irq(unsigned int irq); -static void disable_ipr_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_ipr_irq disable_ipr_irq - -static void mask_and_ack_ipr(unsigned int); -static void end_ipr_irq(unsigned int irq); - -static unsigned int startup_ipr_irq(unsigned int irq) -{ - enable_ipr_irq(irq); - return 0; /* never anything pending */ -} - -static struct hw_interrupt_type ipr_irq_type = { - .typename = "IPR-IRQ", - .startup = startup_ipr_irq, - .shutdown = shutdown_ipr_irq, - .enable = enable_ipr_irq, - .disable = disable_ipr_irq, - .ack = mask_and_ack_ipr, - .end = end_ipr_irq -}; static void disable_ipr_irq(unsigned int irq) { - unsigned long val; - unsigned int addr = ipr_data[irq].addr; - unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); - + struct ipr_data *p = get_irq_chip_data(irq); /* Set the priority in IPR to 0 */ - val = ctrl_inw(addr); - val &= mask; - ctrl_outw(val, addr); + ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr); } static void enable_ipr_irq(unsigned int irq) { - unsigned long val; - unsigned int addr = ipr_data[irq].addr; - int priority = ipr_data[irq].priority; - unsigned short value = (priority << ipr_data[irq].shift); - + struct ipr_data *p = get_irq_chip_data(irq); /* Set priority in IPR back to original value */ - val = ctrl_inw(addr); - val |= value; - ctrl_outw(val, addr); + ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr); } -static void mask_and_ack_ipr(unsigned int irq) -{ - disable_ipr_irq(irq); - -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) - /* This is needed when we use edge triggered setting */ - /* XXX: Is it really needed? */ - if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) { - /* Clear external interrupt request */ - int a = ctrl_inb(INTC_IRR0); - a &= ~(1 << (irq - IRQ0_IRQ)); - ctrl_outb(a, INTC_IRR0); - } -#endif -} - -static void end_ipr_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_ipr_irq(irq); -} +static struct irq_chip ipr_irq_chip = { + .name = "ipr", + .mask = disable_ipr_irq, + .unmask = enable_ipr_irq, + .mask_ack = disable_ipr_irq, +}; void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) { + struct ipr_data ipr_data; + disable_irq_nosync(irq); - ipr_data[irq].addr = addr; - ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */ - ipr_data[irq].priority = priority; - irq_desc[irq].chip = &ipr_irq_type; - disable_ipr_irq(irq); + ipr_data.addr = addr; + ipr_data.shift = pos*4; /* POSition (0-3) x 4 means shift */ + ipr_data.priority = priority; + + set_irq_chip_and_handler(irq, &ipr_irq_chip, handle_level_irq); + set_irq_chip_data(irq, &ipr_data); + + enable_ipr_irq(irq); } +/* XXX: This needs to die a horrible death.. */ void __init init_IRQ(void) { #ifndef CONFIG_CPU_SUBTYPE_SH7780 -- GitLab From 3211be5c6a61946c75318069611699c90b10e0f8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 6 Oct 2006 21:09:40 +1000 Subject: [PATCH 0686/1619] [PPC] Fix some irq breakage with ARCH=ppc Signed-off-by: Paul Mackerras --- arch/ppc/kernel/time.c | 2 +- include/asm-ppc/floppy.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 187388625a7..d4b2cf74da6 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -142,7 +142,7 @@ void timer_interrupt(struct pt_regs * regs) while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { jiffy_stamp += tb_ticks_per_jiffy; - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); update_process_times(user_mode(regs)); if (smp_processor_id()) diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h index d3963ca79ad..ae316e6d2ca 100644 --- a/include/asm-ppc/floppy.h +++ b/include/asm-ppc/floppy.h @@ -38,14 +38,14 @@ static int virtual_dma_mode; static int doing_vdma; static struct fd_dma_ops *fd_ops; -static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t floppy_hardint(int irq, void *dev_id) { unsigned char st; int lcount; char *lptr; if (!doing_vdma) - return floppy_interrupt(irq, dev_id, regs); + return floppy_interrupt(irq, dev_id); st = 1; @@ -69,7 +69,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) virtual_dma_residue += virtual_dma_count; virtual_dma_count=0; doing_vdma = 0; - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); return IRQ_HANDLED; } return IRQ_HANDLED; -- GitLab From 13a2eea1461f5d54cc5d58334fbde4bf4cc9cb23 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 4 Oct 2006 17:25:44 +0200 Subject: [PATCH 0687/1619] [POWERPC] Fix harmless typo Fix a typo. Noticed by the unlikely profiler. Signed-off-by: Nick Piggin Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index ba069407172..f88a2a675d9 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -75,7 +75,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, /* This allocator was derived from x86_64's bit string search */ /* Sanity check */ - if (unlikely(npages) == 0) { + if (unlikely(npages == 0)) { if (printk_ratelimit()) WARN_ON(1); return DMA_ERROR_CODE; -- GitLab From 74c37e8c9f626ed000388bebdc781a8e35ee4ab7 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 4 Oct 2006 11:03:44 -0500 Subject: [PATCH 0688/1619] [POWERPC] Add DTS for MPC8349E-mITX board Add the DTS for the Freescale MPC 8349E-mITX reference board. Contact Vitesse for the driver for the VSC 7385. Signed-off-by: Timur Tabi Signed-off-by: Paul Mackerras --- arch/powerpc/boot/dts/mpc8349emitx.dts | 246 +++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc8349emitx.dts diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts new file mode 100644 index 00000000000..27807fc4588 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -0,0 +1,246 @@ +/* + * MPC8349E-mITX Device Tree Source + * + * Copyright 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +/ { + model = "MPC8349EMITX"; + compatible = "MPC834xMITX"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8349@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; + i-cache-line-size = <20>; + d-cache-size = <8000>; + i-cache-size = <8000>; + timebase-frequency = <0>; // from bootloader + bus-frequency = <0>; // from bootloader + clock-frequency = <0>; // from bootloader + 32-bit; + }; + }; + + memory { + device_type = "memory"; + reg = <00000000 10000000>; + }; + + soc8349@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <0>; // from bootloader + + wdt@200 { + device_type = "watchdog"; + compatible = "mpc83xx_wdt"; + reg = <200 100>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + spi@7000 { + device_type = "spi"; + compatible = "mpc83xx_spi"; + reg = <7000 1000>; + interrupts = <10 8>; + interrupt-parent = <700>; + mode = <0>; + }; + + usb@22000 { + device_type = "usb"; + compatible = "fsl-usb2-mph"; + reg = <22000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <27 2>; + phy_type = "ulpi"; + port1; + }; + + usb@23000 { + device_type = "usb"; + compatible = "fsl-usb2-dr"; + reg = <23000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <26 2>; + phy_type = "ulpi"; + }; + + mdio@24520 { + device_type = "mdio"; + compatible = "gianfar"; + reg = <24520 20>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <24520>; + + /* Vitesse 8201 */ + ethernet-phy@1c { + linux,phandle = <245201c>; + interrupt-parent = <700>; + interrupts = <12 2>; + reg = <1c>; + device_type = "ethernet-phy"; + }; + + /* Vitesse 7385 */ + ethernet-phy@1f { + linux,phandle = <245201f>; + interrupt-parent = <700>; + interrupts = <12 2>; + reg = <1f>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@24000 { + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <24000 1000>; + address = [ 00 00 00 00 00 00 ]; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <20 8 21 8 22 8>; + interrupt-parent = <700>; + phy-handle = <245201c>; + }; + + ethernet@25000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <25000 1000>; + address = [ 00 00 00 00 00 00 ]; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <23 8 24 8 25 8>; + interrupt-parent = <700>; + phy-handle = <245201f>; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; // from bootloader + interrupts = <9 8>; + interrupt-parent = <700>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; // from bootloader + interrupts = ; + interrupt-parent = <700>; + }; + + pci@8500 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x10 - SATA */ + 8000 0 0 1 700 16 8 /* SATA_INTA */ + >; + interrupt-parent = <700>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <42000000 0 80000000 80000000 0 10000000 + 02000000 0 90000000 90000000 0 10000000 + 01000000 0 00000000 e2000000 0 01000000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8500 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + pci@8600 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0E - MiniPCI Slot */ + 7000 0 0 1 700 15 8 /* PCI_INTA */ + + /* IDSEL 0x0F - PCI Slot */ + 7800 0 0 1 700 14 8 /* PCI_INTA */ + 7800 0 0 2 700 15 8 /* PCI_INTB */ + >; + interrupt-parent = <700>; + interrupts = <43 8>; + bus-range = <1 1>; + ranges = <42000000 0 a0000000 a0000000 0 10000000 + 02000000 0 b0000000 b0000000 0 10000000 + 01000000 0 00000000 e3000000 0 01000000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8600 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 10000>; + interrupts = ; + interrupt-parent = <700>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <0000007e>; + descriptor-types-mask = <01010ebf>; + }; + + pic@700 { + linux,phandle = <700>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <700 100>; + built-in; + device_type = "ipic"; + }; + }; +}; -- GitLab From 9938c474f39e416091db9993954996266a3f2edf Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 4 Oct 2006 22:28:00 -0500 Subject: [PATCH 0689/1619] [POWERPC] linux,tce-size property is 32 bits The "linux,tce-size" property is only 32 bits (see prom_initialize_tce_table() in arch/powerpc/kernel/prom_init.c). Treating it as an unsigned long in iommu_table_setparms() leads to access beyond the end of the property's buffer, so we pass garbage to the memset() in that function. [boot]0020 XICS Init i8259 legacy interrupt controller initialized [boot]0021 XICS Done PID hash table entries: 4096 (order: 12, 32768 bytes) cpu 0x0: Vector: 300 (Data Access) at [c0000000fe783850] pc: c000000000035e90: .memset+0x60/0xfc lr: c000000000044fa4: .iommu_table_setparms+0xb0/0x158 sp: c0000000fe783ad0 msr: 9000000000009032 dar: c000000100000000 dsisr: 42010000 current = 0xc00000000450e810 paca = 0xc000000000411580 pid = 1, comm = swapper enter ? for help [link register ] c000000000044fa4 .iommu_table_setparms+0xb0/0x158 [c0000000fe783ad0] c000000000044f4c .iommu_table_setparms+0x58/0x158 (unreliable) [c0000000fe783b70] c00000000004529c .iommu_bus_setup_pSeries+0x1c4/0x254 [c0000000fe783c00] c00000000002b8ac .do_bus_setup+0x3c/0xe4 [c0000000fe783c80] c00000000002c924 .pcibios_fixup_bus+0x64/0xd8 [c0000000fe783d00] c0000000001a2d5c .pci_scan_child_bus+0x6c/0x10c [c0000000fe783da0] c00000000002be28 .scan_phb+0x17c/0x1b4 [c0000000fe783e40] c0000000003cfa00 .pcibios_init+0x58/0x19c [c0000000fe783ec0] c0000000000094b4 .init+0x1e8/0x3d8 [c0000000fe783f90] c000000000026e54 .kernel_thread+0x4c/0x68 Signed-off-by: Nathan Lynch Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index bbf2e34dc35..d24ba547e53 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -267,7 +267,8 @@ static void iommu_table_setparms(struct pci_controller *phb, struct iommu_table *tbl) { struct device_node *node; - const unsigned long *basep, *sizep; + const unsigned long *basep; + const u32 *sizep; node = (struct device_node *)phb->arch_data; -- GitLab From c998de146061db17787c1a31a3db1989f1341fdf Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 5 Oct 2006 14:18:46 +1000 Subject: [PATCH 0690/1619] [POWERPC] Fix zImage decompress location The zImage wrapper has a "hack" that force the decompression to happen above 20Mb for 64 bits kernels, to work around issues with some firmwares on the field. However, the new wrapper has a bug which makes that hack not work properly. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/boot/of.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c index fd99f789a37..3a71845afc6 100644 --- a/arch/powerpc/boot/of.c +++ b/arch/powerpc/boot/of.c @@ -176,12 +176,9 @@ static void *claim(unsigned long virt, unsigned long size, unsigned long align) static void *of_try_claim(u32 size) { unsigned long addr = 0; - static u8 first_time = 1; - if (first_time) { + if (claim_base == 0) claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB); - first_time = 0; - } for(; claim_base < RAM_END; claim_base += ONE_MB) { #ifdef DEBUG -- GitLab From 41550c5128150175197257b6ceab2cd50dea7b51 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 5 Oct 2006 16:40:41 +1000 Subject: [PATCH 0691/1619] [POWERPC] Don't get PCI IRQ from OF for devices with no IRQ This patch adds checking of the PCI_INTERRUPT_PIN register before using standard OF parsing to retreive PCI interrupts. The reason is that some PCI devices may have no PCI interrupt, though they may have interrupts attached via other means. In this case, we shall not use irq->pdev, but device-specific code can later retreive those interrupts instead. Without that patch, Maple and derivatives don't get the right interrupt for the second IDE channel as the linux IDE code fallsback to the PCI irq instead of trying to use the legacy ones for the on-board controller (which has no PCI_INTERRUPT_PIN). Having no PCI IRQ assign to it (as it doesn't request any) fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_parse.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 603dff3ad62..17fcb4842fe 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -914,6 +914,17 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) u8 pin; int rc; + /* We need to first check if the PCI device has a PCI interrupt at all + * since we have cases where the device-node might expose non-PCI + * interrupts, but the device has no PCI interrupt to it + */ + rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); + if (rc != 0) + return rc; + /* No pin, exit */ + if (pin == 0) + return -ENODEV; + /* Check if we have a device node, if yes, fallback to standard OF * parsing */ @@ -925,12 +936,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) * interrupt spec. we assume #interrupt-cells is 1, which is standard * for PCI. If you do different, then don't use that routine. */ - rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); - if (rc != 0) - return rc; - /* No pin, exit */ - if (pin == 0) - return -ENODEV; /* Now we walk up the PCI tree */ lspec = pin; -- GitLab From 3afbf5d6ef791be61d18329ae5302bbf1cd83723 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 5 Oct 2006 10:52:04 -0500 Subject: [PATCH 0692/1619] [POWERPC] Update pSeries defconfig for SATA Since the ipr driver now supports SATA and depends on libata, enable libata to get built. Signed-off-by: Brian King Signed-off-by: Paul Mackerras --- arch/powerpc/configs/pseries_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 44175fb7ade..9828663652e 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -506,7 +506,7 @@ CONFIG_SCSI_SAS_ATTRS=m # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set -# CONFIG_ATA is not set +CONFIG_ATA=y # CONFIG_SCSI_HPTIOP is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set -- GitLab From 52aed7cd52ce8a1d576e26976c3950512e1af8b6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 6 Oct 2006 02:54:07 +1000 Subject: [PATCH 0693/1619] [POWERPC] Update MTFSF_L() comment David Woodhouse points out that the comment accompanying the MTFSF_L macro is misleading. We should make it clear that the L bit is ignored on older CPUS, not the entire instruction. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- include/asm-powerpc/reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 3a9fcc15811..8fb96811b55 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -503,7 +503,7 @@ /* * An mtfsf instruction with the L bit set. On CPUs that support this a - * full 64bits of FPSCR is restored and on other CPUs it is ignored. + * full 64bits of FPSCR is restored and on other CPUs the L bit is ignored. * * Until binutils gets the new form of mtfsf, hardwire the instruction. */ -- GitLab From c1ce464d29e5bbf5819b2d7527b7d3030a6d65f1 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Thu, 5 Oct 2006 11:35:16 -0700 Subject: [PATCH 0694/1619] [POWERPC] Minor fix for bootargs property Avoid the use of an uninitialized stack variable when the powerpc device tree bootargs property is either missing or incorrectly defined. This also makes CONFIG_CMDLINE work properly under these conditions. This change adds a test for the existence of the bootargs property. early_init_dt_scan_chosen() tests for a zero length bootargs property in its CONFIG_CMDLINE processing, but the current implementation of of_get_flat_dt_prop() doesn't assign a value to the length when no property is found. Since an automatic variable is used, a stale value from the stack will be used in the test. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index eb913f80bfb..865b9648d0d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -724,7 +724,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); #ifdef CONFIG_CMDLINE - if (l == 0 || (l == 1 && (*p) == 0)) + if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); #endif /* CONFIG_CMDLINE */ -- GitLab From d83682b3971d6707d6d668b3b62d416ab7dd1ab3 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 6 Oct 2006 16:38:22 +0200 Subject: [PATCH 0695/1619] [S390] ap bus poll thread priority. The ap bus is supposed to have a low priority. We must use 19 instead of -20, which is just the opposite. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index cd30f37fcea..c5ccd20b110 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1062,7 +1062,7 @@ static int ap_poll_thread(void *data) unsigned long flags; int requests; - set_user_nice(current, -20); + set_user_nice(current, 19); while (1) { if (need_resched()) { schedule(); -- GitLab From 2d103d5a80846e96e1cb1ba5e635e8c37d30ada8 Mon Sep 17 00:00:00 2001 From: Melissa Howland Date: Fri, 6 Oct 2006 16:38:26 +0200 Subject: [PATCH 0696/1619] [S390] monwriter buffer limit. Make max_bufs a global (per linux guest) limit. Signed-off-by: Melissa Howland Signed-off-by: Martin Schwidefsky --- drivers/s390/char/monwriter.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 1e3939aeb8a..4362ff26024 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -26,6 +26,7 @@ #define MONWRITE_MAX_DATALEN 4024 static int mon_max_bufs = 255; +static int mon_buf_count; struct mon_buf { struct list_head list; @@ -40,7 +41,6 @@ struct mon_private { size_t hdr_to_read; size_t data_to_read; struct mon_buf *current_buf; - int mon_buf_count; }; /* @@ -99,13 +99,13 @@ static int monwrite_new_hdr(struct mon_private *monpriv) rc = monwrite_diag(monhdr, monbuf->data, APPLDATA_STOP_REC); list_del(&monbuf->list); - monpriv->mon_buf_count--; + mon_buf_count--; kfree(monbuf->data); kfree(monbuf); monbuf = NULL; } } else { - if (monpriv->mon_buf_count >= mon_max_bufs) + if (mon_buf_count >= mon_max_bufs) return -ENOSPC; monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL); if (!monbuf) @@ -118,7 +118,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) } monbuf->hdr = *monhdr; list_add_tail(&monbuf->list, &monpriv->list); - monpriv->mon_buf_count++; + mon_buf_count++; } monpriv->current_buf = monbuf; return 0; @@ -186,7 +186,7 @@ static int monwrite_close(struct inode *inode, struct file *filp) if (entry->hdr.mon_function != MONWRITE_GEN_EVENT) monwrite_diag(&entry->hdr, entry->data, APPLDATA_STOP_REC); - monpriv->mon_buf_count--; + mon_buf_count--; list_del(&entry->list); kfree(entry->data); kfree(entry); -- GitLab From 7e8ae7bfe8354b1f1b98c5cd29db8965ca1e6391 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 6 Oct 2006 16:38:29 +0200 Subject: [PATCH 0697/1619] [S390] cio: 0 is a valid chpid. In order to determine chpid validity, we need to check whether the corresponding path is specified in the pim. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 3bb4e472d73..07c7f19339d 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -200,11 +200,13 @@ css_get_ssd_info(struct subchannel *sch) spin_unlock_irq(&sch->lock); free_page((unsigned long)page); if (!ret) { - int j, chpid; + int j, chpid, mask; /* Allocate channel path structures, if needed. */ for (j = 0; j < 8; j++) { + mask = 0x80 >> j; chpid = sch->ssd_info.chpid[j]; - if (chpid && (get_chp_status(chpid) < 0)) + if ((sch->schib.pmcw.pim & mask) && + (get_chp_status(chpid) < 0)) new_channel_path(chpid); } } @@ -222,13 +224,15 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) sch = to_subchannel(dev); chpid = data; - for (j = 0; j < 8; j++) - if (sch->schib.pmcw.chpid[j] == chpid->id) + for (j = 0; j < 8; j++) { + mask = 0x80 >> j; + if ((sch->schib.pmcw.pim & mask) && + (sch->schib.pmcw.chpid[j] == chpid->id)) break; + } if (j >= 8) return 0; - mask = 0x80 >> j; spin_lock_irq(&sch->lock); stsch(sch->schid, &schib); @@ -620,7 +624,7 @@ __chp_add_new_sch(struct subchannel_id schid) static int __chp_add(struct subchannel_id schid, void *data) { - int i; + int i, mask; struct channel_path *chp; struct subchannel *sch; @@ -630,8 +634,10 @@ __chp_add(struct subchannel_id schid, void *data) /* Check if the subchannel is now available. */ return __chp_add_new_sch(schid); spin_lock_irq(&sch->lock); - for (i=0; i<8; i++) - if (sch->schib.pmcw.chpid[i] == chp->id) { + for (i=0; i<8; i++) { + mask = 0x80 >> i; + if ((sch->schib.pmcw.pim & mask) && + (sch->schib.pmcw.chpid[i] == chp->id)) { if (stsch(sch->schid, &sch->schib) != 0) { /* Endgame. */ spin_unlock_irq(&sch->lock); @@ -639,6 +645,7 @@ __chp_add(struct subchannel_id schid, void *data) } break; } + } if (i==8) { spin_unlock_irq(&sch->lock); return 0; @@ -646,7 +653,7 @@ __chp_add(struct subchannel_id schid, void *data) sch->lpm = ((sch->schib.pmcw.pim & sch->schib.pmcw.pam & sch->schib.pmcw.pom) - | 0x80 >> i) & sch->opm; + | mask) & sch->opm; if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); -- GitLab From 5a489b9846f688db7e69aa7ccb23c53459a9c20e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 6 Oct 2006 16:38:35 +0200 Subject: [PATCH 0698/1619] [S390] irq change build fixes. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/s390_ext.c | 9 ++++++--- arch/s390/kernel/smp.c | 2 +- arch/s390/kernel/time.c | 15 +++++++++------ arch/s390/kernel/traps.c | 2 +- arch/s390/kernel/vtime.c | 5 +++-- arch/s390/mm/fault.c | 2 +- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/char/ctrlchar.c | 2 +- drivers/s390/char/keyboard.c | 2 +- drivers/s390/char/sclp.c | 4 ++-- drivers/s390/cio/cio.c | 6 +++++- drivers/s390/net/iucv.c | 4 ++-- include/asm-s390/hardirq.h | 2 +- include/asm-s390/irq_regs.h | 1 + include/asm-s390/s390_ext.h | 2 +- 15 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 include/asm-s390/irq_regs.h diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index c1b383537fe..c49ab8c784d 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -16,6 +16,7 @@ #include #include +#include #include /* @@ -114,26 +115,28 @@ void do_extint(struct pt_regs *regs, unsigned short code) { ext_int_info_t *p; int index; + struct pt_regs *old_regs; irq_enter(); + old_regs = set_irq_regs(regs); asm volatile ("mc 0,0"); if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) /** * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(regs); + account_ticks(); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; index = ext_hash(code); for (p = ext_int_hash[index]; p; p = p->next) { if (likely(p->code == code)) { if (likely(p->handler)) - p->handler(regs, code); + p->handler(code); } } + set_irq_regs(old_regs); irq_exit(); } EXPORT_SYMBOL(register_external_interrupt); EXPORT_SYMBOL(unregister_external_interrupt); - diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index a8e6199755d..62822245f9b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -339,7 +339,7 @@ void machine_power_off_smp(void) * cpus are handled. */ -void do_ext_call_interrupt(struct pt_regs *regs, __u16 code) +void do_ext_call_interrupt(__u16 code) { unsigned long bits; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 4bf66cc4a26..2c8c690688c 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -34,6 +34,7 @@ #include #include #include +#include #include /* change this if you have some constant time drift */ @@ -150,9 +151,9 @@ EXPORT_SYMBOL(do_settimeofday); #ifdef CONFIG_PROFILING -#define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) +#define s390_do_profile() profile_tick(CPU_PROFILING) #else -#define s390_do_profile(regs) do { ; } while(0) +#define s390_do_profile() do { ; } while(0) #endif /* CONFIG_PROFILING */ @@ -160,7 +161,7 @@ EXPORT_SYMBOL(do_settimeofday); * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -void account_ticks(struct pt_regs *regs) +void account_ticks(void) { __u64 tmp; __u32 ticks; @@ -221,10 +222,10 @@ void account_ticks(struct pt_regs *regs) account_tick_vtime(current); #else while (ticks--) - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif - s390_do_profile(regs); + s390_do_profile(); } #ifdef CONFIG_NO_IDLE_HZ @@ -285,9 +286,11 @@ static inline void stop_hz_timer(void) */ static inline void start_hz_timer(void) { + BUG_ON(!in_interrupt()); + if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) return; - account_ticks(task_pt_regs(current)); + account_ticks(); cpu_clear(smp_processor_id(), nohz_cpu_mask); } diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 3eb4fab048b..05bf3cc8530 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -61,7 +61,7 @@ extern pgm_check_handler_t do_dat_exception; #ifdef CONFIG_PFAULT extern int pfault_init(void); extern void pfault_fini(void); -extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code); +extern void pfault_interrupt(__u16 error_code); static ext_int_info_t ext_int_pfault; #endif extern pgm_check_handler_t do_monitor_call; diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 2306cd83fca..1d7d3938b2b 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -22,6 +22,7 @@ #include #include +#include static ext_int_info_t ext_int_info_timer; DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); @@ -241,7 +242,7 @@ static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs) /* * Handler for the virtual CPU timer. */ -static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code) +static void do_cpu_timer_interrupt(__u16 error_code) { int cpu; __u64 next, delta; @@ -274,7 +275,7 @@ static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code) list_move_tail(&event->entry, &cb_list); } spin_unlock(&vt_list->lock); - do_callbacks(&cb_list, regs); + do_callbacks(&cb_list, get_irq_regs()); /* next event is first in list */ spin_lock(&vt_list->lock); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 9c3c19fe62f..1c323bbfda9 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -451,7 +451,7 @@ void pfault_fini(void) } asmlinkage void -pfault_interrupt(struct pt_regs *regs, __u16 error_code) +pfault_interrupt(__u16 error_code) { struct task_struct *tsk; __u16 subcode; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 222a8a71a5e..53db58a6861 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -218,7 +218,7 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr) /* Handle external interruption. */ static void -dasd_ext_handler(struct pt_regs *regs, __u16 code) +dasd_ext_handler(__u16 code) { struct dasd_ccw_req *cqr, *next; struct dasd_device *device; diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c index d83eb6358ba..49e9628d929 100644 --- a/drivers/s390/char/ctrlchar.c +++ b/drivers/s390/char/ctrlchar.c @@ -20,7 +20,7 @@ static int ctrlchar_sysrq_key; static void ctrlchar_handle_sysrq(void *tty) { - handle_sysrq(ctrlchar_sysrq_key, NULL, (struct tty_struct *) tty); + handle_sysrq(ctrlchar_sysrq_key, (struct tty_struct *) tty); } static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL); diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 3be06569180..e3491a5f521 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -304,7 +304,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) if (kbd->sysrq) { if (kbd->sysrq == K(KT_LATIN, '-')) { kbd->sysrq = 0; - handle_sysrq(value, NULL, kbd->tty); + handle_sysrq(value, kbd->tty); return; } if (value == '-') { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 31e335751d6..8a056df09d6 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -324,7 +324,7 @@ __sclp_find_req(u32 sccb) * Prepare read event data request if necessary. Start processing of next * request on queue. */ static void -sclp_interrupt_handler(struct pt_regs *regs, __u16 code) +sclp_interrupt_handler(__u16 code) { struct sclp_req *req; u32 finished_sccb; @@ -743,7 +743,7 @@ EXPORT_SYMBOL(sclp_reactivate); /* Handler for external interruption used during initialization. Modify * request state to done. */ static void -sclp_check_handler(struct pt_regs *regs, __u16 code) +sclp_check_handler(__u16 code) { u32 finished_sccb; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 2e2882daefb..f18b1623cad 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "airq.h" #include "cio.h" @@ -606,15 +607,17 @@ do_IRQ (struct pt_regs *regs) struct tpi_info *tpi_info; struct subchannel *sch; struct irb *irb; + struct pt_regs *old_regs; irq_enter (); + old_regs = set_irq_regs(regs); asm volatile ("mc 0,0"); if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) /** * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(regs); + account_ticks(); /* * Get interrupt information from lowcore */ @@ -652,6 +655,7 @@ do_IRQ (struct pt_regs *regs) * out of the sie which costs more cycles than it saves. */ } while (!MACHINE_IS_VM && tpi (NULL) != 0); + set_irq_regs(old_regs); irq_exit (); } diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index 809dd8d7f47..1476ce2b437 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c @@ -116,7 +116,7 @@ static DEFINE_SPINLOCK(iucv_irq_queue_lock); *Internal function prototypes */ static void iucv_tasklet_handler(unsigned long); -static void iucv_irq_handler(struct pt_regs *, __u16); +static void iucv_irq_handler(__u16); static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0); @@ -2251,7 +2251,7 @@ iucv_sever(__u16 pathid, __u8 user_data[16]) * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler(). */ static void -iucv_irq_handler(struct pt_regs *regs, __u16 code) +iucv_irq_handler(__u16 code) { iucv_irqdata *irqdata; diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index e84b7ef54aa..c2f6a8782d3 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -32,6 +32,6 @@ typedef struct { #define HARDIRQ_BITS 8 -extern void account_ticks(struct pt_regs *); +extern void account_ticks(void); #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-s390/irq_regs.h b/include/asm-s390/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-s390/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h index e9a2862b230..df9b1017b70 100644 --- a/include/asm-s390/s390_ext.h +++ b/include/asm-s390/s390_ext.h @@ -10,7 +10,7 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ -typedef void (*ext_int_handler_t)(struct pt_regs *regs, __u16 code); +typedef void (*ext_int_handler_t)(__u16 code); /* * Warning: if you change ext_int_info_t you have to change the -- GitLab From 2033b0c330d50d3f1cccd207147a10ad7f4f47f8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 6 Oct 2006 16:38:42 +0200 Subject: [PATCH 0699/1619] [PATCH] sysrq: irq change build fix. drivers/char/sysrq.c: In function `sysrq_handle_crashdump': drivers/char/sysrq.c:98: warning: implicit declaration of function `get_irq_regs' Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/char/sysrq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 4c0e0868570..5f49280779f 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -38,6 +38,7 @@ #include #include +#include /* Whether we react on sysrq keys or just ignore them */ int sysrq_enabled = 1; -- GitLab From dc64bef5439c8e1fafea225054da4d8882c9d10c Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 6 Oct 2006 16:38:48 +0200 Subject: [PATCH 0700/1619] [S390] Use CONFIG_GENERIC_TIME and define TOD clock source. Fix too slow clock by using CONFIG_GENERIC_TIME and adding a clock source for the s390 time-of-day clock. As added benefit we get rid of the s390 specific definition of do_gettimeofday and do_settimeofday. Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 3 ++ arch/s390/defconfig | 1 + arch/s390/kernel/time.c | 88 ++++++++++------------------------------- 3 files changed, 24 insertions(+), 68 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 51c2dfe89c6..608193cfe43 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -30,6 +30,9 @@ config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_TIME + def_bool y + config GENERIC_BUST_SPINLOCK bool diff --git a/arch/s390/defconfig b/arch/s390/defconfig index b6cad75fd1f..a3257398ea8 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -9,6 +9,7 @@ CONFIG_STACKTRACE_SUPPORT=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y CONFIG_S390=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 2c8c690688c..6cceed4df73 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -82,74 +83,6 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) xtime->tv_nsec = ((todval * 1000) >> 12); } -static inline unsigned long do_gettimeoffset(void) -{ - __u64 now; - - now = (get_clock() - jiffies_timer_cc) >> 12; - now -= (__u64) jiffies * USECS_PER_JIFFY; - return (unsigned long) now; -} - -/* - * This version of gettimeofday has microsecond resolution. - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned long usec, sec; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - - sec = xtime.tv_sec; - usec = xtime.tv_nsec / 1000 + do_gettimeoffset(); - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - /* This is revolting. We need to set the xtime.tv_nsec - * correctly. However, the value in this location is - * is value at the last tick. - * Discover what correction gettimeofday - * would have done, and then undo it! - */ - nsec -= do_gettimeoffset() * 1000; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - - #ifdef CONFIG_PROFILING #define s390_do_profile() profile_tick(CPU_PROFILING) #else @@ -340,6 +273,22 @@ void init_cpu_timer(void) extern void vtime_init(void); +static cycle_t read_tod_clock(void) +{ + return get_clock(); +} + +static struct clocksource clocksource_tod = { + .name = "tod", + .rating = 100, + .read = read_tod_clock, + .mask = -1ULL, + .mult = 1000, + .shift = 12, + .is_continuous = 1, +}; + + /* * Initialize the TOD clock and the CPU timer of * the boot cpu. @@ -384,6 +333,9 @@ void __init time_init(void) &ext_int_info_cc) != 0) panic("Couldn't request external interrupt 0x1004"); + if (clocksource_register(&clocksource_tod) != 0) + panic("Could not register TOD clock source"); + init_cpu_timer(); #ifdef CONFIG_NO_IDLE_HZ -- GitLab From d195412c35fe777811bd58ad43fba3aacc67e15c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 6 Oct 2006 00:43:48 -0700 Subject: [PATCH 0701/1619] [PATCH] i386: irqs build fix Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 7d500da0e63..2fd4b7d927c 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -1197,7 +1197,7 @@ inline void smp_local_timer_interrupt(void) { profile_tick(CPU_PROFILING); #ifdef CONFIG_SMP - update_process_times(user_mode_vm(irq_regs)); + update_process_times(user_mode_vm(get_irq_regs())); #endif /* -- GitLab From 4899b8b16b302299cc91289f7b5bac295e9ab387 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 6 Oct 2006 00:43:48 -0700 Subject: [PATCH 0702/1619] [PATCH] kauditd_thread warning fix Squash this warning: kernel/audit.c: In function 'kauditd_thread': kernel/audit.c:367: warning: no return statement in function returning non-void We might as test kthread_should_stop(), although it's not very pointful at present. The code which starts this thread looks racy - the kernel could start multiple threads. Cc: Al Viro Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/audit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/audit.c b/kernel/audit.c index f9889ee7782..98106f6078b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -340,7 +340,7 @@ static int kauditd_thread(void *dummy) { struct sk_buff *skb; - while (1) { + while (!kthread_should_stop()) { skb = skb_dequeue(&audit_skb_queue); wake_up(&audit_backlog_wait); if (skb) { @@ -369,6 +369,7 @@ static int kauditd_thread(void *dummy) remove_wait_queue(&kauditd_wait, &wait); } } + return 0; } int audit_send_list(void *_dest) -- GitLab From d69a892268c66c13fcb445a8274baa9d7befb7b5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 6 Oct 2006 00:43:49 -0700 Subject: [PATCH 0703/1619] [PATCH] Fix WARN_ON / WARN_ON_ONCE regression Tim and Ananiev report that the recent WARN_ON_ONCE changes cause increased cache misses with the tbench workload. Apparently due to the access to the newly-added static variable. Rearrange the code so that we don't touch that variable unless the warning is going to trigger. Also rework the logic so that the static variable starts out at zero, so we can move it into bss. It would seem logical to mark the static variable as __read_mostly too. But it would be wrong, because that would put it back into the vmlinux image, and the kernel will never read from this variable in normal operation anyway. Unless the compiler or hardware go and do some prefetching on us? For some reason this patch shrinks softirq.o text by 40 bytes. Cc: Tim Chen Cc: Herbert Xu Cc: "Ananiev, Leonid I" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/bug.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index a5250895155..1d9573cf4a0 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -41,14 +41,14 @@ #endif #endif -#define WARN_ON_ONCE(condition) ({ \ - static int __warn_once = 1; \ - typeof(condition) __ret_warn_once = (condition);\ - \ - if (likely(__warn_once)) \ - if (WARN_ON(__ret_warn_once)) \ - __warn_once = 0; \ - unlikely(__ret_warn_once); \ +#define WARN_ON_ONCE(condition) ({ \ + static int __warned; \ + typeof(condition) __ret_warn_once = (condition); \ + \ + if (unlikely(__ret_warn_once)) \ + if (WARN_ON(!__warned)) \ + __warned = 1; \ + unlikely(__ret_warn_once); \ }) #ifdef CONFIG_SMP -- GitLab From efbc52f945696702a97a78b12812093f61880c2c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 6 Oct 2006 00:43:50 -0700 Subject: [PATCH 0704/1619] [PATCH] irq_reqs: export __irq_regs Modules might want this. Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/irq_regs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/irq_regs.c b/lib/irq_regs.c index 101b1a4f9b1..753880a5440 100644 --- a/lib/irq_regs.c +++ b/lib/irq_regs.c @@ -8,8 +8,10 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include #ifndef ARCH_HAS_OWN_IRQ_REGS DEFINE_PER_CPU(struct pt_regs *, __irq_regs); +EXPORT_PER_CPU_SYMBOL(__irq_regs); #endif -- GitLab From da66b719d16f6ea3801b859c1ff35d5cd05c517d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 6 Oct 2006 00:43:51 -0700 Subject: [PATCH 0705/1619] [PATCH] ohci: don't play with IRQ regs This is a more correct fix for the way the ohci hcd was referencing pt_regs in the unlink paths. Signed-off-by: David Brownell Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/host/ohci-q.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index e08d1a2664e..fe1fe2f97cb 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -925,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 (get_irq_regs() && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) { + if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) { if (tick_before (tick, ed->tick)) { skip_ed: last = &ed->ed_next; -- GitLab From 1ca4cb2418c04914e4661c059cf5b7b9262c645a Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 6 Oct 2006 00:43:52 -0700 Subject: [PATCH 0706/1619] [PATCH] slab: reduce numa text size Reduce the NUMA text size of mm/slab.o a little on x86 by using a local variable to store the result of numa_node_id(). text data bss dec hex filename 16858 2584 16 19458 4c02 mm/slab.o (before) 16804 2584 16 19404 4bcc mm/slab.o (after) [akpm@osdl.org: use better names] [pbadari@us.ibm.com: fix that] Cc: Christoph Lameter Signed-off-by: Pekka Enberg Signed-off-by: Badari Pulavarty Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index e9a63b5a7fb..64fb0d770b0 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1106,15 +1106,18 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp) int nodeid = slabp->nodeid; struct kmem_list3 *l3; struct array_cache *alien = NULL; + int node; + + node = numa_node_id(); /* * Make sure we are not freeing a object from another node to the array * cache on this cpu. */ - if (likely(slabp->nodeid == numa_node_id())) + if (likely(slabp->nodeid == node)) return 0; - l3 = cachep->nodelists[numa_node_id()]; + l3 = cachep->nodelists[node]; STATS_INC_NODEFREES(cachep); if (l3->alien && l3->alien[nodeid]) { alien = l3->alien[nodeid]; @@ -1352,6 +1355,7 @@ void __init kmem_cache_init(void) struct cache_names *names; int i; int order; + int node; for (i = 0; i < NUM_INIT_LISTS; i++) { kmem_list3_init(&initkmem_list3[i]); @@ -1386,12 +1390,14 @@ void __init kmem_cache_init(void) * 6) Resize the head arrays of the kmalloc caches to their final sizes. */ + node = numa_node_id(); + /* 1) create the cache_cache */ INIT_LIST_HEAD(&cache_chain); list_add(&cache_cache.next, &cache_chain); cache_cache.colour_off = cache_line_size(); cache_cache.array[smp_processor_id()] = &initarray_cache.cache; - cache_cache.nodelists[numa_node_id()] = &initkmem_list3[CACHE_CACHE]; + cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE]; cache_cache.buffer_size = ALIGN(cache_cache.buffer_size, cache_line_size()); @@ -1496,19 +1502,18 @@ void __init kmem_cache_init(void) } /* 5) Replace the bootstrap kmem_list3's */ { - int node; + int nid; + /* Replace the static kmem_list3 structures for the boot cpu */ - init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], - numa_node_id()); + init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node); - for_each_online_node(node) { + for_each_online_node(nid) { init_list(malloc_sizes[INDEX_AC].cs_cachep, - &initkmem_list3[SIZE_AC + node], node); + &initkmem_list3[SIZE_AC + nid], nid); if (INDEX_AC != INDEX_L3) { init_list(malloc_sizes[INDEX_L3].cs_cachep, - &initkmem_list3[SIZE_L3 + node], - node); + &initkmem_list3[SIZE_L3 + nid], nid); } } } @@ -2918,6 +2923,9 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags) int batchcount; struct kmem_list3 *l3; struct array_cache *ac; + int node; + + node = numa_node_id(); check_irq_off(); ac = cpu_cache_get(cachep); @@ -2931,7 +2939,7 @@ retry: */ batchcount = BATCHREFILL_LIMIT; } - l3 = cachep->nodelists[numa_node_id()]; + l3 = cachep->nodelists[node]; BUG_ON(ac->avail > 0 || !l3); spin_lock(&l3->list_lock); @@ -2961,7 +2969,7 @@ retry: STATS_SET_HIGH(cachep); ac->entry[ac->avail++] = slab_get_obj(cachep, slabp, - numa_node_id()); + node); } check_slabp(cachep, slabp); @@ -2980,7 +2988,7 @@ alloc_done: if (unlikely(!ac->avail)) { int x; - x = cache_grow(cachep, flags, numa_node_id()); + x = cache_grow(cachep, flags, node); /* cache_grow can reenable interrupts, then ac could change. */ ac = cpu_cache_get(cachep); -- GitLab From 7f7bbbe50b8a28f4dfaa4cea939ddb50198c4a99 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 6 Oct 2006 00:43:53 -0700 Subject: [PATCH 0707/1619] [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(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index b7966ab8cb6..26146623be2 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 9cf3f341a28..b5a4aadd961 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? -- GitLab From 7236e978a3883406ca06ee79e0739743c7c92a85 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 6 Oct 2006 00:43:54 -0700 Subject: [PATCH 0708/1619] [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(+) diff --git a/include/linux/timex.h b/include/linux/timex.h index 049dfe4a11f..db501dc23c2 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 */ -- GitLab From d6359fd783251238dbbf70b7c2fc745db25cf51f Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 6 Oct 2006 00:43:55 -0700 Subject: [PATCH 0709/1619] [PATCH] m68k: cleanup string functions - cleanup asm of string functions - deinline strncat()/strncmp() - provide non-inlined strcpy() Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/m68k/kernel/m68k_ksyms.c | 4 - arch/m68k/lib/string.c | 15 ++- include/asm-m68k/string.h | 198 +++++++++++++++------------------- 3 files changed, 102 insertions(+), 115 deletions(-) diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index aff26a52167..f9636e84e6a 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -53,9 +52,6 @@ EXPORT_SYMBOL(mach_beep); #endif EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(kernel_thread); #ifdef CONFIG_VME EXPORT_SYMBOL(vme_brdtype); diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c index b92b89e1ea0..891e1347bc4 100644 --- a/arch/m68k/lib/string.c +++ b/arch/m68k/lib/string.c @@ -1,6 +1,19 @@ +/* + * 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. + */ + +#define __IN_STRING_C -#include #include +#include + +char *strcpy(char *dest, const char *src) +{ + return __kernel_strcpy(dest, src); +} +EXPORT_SYMBOL(strcpy); void *memset(void *s, int c, size_t count) { diff --git a/include/asm-m68k/string.h b/include/asm-m68k/string.h index 6c59215b285..2eb7df1e0f5 100644 --- a/include/asm-m68k/string.h +++ b/include/asm-m68k/string.h @@ -1,138 +1,114 @@ #ifndef _M68K_STRING_H_ #define _M68K_STRING_H_ -#include -#include +#include +#include -#define __HAVE_ARCH_STRCPY -static inline char * strcpy(char * dest,const char *src) +static inline size_t __kernel_strlen(const char *s) { - char *xdest = dest; - - __asm__ __volatile__ - ("1:\tmoveb %1@+,%0@+\n\t" - "jne 1b" - : "=a" (dest), "=a" (src) - : "0" (dest), "1" (src) : "memory"); - return xdest; -} + const char *sc; -#define __HAVE_ARCH_STRNCPY -static inline char * strncpy(char *dest, const char *src, size_t n) -{ - char *xdest = dest; - - if (n == 0) - return xdest; - - __asm__ __volatile__ - ("1:\tmoveb %1@+,%0@+\n\t" - "jeq 2f\n\t" - "subql #1,%2\n\t" - "jne 1b\n\t" - "2:" - : "=a" (dest), "=a" (src), "=d" (n) - : "0" (dest), "1" (src), "2" (n) - : "memory"); - return xdest; + for (sc = s; *sc++; ) + ; + return sc - s - 1; } -#define __HAVE_ARCH_STRCAT -static inline char * strcat(char * dest, const char * src) +static inline char *__kernel_strcpy(char *dest, const char *src) { - char *tmp = dest; - - while (*dest) - dest++; - while ((*dest++ = *src++)) - ; - - return tmp; + char *xdest = dest; + + asm volatile ("\n" + "1: move.b (%1)+,(%0)+\n" + " jne 1b" + : "+a" (dest), "+a" (src) + : : "memory"); + return xdest; } -#define __HAVE_ARCH_STRNCAT -static inline char * strncat(char *dest, const char *src, size_t count) -{ - char *tmp = dest; - - if (count) { - while (*dest) - dest++; - while ((*dest++ = *src++)) { - if (--count == 0) { - *dest++='\0'; - break; - } - } - } +#ifndef __IN_STRING_C - return tmp; -} +#define __HAVE_ARCH_STRLEN +#define strlen(s) (__builtin_constant_p(s) ? \ + __builtin_strlen(s) : \ + __kernel_strlen(s)) -#define __HAVE_ARCH_STRCHR -static inline char * strchr(const char * s, int c) +#define __HAVE_ARCH_STRNLEN +static inline size_t strnlen(const char *s, size_t count) { - const char ch = c; - - for(; *s != ch; ++s) - if (*s == '\0') - return( NULL ); - return( (char *) s); + const char *sc = s; + + asm volatile ("\n" + "1: subq.l #1,%1\n" + " jcs 2f\n" + " tst.b (%0)+\n" + " jne 1b\n" + " subq.l #1,%0\n" + "2:" + : "+a" (sc), "+d" (count)); + return sc - s; } -/* strstr !! */ +#define __HAVE_ARCH_STRCPY +#if __GNUC__ >= 4 +#define strcpy(d, s) (__builtin_constant_p(s) && \ + __builtin_strlen(s) <= 32 ? \ + __builtin_strcpy(d, s) : \ + __kernel_strcpy(d, s)) +#else +#define strcpy(d, s) __kernel_strcpy(d, s) +#endif -#define __HAVE_ARCH_STRLEN -static inline size_t strlen(const char * s) +#define __HAVE_ARCH_STRNCPY +static inline char *strncpy(char *dest, const char *src, size_t n) { - const char *sc; - for (sc = s; *sc != '\0'; ++sc) ; - return(sc - s); + char *xdest = dest; + + asm volatile ("\n" + " jra 2f\n" + "1: move.b (%1),(%0)+\n" + " jeq 2f\n" + " addq.l #1,%1\n" + "2: subq.l #1,%2\n" + " jcc 1b\n" + : "+a" (dest), "+a" (src), "+d" (n) + : : "memory"); + return xdest; } -/* strnlen !! */ +#define __HAVE_ARCH_STRCAT +#define strcat(d, s) ({ \ + char *__d = (d); \ + strcpy(__d + strlen(__d), (s)); \ +}) -#define __HAVE_ARCH_STRCMP -static inline int strcmp(const char * cs,const char * ct) +#define __HAVE_ARCH_STRCHR +static inline char *strchr(const char *s, int c) { - char __res; - - __asm__ - ("1:\tmoveb %0@+,%2\n\t" /* get *cs */ - "cmpb %1@+,%2\n\t" /* compare a byte */ - "jne 2f\n\t" /* not equal, break out */ - "tstb %2\n\t" /* at end of cs? */ - "jne 1b\n\t" /* no, keep going */ - "jra 3f\n\t" /* strings are equal */ - "2:\tsubb %1@-,%2\n\t" /* *cs - *ct */ - "3:" - : "=a" (cs), "=a" (ct), "=d" (__res) - : "0" (cs), "1" (ct)); - return __res; + char sc, ch = c; + + for (; (sc = *s++) != ch; ) { + if (!sc) + return NULL; + } + return (char *)s - 1; } -#define __HAVE_ARCH_STRNCMP -static inline int strncmp(const char * cs,const char * ct,size_t count) +#define __HAVE_ARCH_STRCMP +static inline int strcmp(const char *cs, const char *ct) { - char __res; - - if (!count) - return 0; - __asm__ - ("1:\tmovb %0@+,%3\n\t" /* get *cs */ - "cmpb %1@+,%3\n\t" /* compare a byte */ - "jne 3f\n\t" /* not equal, break out */ - "tstb %3\n\t" /* at end of cs? */ - "jeq 4f\n\t" /* yes, all done */ - "subql #1,%2\n\t" /* no, adjust count */ - "jne 1b\n\t" /* more to do, keep going */ - "2:\tmoveq #0,%3\n\t" /* strings are equal */ - "jra 4f\n\t" - "3:\tsubb %1@-,%3\n\t" /* *cs - *ct */ - "4:" - : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res) - : "0" (cs), "1" (ct), "2" (count)); - return __res; + char res; + + asm ("\n" + "1: move.b (%0)+,%2\n" /* get *cs */ + " cmp.b (%1)+,%2\n" /* compare a byte */ + " jne 2f\n" /* not equal, break out */ + " tst.b %2\n" /* at end of cs? */ + " jne 1b\n" /* no, keep going */ + " jra 3f\n" /* strings are equal */ + "2: sub.b -(%1),%2\n" /* *cs - *ct */ + "3:" + : "+a" (cs), "+a" (ct), "=d" (res)); + return res; } #define __HAVE_ARCH_MEMSET @@ -150,4 +126,6 @@ extern void *memmove(void *, const void *, __kernel_size_t); extern int memcmp(const void *, const void *, __kernel_size_t); #define memcmp(d, s, n) __builtin_memcmp(d, s, n) +#endif + #endif /* _M68K_STRING_H_ */ -- GitLab From 6c04c28a656c1717fbe617efc40edabca3a85ca3 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 6 Oct 2006 00:43:56 -0700 Subject: [PATCH 0710/1619] [PATCH] m68k: fix typo in __generic_copy_to_user Jump to the correct exit label after exception Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/m68k/lib/uaccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c index 1bc188c0d98..865f9fb9e68 100644 --- a/arch/m68k/lib/uaccess.c +++ b/arch/m68k/lib/uaccess.c @@ -84,7 +84,7 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from, " .even\n" "20: lsl.l #2,%0\n" "50: add.l %5,%0\n" - " jra 7b\n" + " jra 8b\n" " .previous\n" "\n" " .section __ex_table,\"a\"\n" -- GitLab From 9ef308946fa8390136130a886b0d9a57867a747a Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 6 Oct 2006 00:43:56 -0700 Subject: [PATCH 0711/1619] [PATCH] m68k: small system.h cleanup avoid unnecessary xchg() use in set_mb() Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-m68k/system.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h index 131a0cb0f49..243dd13e6bf 100644 --- a/include/asm-m68k/system.h +++ b/include/asm-m68k/system.h @@ -78,13 +78,13 @@ static inline int irqs_disabled(void) #define mb() barrier() #define rmb() barrier() #define wmb() barrier() -#define read_barrier_depends() do { } while(0) -#define set_mb(var, value) do { xchg(&var, value); } while (0) +#define read_barrier_depends() ((void)0) +#define set_mb(var, value) ({ (var) = (value); wmb(); }) #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() -#define smp_read_barrier_depends() do { } while(0) +#define smp_read_barrier_depends() ((void)0) #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -- GitLab From 5e7c4ea83efa9d6269bcbf17611f83aeef71c096 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 6 Oct 2006 00:43:57 -0700 Subject: [PATCH 0712/1619] [PATCH] m68k: fix NBPG define The recent header cleanup removed PAGE_SIZE from the exported information as it depends on the configuration. BTW This has possibly other consequences, as the core dump code is using PAGE_SIZE directly, which may need fixing as well. Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-m68k/user.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-m68k/user.h b/include/asm-m68k/user.h index e8d5a64c7e7..d7c0b109bd4 100644 --- a/include/asm-m68k/user.h +++ b/include/asm-m68k/user.h @@ -81,7 +81,7 @@ struct user{ unsigned long magic; /* To uniquely identify a core file */ char u_comm[32]; /* User command that was responsible */ }; -#define NBPG PAGE_SIZE +#define NBPG 4096 #define UPAGES 1 #define HOST_TEXT_START_ADDR (u.start_code) #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) -- GitLab From dc366708b3b022050f139347a44c65a102e4835d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 6 Oct 2006 00:43:58 -0700 Subject: [PATCH 0713/1619] [PATCH] m68k: dma_alloc_coherent() has gfp_t as the last argument annotate, fix the bogus argument of vmap() in it. Signed-off-by: Al Viro Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/m68k/kernel/dma.c | 4 ++-- include/asm-m68k/dma-mapping.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c index fc449f8b204..9d4e4b5b6bd 100644 --- a/arch/m68k/kernel/dma.c +++ b/arch/m68k/kernel/dma.c @@ -15,7 +15,7 @@ #include void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *handle, int flag) + dma_addr_t *handle, gfp_t flag) { struct page *page, **map; pgprot_t pgprot; @@ -51,7 +51,7 @@ void *dma_alloc_coherent(struct device *dev, size_t size, pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S; else pgprot_val(pgprot) |= _PAGE_NOCACHE030; - addr = vmap(map, size, flag, pgprot); + addr = vmap(map, size, VM_MAP, pgprot); kfree(map); return addr; diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h index cebbb03370e..c1299c3beb5 100644 --- a/include/asm-m68k/dma-mapping.h +++ b/include/asm-m68k/dma-mapping.h @@ -26,7 +26,7 @@ static inline int dma_is_consistent(dma_addr_t dma_addr) } extern void *dma_alloc_coherent(struct device *, size_t, - dma_addr_t *, int); + dma_addr_t *, gfp_t); extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t); -- GitLab From a666ecfbf512dbd63a60f65d2ad6733a9a1b12ee Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Fri, 6 Oct 2006 00:43:58 -0700 Subject: [PATCH 0714/1619] [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(-) diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index 6d45ee5472a..19637626224 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 495ad99c763..9ea7f1023e5 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 285756010c5..5ed0ef34084 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 46ec72fa2c8..600e3d387ff 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() -- GitLab From 1662d32cea96a8711bd61094ff090979478f0fd4 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 6 Oct 2006 00:43:59 -0700 Subject: [PATCH 0715/1619] [PATCH] MAINTAINERS: take over scx200-* and pc8736* drivers Add MAINTAINERS entries for new scx200_hrt and pc8736x_gpio drivers, and take over maintenance of scx200_gpio, authored by Christer Weinigel (which I've hacked at), who no longer has the hardware. Also take over hwmon/pc87360, authored by Jean Delvare, who's dropped maintenance to dedicate more time to hwmon subsystem. Signed-off-by: Jim Cromie Cc: Jean Delvare Cc: Christer Weinigel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 84a018ee455..50fb3ae5f31 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2261,6 +2261,17 @@ T: git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git T: cvs cvs.parisc-linux.org:/var/cvs/linux-2.6 S: Maintained +PC87360 HARDWARE MONITORING DRIVER +P: Jim Cromie +M: jim.cromie@gmail.com +L: lm-sensors@lm-sensors.org +S: Maintained + +PC8736x GPIO DRIVER +P: Jim Cromie +M: jim.cromie@gmail.com +S: Maintained + PCI ERROR RECOVERY P: Linas Vepstas M: linas@austin.ibm.com @@ -2592,10 +2603,19 @@ L: lksctp-developers@lists.sourceforge.net S: Supported SCx200 CPU SUPPORT -P: Christer Weinigel -M: christer@weinigel.se -W: http://www.weinigel.se -S: Supported +P: Jim Cromie +M: jim.cromie@gmail.com +S: Odd Fixes + +SCx200 GPIO DRIVER +P: Jim Cromie +M: jim.cromie@gmail.com +S: Maintained + +SCx200 HRT CLOCKSOURCE DRIVER +P: Jim Cromie +M: jim.cromie@gmail.com +S: Maintained SECURITY CONTACT P: Security Officers -- GitLab From 3260259f0084e51ce21503b130473b78871e7077 Mon Sep 17 00:00:00 2001 From: Henne Date: Fri, 6 Oct 2006 00:44:01 -0700 Subject: [PATCH 0716/1619] [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(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 331f4502e92..6735c1cf334 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) { -- GitLab From 45e02b5b52e43aa7a674f64ca3470b9ee51fc9fd Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 6 Oct 2006 00:44:02 -0700 Subject: [PATCH 0717/1619] [PATCH] swarm: Actually initialize the IDE driver This is required for the SWARM GenBus IDE interface to be recognized. Signed-off-by: Maciej W. Rozycki Cc: Ralf Baechle Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/mips/swarm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 66f6064f464..09c9e7936b0 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c @@ -4,6 +4,7 @@ * Author: Manish Lachwani, mlachwani@mvista.com * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved. * Author: Maciej W. Rozycki + * Copyright (c) 2006 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -127,6 +128,7 @@ static int __devinit swarm_ide_probe(struct device *dev) memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->irq = hwif->hw.irq; + probe_hwif_init(hwif); dev_set_drvdata(dev, hwif); return 0; -- GitLab From ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 6 Oct 2006 00:44:03 -0700 Subject: [PATCH 0718/1619] [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(-) diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index c1293f1bda8..f9027c8db79 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 81c3f77f652..08dec8d9e70 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 */ -- GitLab From 5842730de179405d80649231faa0b3f254477434 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 6 Oct 2006 00:44:04 -0700 Subject: [PATCH 0719/1619] [PATCH] md: fix bug where new drives added to an md array sometimes don't sync properly This fixes a bug introduced in 2.6.18. If a drive is added to a raid1 using older tools (mdadm-1.x or raidtools) then it will be included in the array without any resync happening. It has been submitted for 2.6.18.1. Signed-off-by: Neil Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index cb8281605be..57fa64f93e5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3849,6 +3849,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) } clear_bit(In_sync, &rdev->flags); rdev->desc_nr = -1; + rdev->saved_raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); if (err) goto abort_export; -- GitLab From c6b0a9f87b82f25fa35206ec04b5160372eabab4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 6 Oct 2006 00:44:05 -0700 Subject: [PATCH 0720/1619] [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(-) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 6fa6340a5fb..013b38996e6 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 d6288e89fd9..9c9a8ad9247 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 c2c8bb20d07..2807fa0eab4 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 b39e7e2b648..61e307cca13 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 */ -- GitLab From 96e1a87392293cf895ea99ab70758453897c7bbf Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 6 Oct 2006 00:44:06 -0700 Subject: [PATCH 0721/1619] [PATCH] um: irq changes break build Fixup broken UML build due to 7d12e780e003f93433d49ce78cfedf4b4c52adc5 "IRQ: Maintain regs pointer globally rather than passing to IRQ handlers". Cc: David Howells Cc: Jeff Dike Cc: Paolo "Blaisorblade" Giarrusso Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/irq.c | 2 +- include/asm-um/irq_regs.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 include/asm-um/irq_regs.h diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index eee97bb81ba..7c41dabe7a2 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -356,7 +356,7 @@ void forward_interrupts(int pid) unsigned int do_IRQ(int irq, union uml_pt_regs *regs) { irq_enter(); - __do_IRQ(irq, (struct pt_regs *)regs); + __do_IRQ(irq); irq_exit(); return 1; } diff --git a/include/asm-um/irq_regs.h b/include/asm-um/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-um/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 8c1addbc752660e95bbf2128d66b8e5bb38d5fc7 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 6 Oct 2006 10:09:41 -0700 Subject: [PATCH 0722/1619] [IA64] Fix breakage from irq change A few missed spots in ia64-land from this gigantic commit: 7d12e780e003f93433d49ce78cfedf4b4c52adc5 Signed-off-by: Tony Luck --- arch/ia64/kernel/irq.c | 5 ++++- arch/ia64/kernel/irq_ia64.c | 7 +++++-- arch/ia64/sn/kernel/sn2/timer_interrupt.c | 2 +- drivers/serial/sn_console.c | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 7852382de2f..f07c0864b0b 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -194,8 +194,11 @@ void fixup_irqs(void) */ for (irq=0; irq < NR_IRQS; irq++) { if (vectors_in_migration[irq]) { + struct pt_regs *old_regs = set_irq_regs(NULL); + vectors_in_migration[irq]=0; - __do_IRQ(irq, NULL); + __do_IRQ(irq); + set_irq_regs(old_regs); } } diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 7fd3ef9e064..68339dd0c9e 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -226,6 +226,8 @@ void ia64_process_pending_intr(void) */ while (vector != IA64_SPURIOUS_INT_VECTOR) { if (!IS_RESCHEDULE(vector)) { + struct pt_regs *old_regs = set_irq_regs(NULL); + ia64_setreg(_IA64_REG_CR_TPR, vector); ia64_srlz_d(); @@ -236,7 +238,8 @@ void ia64_process_pending_intr(void) * Probably could shared code. */ vectors_in_migration[local_vector_to_irq(vector)]=0; - __do_IRQ(local_vector_to_irq(vector), NULL); + __do_IRQ(local_vector_to_irq(vector)); + set_irq_regs(old_regs); /* * Disable interrupts and send EOI @@ -253,7 +256,7 @@ void ia64_process_pending_intr(void) #ifdef CONFIG_SMP -extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t handle_IPI (int irq, void *dev_id); static struct irqaction ipi_irqaction = { .handler = handle_IPI, diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c index fa7f6994591..103d6ea8e94 100644 --- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c +++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c @@ -36,7 +36,7 @@ extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); #define SN_LB_INT_WAR_INTERVAL 100 -void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void sn_timer_interrupt(int irq, void *dev_id) { /* LED blinking */ if (!pda->hb_count--) { diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 709f93a6c18..956b2cf08e1 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -674,7 +674,7 @@ static void sn_sal_timer_poll(unsigned long data) if (!port->sc_port.irq) { spin_lock_irqsave(&port->sc_port.lock, flags); if (sn_process_input) - sn_receive_chars(port, NULL, flags); + sn_receive_chars(port, flags); sn_transmit_chars(port, TRANSMIT_RAW); spin_unlock_irqrestore(&port->sc_port.lock, flags); mod_timer(&port->sc_timer, -- GitLab From 86d91bab4806191a8126502d80d729c2a4765ebe Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 6 Oct 2006 13:32:44 -0400 Subject: [PATCH 0723/1619] arch/i386/kernel/time: don't shadow 'irq' function arg Signed-off-by: Jeff Garzik --- arch/i386/kernel/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 3f221f5eb47..78af572fd17 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -201,8 +201,8 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) high bit of the PPI port B (0x61). Note that some PS/2s, notably the 55SX, work fine if this is removed. */ - irq = inb_p( 0x61 ); /* read the current state */ - outb_p( irq|0x80, 0x61 ); /* reset the IRQ */ + u8 irq_v = inb_p( 0x61 ); /* read the current state */ + outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */ } write_sequnlock(&xtime_lock); -- GitLab From 0cd61b68c340a4f901a06e8bb5e0dea4353161c0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 6 Oct 2006 10:53:39 -0700 Subject: [PATCH 0724/1619] Initial blind fixup for arm for irq changes Untested, but this should fix up the bulk of the totally mechanical issues, and should make the actual detail fixing easier. Signed-off-by: Linus Torvalds --- arch/arm/common/locomo.c | 25 ++++++------- arch/arm/common/sa1111.c | 8 ++--- arch/arm/common/sharpsl_pm.c | 6 ++-- arch/arm/common/time-acorn.c | 4 +-- arch/arm/kernel/ecard.c | 8 ++--- arch/arm/kernel/irq.c | 3 +- arch/arm/kernel/time.c | 3 +- arch/arm/mach-aaec2000/core.c | 4 +-- arch/arm/mach-at91rm9200/at91rm9200_time.c | 4 +-- arch/arm/mach-at91rm9200/gpio.c | 4 +-- arch/arm/mach-clps711x/time.c | 4 +-- arch/arm/mach-clps7500/core.c | 4 +-- arch/arm/mach-ebsa110/core.c | 4 +-- arch/arm/mach-ep93xx/core.c | 10 +++--- arch/arm/mach-footbridge/dc21285-timer.c | 4 +-- arch/arm/mach-footbridge/dc21285.c | 12 +++---- arch/arm/mach-footbridge/isa-irq.c | 6 ++-- arch/arm/mach-footbridge/isa-timer.c | 4 +-- arch/arm/mach-h720x/common.c | 29 +++++++-------- arch/arm/mach-h720x/cpu-h7201.c | 4 +-- arch/arm/mach-h720x/cpu-h7202.c | 11 +++--- arch/arm/mach-imx/dma.c | 12 +++---- arch/arm/mach-imx/irq.c | 24 ++++++------- arch/arm/mach-imx/time.c | 4 +-- arch/arm/mach-integrator/core.c | 6 ++-- arch/arm/mach-integrator/integrator_cp.c | 6 ++-- arch/arm/mach-integrator/pci_v3.c | 3 +- arch/arm/mach-integrator/time.c | 3 +- arch/arm/mach-ixp2000/core.c | 12 +++---- arch/arm/mach-ixp2000/ixdp2x00.c | 4 +-- arch/arm/mach-ixp2000/ixdp2x01.c | 4 +-- arch/arm/mach-ixp23xx/core.c | 8 ++--- arch/arm/mach-ixp23xx/ixdp2351.c | 8 ++--- arch/arm/mach-ixp4xx/common.c | 4 +-- arch/arm/mach-ixp4xx/nas100d-power.c | 2 +- arch/arm/mach-ixp4xx/nslu2-power.c | 4 +-- arch/arm/mach-lh7a40x/arch-kev7a400.c | 5 ++- arch/arm/mach-lh7a40x/arch-lpd7a40x.c | 3 +- arch/arm/mach-lh7a40x/irq-kev7a400.c | 5 ++- arch/arm/mach-lh7a40x/irq-lpd7a40x.c | 3 +- arch/arm/mach-lh7a40x/time.c | 4 +-- arch/arm/mach-netx/generic.c | 5 ++- arch/arm/mach-netx/time.c | 4 +-- arch/arm/mach-omap1/board-osk.c | 2 +- arch/arm/mach-omap1/fpga.c | 5 ++- arch/arm/mach-omap1/pm.c | 3 +- arch/arm/mach-omap1/serial.c | 3 +- arch/arm/mach-omap1/time.c | 8 ++--- arch/arm/mach-omap2/board-apollon.c | 2 +- arch/arm/mach-omap2/timer-gp.c | 5 ++- arch/arm/mach-pnx4008/dma.c | 10 +++--- arch/arm/mach-pnx4008/time.c | 5 ++- arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/dma.c | 8 ++--- arch/arm/mach-pxa/idp.c | 2 +- arch/arm/mach-pxa/irq.c | 11 +++--- arch/arm/mach-pxa/lpd270.c | 5 ++- arch/arm/mach-pxa/lubbock.c | 13 ++++--- arch/arm/mach-pxa/mainstone.c | 7 ++-- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/spitz.c | 2 +- arch/arm/mach-pxa/ssp.c | 2 +- arch/arm/mach-pxa/time.c | 8 ++--- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-pxa/trizeps4.c | 2 +- arch/arm/mach-realview/core.c | 6 ++-- arch/arm/mach-rpc/dma.c | 2 +- arch/arm/mach-s3c2410/bast-irq.c | 5 ++- arch/arm/mach-s3c2410/dma.c | 2 +- arch/arm/mach-s3c2410/irq.c | 41 +++++++++------------- arch/arm/mach-s3c2410/mach-amlm5900.c | 2 +- arch/arm/mach-s3c2410/s3c2440-irq.c | 7 ++-- arch/arm/mach-s3c2410/s3c244x-irq.c | 7 ++-- arch/arm/mach-s3c2410/time.c | 4 +-- arch/arm/mach-s3c2410/usb-simtec.c | 2 +- arch/arm/mach-sa1100/dma.c | 2 +- arch/arm/mach-sa1100/h3600.c | 6 ++-- arch/arm/mach-sa1100/irq.c | 5 ++- arch/arm/mach-sa1100/neponset.c | 8 ++--- arch/arm/mach-sa1100/ssp.c | 2 +- arch/arm/mach-sa1100/time.c | 8 ++--- arch/arm/mach-shark/core.c | 4 +-- arch/arm/mach-shark/irq.c | 2 +- arch/arm/mach-versatile/core.c | 10 +++--- arch/arm/oprofile/op_model_xscale.c | 4 +-- arch/arm/plat-iop/time.c | 4 +-- arch/arm/plat-omap/dma.c | 9 ++--- arch/arm/plat-omap/gpio.c | 5 ++- arch/arm/plat-omap/mcbsp.c | 4 +-- arch/arm/plat-omap/timer32k.c | 15 ++++---- include/asm-arm/arch-clps711x/time.h | 3 +- include/asm-arm/arch-imx/imx-dma.h | 8 ++--- include/asm-arm/arch-l7200/time.h | 3 +- include/asm-arm/arch-pnx4008/dma.h | 2 +- include/asm-arm/arch-pxa/dma.h | 2 +- include/asm-arm/arch-pxa/mmc.h | 2 +- include/asm-arm/hardware/sharpsl_pm.h | 6 ++-- include/asm-arm/irq_regs.h | 1 + include/asm-arm/mach/irq.h | 9 +++-- include/asm-arm/mach/time.h | 4 +-- 100 files changed, 281 insertions(+), 328 deletions(-) create mode 100644 include/asm-arm/irq_regs.h diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 181ef1ead5b..80a72c75214 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -163,8 +163,7 @@ static struct locomo_dev_info locomo_devices[] = { #define LOCOMO_IRQ_LT_START (IRQ_LOCOMO_LT) #define LOCOMO_IRQ_SPI_START (IRQ_LOCOMO_SPI_RFR) -static void locomo_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void locomo_handler(unsigned int irq, struct irqdesc *desc) { int req, i; struct irqdesc *d; @@ -182,7 +181,7 @@ static void locomo_handler(unsigned int irq, struct irqdesc *desc, d = irq_desc + irq; for (i = 0; i <= 3; i++, d++, irq++) { if (req & (0x0100 << i)) { - desc_handle_irq(irq, d, regs); + desc_handle_irq(irq, d); } } @@ -218,15 +217,14 @@ static struct irq_chip locomo_chip = { .unmask = locomo_unmask_irq, }; -static void locomo_key_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void locomo_key_handler(unsigned int irq, struct irqdesc *desc) { struct irqdesc *d; void __iomem *mapbase = get_irq_chipdata(irq); if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) { d = irq_desc + LOCOMO_IRQ_KEY_START; - desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs); + desc_handle_irq(LOCOMO_IRQ_KEY_START, d); } } @@ -264,8 +262,7 @@ static struct irq_chip locomo_key_chip = { .unmask = locomo_key_unmask_irq, }; -static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc) { int req, i; struct irqdesc *d; @@ -280,7 +277,7 @@ static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc, d = irq_desc + LOCOMO_IRQ_GPIO_START; for (i = 0; i <= 15; i++, irq++, d++) { if (req & (0x0001 << i)) { - desc_handle_irq(irq, d, regs); + desc_handle_irq(irq, d); } } } @@ -328,15 +325,14 @@ static struct irq_chip locomo_gpio_chip = { .unmask = locomo_gpio_unmask_irq, }; -static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc) { struct irqdesc *d; void __iomem *mapbase = get_irq_chipdata(irq); if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) { d = irq_desc + LOCOMO_IRQ_LT_START; - desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs); + desc_handle_irq(LOCOMO_IRQ_LT_START, d); } } @@ -374,8 +370,7 @@ static struct irq_chip locomo_lt_chip = { .unmask = locomo_lt_unmask_irq, }; -static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc) { int req, i; struct irqdesc *d; @@ -388,7 +383,7 @@ static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc, for (i = 0; i <= 3; i++, irq++, d++) { if (req & (0x0001 << i)) { - desc_handle_irq(irq, d, regs); + desc_handle_irq(irq, d); } } } diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 30046ad41ce..d5f72010a6f 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -147,7 +147,7 @@ void __init sa1111_adjust_zones(int node, unsigned long *size, unsigned long *ho * will call us again if there are more interrupts to process. */ static void -sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +sa1111_irq_handler(unsigned int irq, struct irqdesc *desc) { unsigned int stat0, stat1, i; void __iomem *base = get_irq_data(irq); @@ -162,17 +162,17 @@ sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) sa1111_writel(stat1, base + SA1111_INTSTATCLR1); if (stat0 == 0 && stat1 == 0) { - do_bad_IRQ(irq, desc, regs); + do_bad_IRQ(irq, desc); return; } for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) if (stat0 & 1) - handle_edge_irq(i, irq_desc + i, regs); + handle_edge_irq(i, irq_desc + i); for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) if (stat1 & 1) - handle_edge_irq(i, irq_desc + i, regs); + handle_edge_irq(i, irq_desc + i); /* For level-based interrupts */ desc->chip->unmask(irq); diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index f412dedda68..605dedf9679 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -258,7 +258,7 @@ static void sharpsl_ac_timer(unsigned long data) } -irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp) +irqreturn_t sharpsl_ac_isr(int irq, void *dev_id) { /* Delay the event slightly to debounce */ /* Must be a smaller delay than the chrg_full_isr below */ @@ -293,7 +293,7 @@ static void sharpsl_chrg_full_timer(unsigned long data) /* Charging Finished Interrupt (Not present on Corgi) */ /* Can trigger at the same time as an AC staus change so delay until after that has been processed */ -irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp) +irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id) { if (sharpsl_pm.flags & SHARPSL_SUSPENDED) return IRQ_HANDLED; @@ -304,7 +304,7 @@ irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp) return IRQ_HANDLED; } -irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp) +irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id) { int is_fatal = 0; diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c index 3f60dd9aca8..34038eccbba 100644 --- a/arch/arm/common/time-acorn.c +++ b/arch/arm/common/time-acorn.c @@ -67,10 +67,10 @@ void __init ioctime_init(void) } static irqreturn_t -ioc_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +ioc_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 3e14b1348c0..b27513a0f11 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -567,7 +567,7 @@ static void ecard_check_lockup(struct irqdesc *desc) } static void -ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +ecard_irq_handler(unsigned int irq, struct irqdesc *desc) { ecard_t *ec; int called = 0; @@ -586,7 +586,7 @@ ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) if (pending) { struct irqdesc *d = irq_desc + ec->irq; - desc_handle_irq(ec->irq, d, regs); + desc_handle_irq(ec->irq, d); called ++; } } @@ -609,7 +609,7 @@ static unsigned char first_set[] = }; static void -ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc) { const unsigned int statusmask = 15; unsigned int status; @@ -633,7 +633,7 @@ ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg * Serial cards should go in 0/1, ethernet/scsi in 2/3 * otherwise you will lose serial data at high speeds! */ - desc_handle_irq(ec->irq, d, regs); + desc_handle_irq(ec->irq, d); } else { printk(KERN_WARNING "card%d: interrupt from unclaimed " "card???\n", slot); diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 2e1bf830fe1..e999b11de2c 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -122,7 +122,8 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) irq_enter(); - desc_handle_irq(irq, desc, regs); + set_irq_regs(regs); + desc_handle_irq(irq, desc); /* AT91 specific workaround */ irq_finish(irq); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index b030320b17c..b094e3e8198 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -324,8 +324,9 @@ EXPORT_SYMBOL(restore_time_delta); /* * Kernel system timer support. */ -void timer_tick(struct pt_regs *regs) +void timer_tick(void) { + struct pt_regs *regs = get_irq_regs(); profile_tick(CPU_PROFILING, regs); do_leds(); do_set_rtc(); diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index baa997c857d..fe3d297d682 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -127,12 +127,12 @@ static unsigned long aaec2000_gettimeoffset(void) /* We enter here with IRQs enabled */ static irqreturn_t -aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +aaec2000_timer_interrupt(int irq, void *dev_id) { /* TODO: Check timer accuracy */ write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); TIMER1_CLEAR = 1; write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-at91rm9200/at91rm9200_time.c b/arch/arm/mach-at91rm9200/at91rm9200_time.c index a92a8622c78..07c9cea8961 100644 --- a/arch/arm/mach-at91rm9200/at91rm9200_time.c +++ b/arch/arm/mach-at91rm9200/at91rm9200_time.c @@ -65,13 +65,13 @@ static unsigned long at91rm9200_gettimeoffset(void) /* * IRQ handler for the timer. */ -static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id) { if (at91_sys_read(AT91_ST_SR) & AT91_ST_PITS) { /* This is a shared interrupt */ write_seqlock(&xtime_lock); while (((read_CRTR() - last_crtr) & AT91_ST_ALMV) >= LATCH) { - timer_tick(regs); + timer_tick(); last_crtr = (last_crtr + LATCH) & AT91_ST_ALMV; } diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c index 58c9bf5e952..7467d644f0a 100644 --- a/arch/arm/mach-at91rm9200/gpio.c +++ b/arch/arm/mach-at91rm9200/gpio.c @@ -332,7 +332,7 @@ static struct irq_chip gpio_irqchip = { .set_wake = gpio_irq_set_wake, }; -static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs) +static void gpio_irq_handler(unsigned irq, struct irqdesc *desc) { unsigned pin; struct irqdesc *gpio; @@ -363,7 +363,7 @@ static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs gpio_irq_mask(pin); } else - desc_handle_irq(pin, gpio, regs); + desc_handle_irq(pin, gpio); } pin++; gpio++; diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c index a071eac4a30..428493dd468 100644 --- a/arch/arm/mach-clps711x/time.c +++ b/arch/arm/mach-clps711x/time.c @@ -48,10 +48,10 @@ static unsigned long clps711x_gettimeoffset(void) * IRQ handler for the timer */ static irqreturn_t -p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +p720t_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c index 92eaebdd560..fb10cf25258 100644 --- a/arch/arm/mach-clps7500/core.c +++ b/arch/arm/mach-clps7500/core.c @@ -292,11 +292,11 @@ extern void ioctime_init(void); extern unsigned long ioc_timer_gettimeoffset(void); static irqreturn_t -clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +clps7500_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); /* Why not using do_leds interface?? */ { diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 70dd12ef3c4..90103ab373a 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -174,7 +174,7 @@ static unsigned long ebsa110_gettimeoffset(void) } static irqreturn_t -ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +ebsa110_timer_interrupt(int irq, void *dev_id) { u32 count; @@ -190,7 +190,7 @@ ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) __raw_writeb(count & 0xff, PIT_T1); __raw_writeb(count >> 8, PIT_T1); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index a87a784b920..e3fd1ab6adc 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -97,7 +97,7 @@ static unsigned int last_jiffy_time; #define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) -static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static int ep93xx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -106,7 +106,7 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time) >= TIMER4_TICKS_PER_JIFFY) { last_jiffy_time += TIMER4_TICKS_PER_JIFFY; - timer_tick(regs); + timer_tick(); } write_sequnlock(&xtime_lock); @@ -245,7 +245,7 @@ EXPORT_SYMBOL(gpio_line_set); * EP93xx IRQ handling *************************************************************************/ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, - struct irqdesc *desc, struct pt_regs *regs) + struct irqdesc *desc) { unsigned char status; int i; @@ -254,7 +254,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, for (i = 0; i < 8; i++) { if (status & (1 << i)) { desc = irq_desc + IRQ_EP93XX_GPIO(0) + i; - desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc, regs); + desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc); } } @@ -262,7 +262,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, for (i = 0; i < 8; i++) { if (status & (1 << i)) { desc = irq_desc + IRQ_EP93XX_GPIO(8) + i; - desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc, regs); + desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc); } } } diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c index 2af610811ca..fa6be870c6c 100644 --- a/arch/arm/mach-footbridge/dc21285-timer.c +++ b/arch/arm/mach-footbridge/dc21285-timer.c @@ -28,13 +28,13 @@ static unsigned long timer1_gettimeoffset (void) } static irqreturn_t -timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +timer1_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); *CSR_TIMER1_CLR = 0; - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c index a1ae49df5c3..fa5d4976f51 100644 --- a/arch/arm/mach-footbridge/dc21285.c +++ b/arch/arm/mach-footbridge/dc21285.c @@ -154,7 +154,7 @@ static void dc21285_enable_error(unsigned long __data) /* * Warn on PCI errors. */ -static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc21285_abort_irq(int irq, void *dev_id) { unsigned int cmd; unsigned int status; @@ -165,7 +165,7 @@ static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs if (status & PCI_STATUS_REC_MASTER_ABORT) { printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", - instruction_pointer(regs)); + instruction_pointer(get_irq_regs())); cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; } @@ -184,7 +184,7 @@ static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs return IRQ_HANDLED; } -static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc21285_serr_irq(int irq, void *dev_id) { struct timer_list *timer = dev_id; unsigned int cntl; @@ -206,7 +206,7 @@ static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc21285_discard_irq(int irq, void *dev_id) { printk(KERN_DEBUG "PCI: discard timer expired\n"); *CSR_SA110_CNTL &= 0xffffde07; @@ -214,7 +214,7 @@ static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *re return IRQ_HANDLED; } -static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id) { unsigned int cmd; @@ -228,7 +228,7 @@ static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *re return IRQ_HANDLED; } -static irqreturn_t dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc21285_parity_irq(int irq, void *dev_id) { struct timer_list *timer = dev_id; unsigned int cmd; diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c index 87448c2d6ba..888dedd501b 100644 --- a/arch/arm/mach-footbridge/isa-irq.c +++ b/arch/arm/mach-footbridge/isa-irq.c @@ -85,17 +85,17 @@ static struct irqchip isa_hi_chip = { }; static void -isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +isa_irq_handler(unsigned int irq, struct irqdesc *desc) { unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE; if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) { - do_bad_IRQ(isa_irq, desc, regs); + do_bad_IRQ(isa_irq, desc); return; } desc = irq_desc + isa_irq; - desc_handle_irq(isa_irq, desc, regs); + desc_handle_irq(isa_irq, desc); } static struct irqaction irq_cascade = { diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c index c4810a40c8e..d884a3954fb 100644 --- a/arch/arm/mach-footbridge/isa-timer.c +++ b/arch/arm/mach-footbridge/isa-timer.c @@ -62,10 +62,10 @@ static unsigned long isa_gettimeoffset(void) } static irqreturn_t -isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +isa_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c index c096b456930..4719229a1a7 100644 --- a/arch/arm/mach-h720x/common.c +++ b/arch/arm/mach-h720x/common.c @@ -101,14 +101,14 @@ static void inline unmask_gpio_irq(u32 irq) static void h720x_gpio_handler(unsigned int mask, unsigned int irq, - struct irqdesc *desc, struct pt_regs *regs) + struct irqdesc *desc) { IRQDBG("%s irq: %d\n",__FUNCTION__,irq); desc = irq_desc + irq; while (mask) { if (mask & 1) { IRQDBG("handling irq %d\n", irq); - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } irq++; desc++; @@ -117,63 +117,58 @@ h720x_gpio_handler(unsigned int mask, unsigned int irq, } static void -h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT); irq = IRQ_CHAINED_GPIOA(0); IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); - h720x_gpio_handler(mask, irq, desc, regs); + h720x_gpio_handler(mask, irq, desc); } static void -h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT); irq = IRQ_CHAINED_GPIOB(0); IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); - h720x_gpio_handler(mask, irq, desc, regs); + h720x_gpio_handler(mask, irq, desc); } static void -h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT); irq = IRQ_CHAINED_GPIOC(0); IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); - h720x_gpio_handler(mask, irq, desc, regs); + h720x_gpio_handler(mask, irq, desc); } static void -h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT); irq = IRQ_CHAINED_GPIOD(0); IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); - h720x_gpio_handler(mask, irq, desc, regs); + h720x_gpio_handler(mask, irq, desc); } #ifdef CONFIG_CPU_H7202 static void -h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT); irq = IRQ_CHAINED_GPIOE(0); IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); - h720x_gpio_handler(mask, irq, desc, regs); + h720x_gpio_handler(mask, irq, desc); } #endif diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c index a9a8255a3a0..13f76bdb3d9 100644 --- a/arch/arm/mach-h720x/cpu-h7201.c +++ b/arch/arm/mach-h720x/cpu-h7201.c @@ -27,12 +27,12 @@ * Timer interrupt handler */ static irqreturn_t -h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +h7201_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); CPU_REG (TIMER_VIRT, TIMER_TOPSTAT); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c index da678d163fd..06fecaefd8d 100644 --- a/arch/arm/mach-h720x/cpu-h7202.c +++ b/arch/arm/mach-h720x/cpu-h7202.c @@ -106,8 +106,7 @@ static struct platform_device *devices[] __initdata = { * we have to handle all timer interrupts in one place. */ static void -h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; @@ -115,7 +114,7 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc, if ( mask & TSTAT_T0INT ) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); if( mask == TSTAT_T0INT ) return; @@ -126,7 +125,7 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc, desc = irq_desc + irq; while (mask) { if (mask & 1) - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); irq++; desc++; mask >>= 1; @@ -137,9 +136,9 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc, * Timer interrupt handler */ static irqreturn_t -h7202_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +h7202_timer_interrupt(int irq, void *dev_id) { - h7202_timerx_demux_handler(0, NULL, regs); + h7202_timerx_demux_handler(0, NULL); return IRQ_HANDLED; } diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c index 36578871ecc..6d50d85a618 100644 --- a/arch/arm/mach-imx/dma.c +++ b/arch/arm/mach-imx/dma.c @@ -279,8 +279,8 @@ imx_dma_setup_sg(imx_dmach_t dma_ch, */ int imx_dma_setup_handlers(imx_dmach_t dma_ch, - void (*irq_handler) (int, void *, struct pt_regs *), - void (*err_handler) (int, void *, struct pt_regs *, int), + void (*irq_handler) (int, void *), + void (*err_handler) (int, void *, int), void *data) { struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; @@ -461,7 +461,7 @@ imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, return -ENODEV; } -static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_err_handler(int irq, void *dev_id) { int i, disr = DISR; struct imx_dma_channel *channel; @@ -500,7 +500,7 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) /*imx_dma_channels[i].sg = NULL;*/ if (channel->name && channel->err_handler) { - channel->err_handler(i, channel->data, regs, errcode); + channel->err_handler(i, channel->data, errcode); continue; } @@ -517,7 +517,7 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id) { int i, disr = DISR; @@ -536,7 +536,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) } else { if (channel->irq_handler) channel->irq_handler(i, - channel->data, regs); + channel->data); } } else { /* diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c index 2688bd82c2a..368b13b058a 100644 --- a/arch/arm/mach-imx/irq.c +++ b/arch/arm/mach-imx/irq.c @@ -146,13 +146,13 @@ imx_gpio_unmask_irq(unsigned int irq) static void imx_gpio_handler(unsigned int mask, unsigned int irq, - struct irqdesc *desc, struct pt_regs *regs) + struct irqdesc *desc) { desc = irq_desc + irq; while (mask) { if (mask & 1) { DEBUG_IRQ("handling irq %d\n", irq); - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } irq++; desc++; @@ -161,47 +161,43 @@ imx_gpio_handler(unsigned int mask, unsigned int irq, } static void -imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = ISR(0); irq = IRQ_GPIOA(0); - imx_gpio_handler(mask, irq, desc, regs); + imx_gpio_handler(mask, irq, desc); } static void -imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = ISR(1); irq = IRQ_GPIOB(0); - imx_gpio_handler(mask, irq, desc, regs); + imx_gpio_handler(mask, irq, desc); } static void -imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = ISR(2); irq = IRQ_GPIOC(0); - imx_gpio_handler(mask, irq, desc, regs); + imx_gpio_handler(mask, irq, desc); } static void -imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int mask, irq; mask = ISR(3); irq = IRQ_GPIOD(0); - imx_gpio_handler(mask, irq, desc, regs); + imx_gpio_handler(mask, irq, desc); } static struct irq_chip imx_internal_chip = { diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 6ed7523c65b..8ae4a2c5066 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -56,7 +56,7 @@ static unsigned long imx_gettimeoffset(void) * IRQ handler for the timer */ static irqreturn_t -imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +imx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -64,7 +64,7 @@ imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (IMX_TSTAT(TIMER_BASE)) IMX_TSTAT(TIMER_BASE) = 0; - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 42021fdfa0c..8d880cb9ba3 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -248,7 +248,7 @@ unsigned long integrator_gettimeoffset(void) * IRQ handler for the timer */ static irqreturn_t -integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +integrator_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -262,7 +262,7 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * primary CPU */ if (hard_smp_processor_id() == 0) { - timer_tick(regs); + timer_tick(); #ifdef CONFIG_SMP smp_send_timer(); #endif @@ -272,7 +272,7 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* * this is the ARM equivalent of the APIC timer interrupt */ - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif /* CONFIG_SMP */ write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 678b6ba2b46..771b65bffe6 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -202,12 +202,12 @@ static struct irq_chip sic_chip = { }; static void -sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +sic_handle_irq(unsigned int irq, struct irqdesc *desc) { unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS); if (status == 0) { - do_bad_IRQ(irq, desc, regs); + do_bad_IRQ(irq, desc); return; } @@ -218,7 +218,7 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) irq += IRQ_SIC_START; desc = irq_desc + irq; - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } while (status); } diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index 4418f6d7572..fb8c6d97b22 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -440,9 +440,10 @@ v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) return 1; } -static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t v3_irq(int irq, void *devid) { #ifdef CONFIG_DEBUG_LL + struct pt_regs *regs = get_irq_regs(); unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; char buf[128]; diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index ee49cf790da..5278f589fce 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c @@ -96,8 +96,7 @@ static struct rtc_ops rtc_ops = { .set_alarm = integrator_rtc_set_alarm, }; -static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id) { writel(0, rtc_base + RTC_EOI); return IRQ_HANDLED; diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 7f91f689a04..22c98e9dad2 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -204,7 +204,7 @@ unsigned long ixp2000_gettimeoffset (void) return offset / ticks_per_usec; } -static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static int ixp2000_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -213,7 +213,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr) >= ticks_per_jiffy) { - timer_tick(regs); + timer_tick(); next_jiffy_time -= ticks_per_jiffy; } @@ -308,7 +308,7 @@ EXPORT_SYMBOL(gpio_line_config); /************************************************************************* * IRQ handling IXP2000 *************************************************************************/ -static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc) { int i; unsigned long status = *IXP2000_GPIO_INST; @@ -316,7 +316,7 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str for (i = 0; i <= 7; i++) { if (status & (1<= 0; i--) { if(status & (1 << i)) { desc = irq_desc + IRQ_IXP2000_DRAM0_MIN_ERR + i; - desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc, regs); + desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc); } } } diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 40eef8b3674..af48cb52dfc 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -106,7 +106,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq) ixp2000_release_slowport(&old_cfg); } -static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc) { volatile u32 ex_interrupt = 0; static struct slowport_cfg old_cfg; @@ -132,7 +132,7 @@ static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct struct irqdesc *cpld_desc; int cpld_irq = IXP2000_BOARD_IRQ(0) + i; cpld_desc = irq_desc + cpld_irq; - desc_handle_irq(cpld_irq, cpld_desc, regs); + desc_handle_irq(cpld_irq, cpld_desc); } } diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index 7f42366f60d..9ccae9e63f7 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c @@ -63,7 +63,7 @@ static void ixdp2x01_irq_unmask(unsigned int irq) static u32 valid_irq_mask; -static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc) { u32 ex_interrupt; int i; @@ -82,7 +82,7 @@ static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct struct irqdesc *cpld_desc; int cpld_irq = IXP2000_BOARD_IRQ(0) + i; cpld_desc = irq_desc + cpld_irq; - desc_handle_irq(cpld_irq, cpld_desc, regs); + desc_handle_irq(cpld_irq, cpld_desc); } } diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c index 566a07821c7..a704a182004 100644 --- a/arch/arm/mach-ixp23xx/core.c +++ b/arch/arm/mach-ixp23xx/core.c @@ -251,7 +251,7 @@ static void ixp23xx_pci_irq_unmask(unsigned int irq) /* * TODO: Should this just be done at ASM level? */ -static void pci_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void pci_handler(unsigned int irq, struct irqdesc *desc) { u32 pci_interrupt; unsigned int irqno; @@ -271,7 +271,7 @@ static void pci_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs * } int_desc = irq_desc + irqno; - desc_handle_irq(irqno, int_desc, regs); + desc_handle_irq(irqno, int_desc); desc->chip->unmask(irq); } @@ -348,12 +348,12 @@ ixp23xx_gettimeoffset(void) } static irqreturn_t -ixp23xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +ixp23xx_timer_interrupt(int irq, void *dev_id) { /* Clear Pending Interrupt by writing '1' to it */ *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND; while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) { - timer_tick(regs); + timer_tick(); next_jiffy_time += LATCH; } diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c index 37a32e6bcca..b6ab0e8bb5e 100644 --- a/arch/arm/mach-ixp23xx/ixdp2351.c +++ b/arch/arm/mach-ixp23xx/ixdp2351.c @@ -60,7 +60,7 @@ static void ixdp2351_inta_unmask(unsigned int irq) *IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(irq); } -static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc) { u16 ex_interrupt = *IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID; @@ -74,7 +74,7 @@ static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc, struct int cpld_irq = IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i); cpld_desc = irq_desc + cpld_irq; - desc_handle_irq(cpld_irq, cpld_desc, regs); + desc_handle_irq(cpld_irq, cpld_desc); } } @@ -97,7 +97,7 @@ static void ixdp2351_intb_unmask(unsigned int irq) *IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(irq); } -static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc) { u16 ex_interrupt = *IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID; @@ -111,7 +111,7 @@ static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc, struct int cpld_irq = IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i); cpld_desc = irq_desc + cpld_irq; - desc_handle_irq(cpld_irq, cpld_desc, regs); + desc_handle_irq(cpld_irq, cpld_desc); } } diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 35dd8b3824b..c7513f6eb50 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -256,7 +256,7 @@ static unsigned volatile last_jiffy_time; #define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) -static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -267,7 +267,7 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs * Catch up with the real idea of time */ while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) { - timer_tick(regs); + timer_tick(); last_jiffy_time += LATCH; } diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c index 81ffcae1f56..29aa98d3a7f 100644 --- a/arch/arm/mach-ixp4xx/nas100d-power.c +++ b/arch/arm/mach-ixp4xx/nas100d-power.c @@ -24,7 +24,7 @@ #include -static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) { /* Signal init to do the ctrlaltdel action, this will bypass init if * it hasn't started and do a kernel_restart. diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c index a29b3b2b61b..acd71e9c38a 100644 --- a/arch/arm/mach-ixp4xx/nslu2-power.c +++ b/arch/arm/mach-ixp4xx/nslu2-power.c @@ -25,7 +25,7 @@ #include -static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t nslu2_power_handler(int irq, void *dev_id) { /* Signal init to do the ctrlaltdel action, this will bypass init if * it hasn't started and do a kernel_restart. @@ -35,7 +35,7 @@ static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *re return IRQ_HANDLED; } -static irqreturn_t nslu2_reset_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t nslu2_reset_handler(int irq, void *dev_id) { /* This is the paper-clip reset, it shuts the machine down directly. */ diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c index 4f2ab48800a..15fbcc911fe 100644 --- a/arch/arm/mach-lh7a40x/arch-kev7a400.c +++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c @@ -71,14 +71,13 @@ static struct irq_chip kev7a400_cpld_chip = { }; -static void kev7a400_cpld_handler (unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void kev7a400_cpld_handler (unsigned int irq, struct irqdesc *desc) { u32 mask = CPLD_LATCHED_INTS; irq = IRQ_KEV7A400_CPLD; for (; mask; mask >>= 1, ++irq) { if (mask & 1) - desc[irq].handle (irq, desc, regs); + desc[irq].handle (irq, desc); } } diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index a21b12f06c6..8441e0a156c 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -207,8 +207,7 @@ static struct irq_chip lpd7a40x_cpld_chip = { .unmask = lh7a40x_unmask_cpld_irq, }; -static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc) { unsigned int mask = CPLD_INTERRUPTS; diff --git a/arch/arm/mach-lh7a40x/irq-kev7a400.c b/arch/arm/mach-lh7a40x/irq-kev7a400.c index f9b3fe9174a..646071334b8 100644 --- a/arch/arm/mach-lh7a40x/irq-kev7a400.c +++ b/arch/arm/mach-lh7a40x/irq-kev7a400.c @@ -51,14 +51,13 @@ irq_chip lh7a400_cpld_chip = { }; static void -lh7a400_cpld_handler (unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +lh7a400_cpld_handler (unsigned int irq, struct irqdesc *desc) { u32 mask = CPLD_LATCHED_INTS; irq = IRQ_KEV_7A400_CPLD; for (; mask; mask >>= 1, ++irq) { if (mask & 1) - desc[irq].handle (irq, desc, regs); + desc[irq].handle (irq, desc); } } diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c index d6055dde646..b20376804bb 100644 --- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c @@ -57,8 +57,7 @@ static struct irq_chip lh7a40x_cpld_chip = { .unmask = lh7a40x_unmask_cpld_irq, }; -static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc) { unsigned int mask = CPLD_INTERRUPTS; diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c index ad5652e0150..bef3c4b68d3 100644 --- a/arch/arm/mach-lh7a40x/time.c +++ b/arch/arm/mach-lh7a40x/time.c @@ -39,12 +39,12 @@ #endif static irqreturn_t -lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +lh7a40x_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); TIMER_EOI = 0; - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c index af0b13534cf..edbbbdc3b06 100644 --- a/arch/arm/mach-netx/generic.c +++ b/arch/arm/mach-netx/generic.c @@ -69,8 +69,7 @@ static struct platform_device *devices[] __initdata = { #endif static void -netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc, - struct pt_regs *regs) +netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc) { unsigned int irq = NETX_IRQ_HIF_CHAINED(0); unsigned int stat; @@ -83,7 +82,7 @@ netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc, while (stat) { if (stat & 1) { DEBUG_IRQ("handling irq %d\n", irq); - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } irq++; desc++; diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c index 6d72c81b7d9..0993336c0b5 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c @@ -38,11 +38,11 @@ static unsigned long netx_gettimeoffset(void) * IRQ handler for the timer */ static irqreturn_t -netx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +netx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); /* acknowledge interrupt */ diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 6b05647a6c0..3a622801d7b 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -327,7 +327,7 @@ static struct spi_board_info __initdata mistral_boardinfo[] = { { #ifdef CONFIG_PM static irqreturn_t -osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs) +osk_mistral_wake_interrupt(int irq, void *ignored) { return IRQ_HANDLED; } diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c index efe9bfc6e55..8e40208b10b 100644 --- a/arch/arm/mach-omap1/fpga.c +++ b/arch/arm/mach-omap1/fpga.c @@ -84,8 +84,7 @@ static void fpga_mask_ack_irq(unsigned int irq) fpga_ack_irq(irq); } -void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc) { struct irqdesc *d; u32 stat; @@ -101,7 +100,7 @@ void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc, fpga_irq++, stat >>= 1) { if (stat & 1) { d = irq_desc + fpga_irq; - desc_handle_irq(fpga_irq, d, regs); + desc_handle_irq(fpga_irq, d); } } } diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index cd76185bab7..4834758d340 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -682,8 +682,7 @@ static int omap_pm_finish(suspend_state_t state) } -static irqreturn_t omap_wakeup_interrupt(int irq, void * dev, - struct pt_regs * regs) +static irqreturn_t omap_wakeup_interrupt(int irq, void *dev) { return IRQ_HANDLED; } diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index c4b790217a5..4cc98a578e4 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -204,8 +204,7 @@ void __init omap_serial_init(void) #ifdef CONFIG_OMAP_SERIAL_WAKE -static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id) { /* Need to do something with serial port right after wake-up? */ return IRQ_HANDLED; diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 4d91b9f5108..1b7e4a506c2 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -160,8 +160,7 @@ static unsigned long omap_mpu_timer_gettimeoffset(void) * Latency during the interrupt is calculated using timer1. * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz). */ -static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id) { unsigned long now, latency; @@ -169,7 +168,7 @@ static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id, now = 0 - omap_mpu_timer_read(0); latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1); omap_mpu_timer_last = now - latency; - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; @@ -182,8 +181,7 @@ static struct irqaction omap_mpu_timer_irq = { }; static unsigned long omap_mpu_timer1_overflows; -static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) { omap_mpu_timer1_overflows++; return IRQ_HANDLED; diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index c37b0e6d124..03d6905ba49 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -203,7 +203,7 @@ static void __init apollon_led_init(void) omap_set_gpio_dataout(LED2_GPIO15, 0); } -static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs) +static irqreturn_t apollon_sw_interrupt(int irq, void *ignored) { static unsigned int led0, led1, led2; diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index fe5fd6d42de..973189cd976 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -37,13 +37,12 @@ static inline void omap2_gp_timer_start(unsigned long load_val) omap_dm_timer_start(gptimer); } -static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c index ec01574f88a..d6a279e4b52 100644 --- a/arch/arm/mach-pnx4008/dma.c +++ b/arch/arm/mach-pnx4008/dma.c @@ -32,7 +32,7 @@ static struct dma_channel { char *name; - void (*irq_handler) (int, int, void *, struct pt_regs *); + void (*irq_handler) (int, int, void *); void *data; struct pnx4008_dma_ll *ll; u32 ll_dma; @@ -150,8 +150,7 @@ static inline void pnx4008_dma_unlock(void) #define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS)) int pnx4008_request_channel(char *name, int ch, - void (*irq_handler) (int, int, void *, - struct pt_regs *), void *data) + void (*irq_handler) (int, int, void *), void *data) { int i, found = 0; @@ -1033,7 +1032,7 @@ int pnx4008_dma_ch_enabled(int ch) EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled); -static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id) { int i; unsigned long dint = __raw_readl(DMAC_INT_STAT); @@ -1053,8 +1052,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) cause |= DMA_ERR_INT; if (tcint & i_bit) cause |= DMA_TC_INT; - channel->irq_handler(i, cause, channel->data, - regs); + channel->irq_handler(i, cause, channel->data); } else { /* * IRQ for an unregistered DMA channel diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c index b986065cd0f..8621c206ac8 100644 --- a/arch/arm/mach-pnx4008/time.c +++ b/arch/arm/mach-pnx4008/time.c @@ -47,15 +47,14 @@ static unsigned long pnx4008_gettimeoffset(void) /*! * IRQ handler for the timer */ -static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id) { if (__raw_readl(HSTIM_INT) & MATCH0_INT) { write_seqlock(&xtime_lock); do { - timer_tick(regs); + timer_tick(); /* * this algorithm takes care of possible delay diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 337c01c4ac3..74f8378d7bb 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -212,7 +212,7 @@ static struct platform_device corgits_device = { */ static struct pxamci_platform_data corgi_mci_platform_data; -static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *, struct pt_regs *), void *data) +static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *), void *data) { int err; diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c index 7d8c85486c6..4440babe7b9 100644 --- a/arch/arm/mach-pxa/dma.c +++ b/arch/arm/mach-pxa/dma.c @@ -27,13 +27,13 @@ static struct dma_channel { char *name; - void (*irq_handler)(int, void *, struct pt_regs *); + void (*irq_handler)(int, void *); void *data; } dma_channels[PXA_DMA_CHANNELS]; int pxa_request_dma (char *name, pxa_dma_prio prio, - void (*irq_handler)(int, void *, struct pt_regs *), + void (*irq_handler)(int, void *), void *data) { unsigned long flags; @@ -87,7 +87,7 @@ void pxa_free_dma (int dma_ch) local_irq_restore(flags); } -static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id) { int i, dint = DINT; @@ -95,7 +95,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) if (dint & (1 << i)) { struct dma_channel *channel = &dma_channels[i]; if (channel->name && channel->irq_handler) { - channel->irq_handler(i, channel->data, regs); + channel->irq_handler(i, channel->data); } else { /* * IRQ for an unregistered DMA channel: diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 3e4b0ab71c6..a4cb875b748 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -125,7 +125,7 @@ static struct pxafb_mach_info sharp_lm8v31 = { .pxafb_lcd_power = &idp_lcd_power }; -static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data) +static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *), void *data) { /* setup GPIO for PXA25x MMC controller */ pxa_gpio_mode(GPIO6_MMCCLK_MD); diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 12141e2a50c..ab1a16025d5 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -143,8 +143,7 @@ static struct irq_chip pxa_low_gpio_chip = { * Demux handler for GPIO>=2 edge detect interrupts */ -static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc) { unsigned int mask; int loop; @@ -160,7 +159,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, mask >>= 2; do { if (mask & 1) - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); irq++; desc++; mask >>= 1; @@ -175,7 +174,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, desc = irq_desc + irq; do { if (mask & 1) - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); irq++; desc++; mask >>= 1; @@ -190,7 +189,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, desc = irq_desc + irq; do { if (mask & 1) - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); irq++; desc++; mask >>= 1; @@ -206,7 +205,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, desc = irq_desc + irq; do { if (mask & 1) - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); irq++; desc++; mask >>= 1; diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index eff2a91b256..5749f6b72e1 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -75,8 +75,7 @@ static struct irq_chip lpd270_irq_chip = { .unmask = lpd270_unmask_irq, }; -static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc) { unsigned long pending; @@ -86,7 +85,7 @@ static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc, if (likely(pending)) { irq = LPD270_IRQ(0) + __ffs(pending); desc = irq_desc + irq; - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); pending = __raw_readw(LPD270_INT_STATUS) & lpd270_irq_enabled; diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 157cf47cbe6..b1e77bd85a3 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -85,8 +85,7 @@ static struct irq_chip lubbock_irq_chip = { .unmask = lubbock_unmask_irq, }; -static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc) { unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; do { @@ -94,7 +93,7 @@ static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc, if (likely(pending)) { irq = LUBBOCK_IRQ(0) + __ffs(pending); desc = irq_desc + irq; - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; } while (pending); @@ -379,7 +378,7 @@ static struct pxafb_mach_info sharp_lm8v31 = { #define MMC_POLL_RATE msecs_to_jiffies(1000) static void lubbock_mmc_poll(unsigned long); -static irqreturn_t (*mmc_detect_int)(int, void *, struct pt_regs *); +static irqreturn_t (*mmc_detect_int)(int, void *); static struct timer_list mmc_timer = { .function = lubbock_mmc_poll, @@ -403,17 +402,17 @@ static void lubbock_mmc_poll(unsigned long data) } } -static irqreturn_t lubbock_detect_int(int irq, void *data, struct pt_regs *regs) +static irqreturn_t lubbock_detect_int(int irq, void *data) { /* IRQ is level triggered; disable, and poll for removal */ disable_irq(irq); mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE); - return mmc_detect_int(irq, data, regs); + return mmc_detect_int(irq, data); } static int lubbock_mci_init(struct device *dev, - irqreturn_t (*detect_int)(int, void *, struct pt_regs *), + irqreturn_t (*detect_int)(int, void *), void *data) { /* setup GPIO for PXA25x MMC controller */ diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 7ba0447d6fa..8c301978491 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -71,8 +71,7 @@ static struct irq_chip mainstone_irq_chip = { .unmask = mainstone_unmask_irq, }; -static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc) { unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; do { @@ -80,7 +79,7 @@ static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc, if (likely(pending)) { irq = MAINSTONE_IRQ(0) + __ffs(pending); desc = irq_desc + irq; - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } pending = MST_INTSETCLR & mainstone_irq_enabled; } while (pending); @@ -314,7 +313,7 @@ static struct pxafb_mach_info mainstone_pxafb_info = { .pxafb_backlight_power = mainstone_backlight_power, }; -static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data) +static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *), void *data) { int err; diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 5e8c098ca13..9052a971c8a 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -197,7 +197,7 @@ static struct platform_device poodle_ts_device = { */ static struct pxamci_platform_data poodle_mci_platform_data; -static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(int, void *, struct pt_regs *), void *data) +static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(int, void *), void *data) { int err; diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 401cdb850fb..911452dd0b4 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -291,7 +291,7 @@ static struct platform_device spitzts_device = { static struct pxamci_platform_data spitz_mci_platform_data; -static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *, struct pt_regs *), void *data) +static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *), void *data) { int err; diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c index 1fddfeaa630..6cc202755fb 100644 --- a/arch/arm/mach-pxa/ssp.c +++ b/arch/arm/mach-pxa/ssp.c @@ -65,7 +65,7 @@ static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { static DEFINE_MUTEX(mutex); static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; -static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ssp_interrupt(int irq, void *dev_id) { struct ssp_dev *dev = (struct ssp_dev*) dev_id; unsigned int status = SSSR_P(dev->port); diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 5dbd191c57c..3ac268fa419 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -75,7 +75,7 @@ static int match_posponed; #endif static irqreturn_t -pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +pxa_timer_interrupt(int irq, void *dev_id) { int next_match; @@ -105,7 +105,7 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * exactly one tick period which should be a pretty rare event. */ do { - timer_tick(regs); + timer_tick(); OSSR = OSSR_M0; /* Clear match on timer 0 */ next_match = (OSMR0 += LATCH); } while( (signed long)(next_match - OSCR) <= 8 ); @@ -157,13 +157,13 @@ static void pxa_dyn_tick_reprogram(unsigned long ticks) } static irqreturn_t -pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs) +pxa_dyn_tick_handler(int irq, void *dev_id) { if (match_posponed) { match_posponed = 0; OSMR0 = initial_match; if ( (signed long)(initial_match - OSCR) <= 8 ) - return pxa_timer_interrupt(irq, dev_id, regs); + return pxa_timer_interrupt(irq, dev_id); } return IRQ_NONE; } diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 249353616ab..17e46c1060b 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -174,7 +174,7 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = { */ static struct pxamci_platform_data tosa_mci_platform_data; -static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *, struct pt_regs *), void *data) +static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *), void *data) { int err; diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index 910571e9a19..a2c05a840a2 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -270,7 +270,7 @@ void board_pcmcia_power(int power) {;} #endif /* CONFIG_MACH_TRIZEPS4_CONXS */ EXPORT_SYMBOL(board_pcmcia_power); -static int trizeps4_mci_init(struct device *dev, irqreturn_t (*mci_detect_int)(int, void *, struct pt_regs *), void *data) +static int trizeps4_mci_init(struct device *dev, irqreturn_t (*mci_detect_int)(int, void *), void *data) { int err; /* setup GPIO for PXA27x MMC controller */ diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index da028697382..68c67053f47 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -515,18 +515,18 @@ static unsigned long realview_gettimeoffset(void) /* * IRQ handler for the timer */ -static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); // ...clear the interrupt writel(1, TIMER0_VA_BASE + TIMER_INTCLR); - timer_tick(regs); + timer_tick(); #if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) smp_send_timer(); - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif write_sequnlock(&xtime_lock); diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c index ac511d41d4d..596379a4cf8 100644 --- a/arch/arm/mach-rpc/dma.c +++ b/arch/arm/mach-rpc/dma.c @@ -83,7 +83,7 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) sg->length |= flags; } -static irqreturn_t iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t iomd_dma_handle(int irq, void *dev_id) { dma_t *dma = (dma_t *)dev_id; unsigned long base = dma->dma_base; diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c index 440e9aa0211..23d5beea556 100644 --- a/arch/arm/mach-s3c2410/bast-irq.c +++ b/arch/arm/mach-s3c2410/bast-irq.c @@ -112,8 +112,7 @@ static struct irqchip bast_pc104_chip = { static void bast_irq_pc104_demux(unsigned int irq, - struct irqdesc *desc, - struct pt_regs *regs) + struct irqdesc *desc) { unsigned int stat; unsigned int irqno; @@ -133,7 +132,7 @@ bast_irq_pc104_demux(unsigned int irq, if (stat & 1) { irqno = bast_pc104_irqs[i]; desc = irq_desc + irqno; - desc_handle_irq(irqno, desc, regs); + desc_handle_irq(irqno, desc); } } } diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c index d264bbbd8be..3d211dc2f2f 100644 --- a/arch/arm/mach-s3c2410/dma.c +++ b/arch/arm/mach-s3c2410/dma.c @@ -595,7 +595,7 @@ s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) #define dmadbg2(x...) static irqreturn_t -s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs) +s3c2410_dma_irq(int irq, void *devpw) { struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; struct s3c2410_dma_buf *buf; diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 3e9f3462c61..683b3491ba3 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -480,8 +480,7 @@ static struct irqchip s3c_irq_adc = { /* irq demux for adc */ static void s3c_irq_demux_adc(unsigned int irq, - struct irqdesc *desc, - struct pt_regs *regs) + struct irqdesc *desc) { unsigned int subsrc, submsk; unsigned int offset = 9; @@ -500,17 +499,16 @@ static void s3c_irq_demux_adc(unsigned int irq, if (subsrc != 0) { if (subsrc & 1) { mydesc = irq_desc + IRQ_TC; - desc_handle_irq(IRQ_TC, mydesc, regs); + desc_handle_irq(IRQ_TC, mydesc); } if (subsrc & 2) { mydesc = irq_desc + IRQ_ADC; - desc_handle_irq(IRQ_ADC, mydesc, regs); + desc_handle_irq(IRQ_ADC, mydesc); } } } -static void s3c_irq_demux_uart(unsigned int start, - struct pt_regs *regs) +static void s3c_irq_demux_uart(unsigned int start) { unsigned int subsrc, submsk; unsigned int offset = start - IRQ_S3CUART_RX0; @@ -533,17 +531,17 @@ static void s3c_irq_demux_uart(unsigned int start, desc = irq_desc + start; if (subsrc & 1) - desc_handle_irq(start, desc, regs); + desc_handle_irq(start, desc); desc++; if (subsrc & 2) - desc_handle_irq(start+1, desc, regs); + desc_handle_irq(start+1, desc); desc++; if (subsrc & 4) - desc_handle_irq(start+2, desc, regs); + desc_handle_irq(start+2, desc); } } @@ -551,35 +549,31 @@ static void s3c_irq_demux_uart(unsigned int start, static void s3c_irq_demux_uart0(unsigned int irq, - struct irqdesc *desc, - struct pt_regs *regs) + struct irqdesc *desc) { irq = irq; - s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs); + s3c_irq_demux_uart(IRQ_S3CUART_RX0); } static void s3c_irq_demux_uart1(unsigned int irq, - struct irqdesc *desc, - struct pt_regs *regs) + struct irqdesc *desc) { irq = irq; - s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs); + s3c_irq_demux_uart(IRQ_S3CUART_RX1); } static void s3c_irq_demux_uart2(unsigned int irq, - struct irqdesc *desc, - struct pt_regs *regs) + struct irqdesc *desc) { irq = irq; - s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); + s3c_irq_demux_uart(IRQ_S3CUART_RX2); } static void s3c_irq_demux_extint8(unsigned int irq, - struct irqdesc *desc, - struct pt_regs *regs) + struct irqdesc *desc) { unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); @@ -594,15 +588,14 @@ s3c_irq_demux_extint8(unsigned int irq, eintpnd &= ~(1<> 5) & 7); diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index 7364478cec1..fa6dc71bd6a 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -702,7 +702,7 @@ static u32 gpio_irq_mask[] = { GPIO2_SD_CON_SLT, }; -static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc) { int i; @@ -719,14 +719,14 @@ static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_re if (0) printk("%s KPIO 0x%08X\n", __FUNCTION__, irq); for (j = 0; j < H3800_KPIO_IRQ_COUNT; j++) if (irq & kpio_irq_mask[j]) - do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j, regs); + do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j); /* GPIO2 */ irq = H3800_ASIC2_GPIINTFLAG; if (0) printk("%s GPIO 0x%08X\n", __FUNCTION__, irq); for (j = 0; j < H3800_GPIO_IRQ_COUNT; j++) if (irq & gpio_irq_mask[j]) - do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j , regs); + do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j); } if (i >= MAX_ASIC_ISR_LOOPS) diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index b55b90a2e8f..f4c6322ca33 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -110,8 +110,7 @@ static struct irq_chip sa1100_low_gpio_chip = { * and call the handler. */ static void -sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc) { unsigned int mask; @@ -128,7 +127,7 @@ sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc, mask >>= 11; do { if (mask & 1) - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); mask >>= 1; irq++; desc++; diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index af6d2775cf8..354d5e91da5 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -29,7 +29,7 @@ * is rather unfortunate. */ static void -neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +neponset_irq_handler(unsigned int irq, struct irqdesc *desc) { unsigned int irr; @@ -69,12 +69,12 @@ neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg if (irr & IRR_ETHERNET) { d = irq_desc + IRQ_NEPONSET_SMC9196; - desc_handle_irq(IRQ_NEPONSET_SMC9196, d, regs); + desc_handle_irq(IRQ_NEPONSET_SMC9196, d); } if (irr & IRR_USAR) { d = irq_desc + IRQ_NEPONSET_USAR; - desc_handle_irq(IRQ_NEPONSET_USAR, d, regs); + desc_handle_irq(IRQ_NEPONSET_USAR, d); } desc->chip->unmask(irq); @@ -82,7 +82,7 @@ neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg if (irr & IRR_SA1111) { d = irq_desc + IRQ_NEPONSET_SA1111; - desc_handle_irq(IRQ_NEPONSET_SA1111, d, regs); + desc_handle_irq(IRQ_NEPONSET_SA1111, d); } } } diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c index 5eba5fbbb56..59703c6fb29 100644 --- a/arch/arm/mach-sa1100/ssp.c +++ b/arch/arm/mach-sa1100/ssp.c @@ -25,7 +25,7 @@ #define TIMEOUT 100000 -static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ssp_interrupt(int irq, void *dev_id) { unsigned int status = Ser4SSSR; diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 49ae716e16c..4284bd6f7a1 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -77,7 +77,7 @@ static int match_posponed; #endif static irqreturn_t -sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +sa1100_timer_interrupt(int irq, void *dev_id) { unsigned int next_match; @@ -99,7 +99,7 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * handlers. */ do { - timer_tick(regs); + timer_tick(); OSSR = OSSR_M0; /* Clear match on timer 0 */ next_match = (OSMR0 += LATCH); } while ((signed long)(next_match - OSCR) <= 0); @@ -151,13 +151,13 @@ static void sa1100_dyn_tick_reprogram(unsigned long ticks) } static irqreturn_t -sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs) +sa1100_dyn_tick_handler(int irq, void *dev_id) { if (match_posponed) { match_posponed = 0; OSMR0 = initial_match; if ((signed long)(initial_match - OSCR) <= 0) - return sa1100_timer_interrupt(irq, dev_id, regs); + return sa1100_timer_interrupt(irq, dev_id); } return IRQ_NONE; } diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index 1095df34fec..0e480fae8ec 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -80,10 +80,10 @@ static void __init shark_map_io(void) #define HZ_TIME ((1193180 + HZ/2) / HZ) static irqreturn_t -shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +shark_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c index b227052296c..297ecf13065 100644 --- a/arch/arm/mach-shark/irq.c +++ b/arch/arm/mach-shark/irq.c @@ -61,7 +61,7 @@ static void shark_enable_8259A_irq(unsigned int irq) static void shark_ack_8259A_irq(unsigned int irq){} -static irqreturn_t bogus_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bogus_int(int irq, void *dev_id) { printk("Got interrupt %i!\n",irq); return IRQ_NONE; diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index f2bbef07b1e..2aa150b57ba 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -77,12 +77,12 @@ static struct irq_chip sic_chip = { }; static void -sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +sic_handle_irq(unsigned int irq, struct irqdesc *desc) { unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); if (status == 0) { - do_bad_IRQ(irq, desc, regs); + do_bad_IRQ(irq, desc); return; } @@ -93,7 +93,7 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) irq += IRQ_SIC_START; desc = irq_desc + irq; - desc_handle_irq(irq, desc, regs); + desc_handle_irq(irq, desc); } while (status); } @@ -851,14 +851,14 @@ static unsigned long versatile_gettimeoffset(void) /* * IRQ handler for the timer */ -static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); // ...clear the interrupt writel(1, TIMER0_VA_BASE + TIMER_INTCLR); - timer_tick(regs); + timer_tick(); write_sequnlock(&xtime_lock); diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c index 726ad2b3b43..7899d3ca75a 100644 --- a/arch/arm/oprofile/op_model_xscale.c +++ b/arch/arm/oprofile/op_model_xscale.c @@ -341,7 +341,7 @@ static void inline __xsc2_check_ctrs(void) __asm__ __volatile__ ("mcr p14, 0, %0, c5, c1, 0" : : "r" (flag)); } -static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t xscale_pmu_interrupt(int irq, void *arg) { int i; u32 pmnc; @@ -356,7 +356,7 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs continue; write_counter(i, -(u32)results[i].reset_counter); - oprofile_add_sample(regs, i); + oprofile_add_sample(get_irq_regs(), i); results[i].ovf--; } diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c index 06282dffbdc..f530abdaa7a 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/plat-iop/time.c @@ -47,7 +47,7 @@ unsigned long iop3xx_gettimeoffset(void) } static irqreturn_t -iop3xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +iop3xx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -57,7 +57,7 @@ iop3xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) while ((signed long)(next_jiffy_time - *IOP3XX_TU_TCR1) >= ticks_per_jiffy) { - timer_tick(regs); + timer_tick(); next_jiffy_time -= ticks_per_jiffy; } diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 1bbb431843c..bb045e5ddbd 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -899,8 +899,7 @@ static int omap1_dma_handle_ch(int ch) return 1; } -static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id) { int ch = ((int) dev_id) - 1; int handled = 0; @@ -962,8 +961,7 @@ static int omap2_dma_handle_ch(int ch) } /* STATUS register count is from 1-32 while our is 0-31 */ -static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id) { u32 val; int i; @@ -1220,8 +1218,7 @@ static void set_b1_regs(void) omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L); } -static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id) { u16 w; diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index f55f99ae58a..8162eed8b50 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -783,8 +783,7 @@ void omap_free_gpio(int gpio) * line's interrupt handler has been run, we may miss some nested * interrupts. */ -static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, - struct pt_regs *regs) +static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc) { void __iomem *isr_reg = NULL; u32 isr; @@ -882,7 +881,7 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, continue; } - desc_handle_irq(gpio_irq, d, regs); + desc_handle_irq(gpio_irq, d); if (unlikely((d->status & IRQ_PENDING) && !d->depth)) { irq_mask = 1 << diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index ade9a0fa6ef..ec50008a2df 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -96,7 +96,7 @@ static void omap_mcbsp_dump_reg(u8 id) DBG("***********************\n"); } -static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) { struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); @@ -106,7 +106,7 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_re return IRQ_HANDLED; } -static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) { struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id); diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index cf6df3378d3..26531060116 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c @@ -194,8 +194,7 @@ unsigned long long sched_clock(void) * issues with dynamic tick. In the dynamic tick case, we need to lock * with irqsave. */ -static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id) { unsigned long now; @@ -205,7 +204,7 @@ static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id, while ((signed long)(now - omap_32k_last_tick) >= OMAP_32K_TICKS_PER_HZ) { omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; - timer_tick(regs); + timer_tick(); } /* Restart timer so we don't drift off due to modulo or dynamic tick. @@ -218,19 +217,17 @@ static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id, return IRQ_HANDLED; } -static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id) { - return _omap_32k_timer_interrupt(irq, dev_id, regs); + return _omap_32k_timer_interrupt(irq, dev_id); } -static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) { unsigned long flags; write_seqlock_irqsave(&xtime_lock, flags); - _omap_32k_timer_interrupt(irq, dev_id, regs); + _omap_32k_timer_interrupt(irq, dev_id); write_sequnlock_irqrestore(&xtime_lock, flags); return IRQ_HANDLED; diff --git a/include/asm-arm/arch-clps711x/time.h b/include/asm-arm/arch-clps711x/time.h index 0e4a3901d3b..5edaae1c61d 100644 --- a/include/asm-arm/arch-clps711x/time.h +++ b/include/asm-arm/arch-clps711x/time.h @@ -26,8 +26,9 @@ extern void clps711x_setup_timer(void); * IRQ handler for the timer */ static irqreturn_t -p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +p720t_timer_interrupt(int irq, void *dev_id) { + struct pt_regs *regs = get_irq_regs(); do_leds(); do_timer(1); #ifndef CONFIG_SMP diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h index 599f03e5a9e..5b1066da4e1 100644 --- a/include/asm-arm/arch-imx/imx-dma.h +++ b/include/asm-arm/arch-imx/imx-dma.h @@ -45,8 +45,8 @@ struct imx_dma_channel { const char *name; - void (*irq_handler) (int, void *, struct pt_regs *); - void (*err_handler) (int, void *, struct pt_regs *, int errcode); + void (*irq_handler) (int, void *); + void (*err_handler) (int, void *, int errcode); void *data; dmamode_t dma_mode; struct scatterlist *sg; @@ -77,8 +77,8 @@ imx_dma_setup_sg(imx_dmach_t dma_ch, int imx_dma_setup_handlers(imx_dmach_t dma_ch, - void (*irq_handler) (int, void *, struct pt_regs *), - void (*err_handler) (int, void *, struct pt_regs *, int), void *data); + void (*irq_handler) (int, void *), + void (*err_handler) (int, void *, int), void *data); void imx_dma_enable(imx_dmach_t dma_ch); diff --git a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h index c69cb508735..ea22f7fff9c 100644 --- a/include/asm-arm/arch-l7200/time.h +++ b/include/asm-arm/arch-l7200/time.h @@ -43,8 +43,9 @@ * Handler for RTC timer interrupt */ static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +timer_interrupt(int irq, void *dev_id) { + struct pt_regs *regs = get_irq_regs(); do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); diff --git a/include/asm-arm/arch-pnx4008/dma.h b/include/asm-arm/arch-pnx4008/dma.h index 3aee1204795..418f15283ff 100644 --- a/include/asm-arm/arch-pnx4008/dma.h +++ b/include/asm-arm/arch-pnx4008/dma.h @@ -137,7 +137,7 @@ extern void pnx4008_free_ll_entry(struct pnx4008_dma_ll *, dma_addr_t); extern void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll *); extern int pnx4008_request_channel(char *, int, - void (*)(int, int, void *, struct pt_regs *), + void (*)(int, int, void *), void *); extern void pnx4008_free_channel(int); extern int pnx4008_config_dma(int, int, int); diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h index a008150abc5..bed042d71d6 100644 --- a/include/asm-arm/arch-pxa/dma.h +++ b/include/asm-arm/arch-pxa/dma.h @@ -56,7 +56,7 @@ for ( \ int pxa_request_dma (char *name, pxa_dma_prio prio, - void (*irq_handler)(int, void *, struct pt_regs *), + void (*irq_handler)(int, void *), void *data); void pxa_free_dma (int dma_ch); diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h index 88c17dd02ed..b704c4f05f4 100644 --- a/include/asm-arm/arch-pxa/mmc.h +++ b/include/asm-arm/arch-pxa/mmc.h @@ -10,7 +10,7 @@ struct mmc_host; struct pxamci_platform_data { unsigned int ocr_mask; /* available voltages */ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ - int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *); + int (*init)(struct device *, irqreturn_t (*)(int, void *), void *); int (*get_ro)(struct device *); void (*setpower)(struct device *, unsigned int); void (*exit)(struct device *, void *); diff --git a/include/asm-arm/hardware/sharpsl_pm.h b/include/asm-arm/hardware/sharpsl_pm.h index a836e76a14f..2d00db22b98 100644 --- a/include/asm-arm/hardware/sharpsl_pm.h +++ b/include/asm-arm/hardware/sharpsl_pm.h @@ -100,7 +100,7 @@ extern struct sharpsl_pm_status sharpsl_pm; void sharpsl_battery_kick(void); void sharpsl_pm_led(int val); -irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp); -irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp); -irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp); +irqreturn_t sharpsl_ac_isr(int irq, void *dev_id); +irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id); +irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id); diff --git a/include/asm-arm/irq_regs.h b/include/asm-arm/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-arm/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-arm/mach/irq.h b/include/asm-arm/mach/irq.h index 131f33733d2..0e017ecf209 100644 --- a/include/asm-arm/mach/irq.h +++ b/include/asm-arm/mach/irq.h @@ -30,10 +30,9 @@ extern int show_fiq_list(struct seq_file *, void *); /* * Obsolete inline function for calling irq descriptor handlers. */ -static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc) { - desc->handle_irq(irq, desc, regs); + desc->handle_irq(irq, desc); } void set_irq_flags(unsigned int irq, unsigned int flags); @@ -51,10 +50,10 @@ void set_irq_flags(unsigned int irq, unsigned int flags); #define irqdesc irq_desc #define irqchip irq_chip -#define do_bad_IRQ(irq,desc,regs) \ +#define do_bad_IRQ(irq,desc) \ do { \ spin_lock(&desc->lock); \ - handle_bad_irq(irq, desc, regs); \ + handle_bad_irq(irq, desc); \ spin_unlock(&desc->lock); \ } while(0) diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h index 1eb93f5c0d6..5dc357013b7 100644 --- a/include/asm-arm/mach/time.h +++ b/include/asm-arm/mach/time.h @@ -57,7 +57,7 @@ struct dyn_tick_timer { int (*enable)(void); /* Enables dynamic tick */ int (*disable)(void); /* Disables dynamic tick */ void (*reprogram)(unsigned long); /* Reprograms the timer */ - int (*handler)(int, void *, struct pt_regs *); + int (*handler)(int, void *); }; void timer_dyn_reprogram(void); @@ -66,7 +66,7 @@ void timer_dyn_reprogram(void); #endif extern struct sys_timer *system_timer; -extern void timer_tick(struct pt_regs *); +extern void timer_tick(void); /* * Kernel time keeping support. -- GitLab From 815a965b0e6d925646e1f6012175830ef21e0d21 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 6 Oct 2006 11:11:56 +0200 Subject: [PATCH 0725/1619] [PATCH] make kernels with CONFIG_X86_GENERIC and !CONFIG_SMP compilable CONFIG_X86_GENERIC is not exclusively CONFIG_SMP, as mach-default/ could be compiled also for UP archs. The patch fixes compilation error in include/asm/mach-summit/mach_apic.h in case CONFIG_X86_GENERIC && !CONFIG_SMP Signed-off-by: Jiri Kosina Acked-by: Keith Mannthey Signed-off-by: Linus Torvalds --- include/asm-i386/smp.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 6aa1206f6e2..bd59c1508e7 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -46,8 +46,6 @@ extern u8 x86_cpu_to_apicid[]; #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] -extern u8 apicid_2_node[]; - #ifdef CONFIG_HOTPLUG_CPU extern void cpu_exit_clear(void); extern void cpu_uninit(void); @@ -101,6 +99,9 @@ extern unsigned int num_processors; #endif #ifndef __ASSEMBLY__ + +extern u8 apicid_2_node[]; + #ifdef CONFIG_X86_LOCAL_APIC static __inline int logical_smp_processor_id(void) { -- GitLab From 476d1205d182e12a74f4197ccc9092ea6a80e15b Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Tue, 26 Sep 2006 15:27:38 +0200 Subject: [PATCH 0726/1619] [ALSA] hda/patch_si3054: new codec vendor IDs There are additional IDs for Si3054 codec based HDA modems. Most of them were discovered on discuss@linmodems.org list - Thanks to MarvS and all linmodems.org folks. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_si3054.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 76ec3d75fa9..cc87dff1eb5 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -297,8 +297,13 @@ static int patch_si3054(struct hda_codec *codec) struct hda_codec_preset snd_hda_preset_si3054[] = { { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, + { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, + { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, + { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, + { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 }, + { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 }, {} }; -- GitLab From 2aedbda6f9a51f0a2130c150676a5c99c81fa7a2 Mon Sep 17 00:00:00 2001 From: Luke Zhang Date: Tue, 26 Sep 2006 15:28:41 +0200 Subject: [PATCH 0727/1619] [ALSA] WM9712 fixes for ac97_patch.c This patch by Luke Zhang fixes a couple of issues with the WM9712 support in ac97_patch.c Changes:- o Fix Out3 ZC switch invert. o Extend capture volume control to 6 bits. o Change Mic 1 volume mask to 5 bits (31). o Add Mic 2 volume. Signed-off-by: Luke Zhang Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index dc28b111a06..15be6ba87c8 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -530,7 +530,7 @@ AC97_ENUM("ALC Headphone Mux", wm9711_enum[1]), AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1), AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1), -AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1), +AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 0), AC97_ENUM("Out3 Mux", wm9711_enum[2]), AC97_ENUM("Out3 LR Mux", wm9711_enum[3]), AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1), @@ -575,13 +575,14 @@ AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1), AC97_ENUM("Capture Volume Steps", wm9711_enum[6]), -AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1), +AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1), AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1), AC97_ENUM("Mic Select Source", wm9711_enum[7]), -AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1), +AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), +AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), -- GitLab From 7a99795477ca758a4b29ef3595edde2e067af85a Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Tue, 26 Sep 2006 15:30:10 +0200 Subject: [PATCH 0728/1619] [ALSA] Add new subdevice ids for hda-intel This patch adds a couple of device ids for Acer laptops. In both cases, the owners got the driver working by adding 'model=acer' to their modprobe.conf files. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d08d2e399c8..84a3eb8aacc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5076,6 +5076,10 @@ static struct hda_board_config alc883_cfg_tbl[] = { { .modelname = "acer", .config = ALC883_ACER }, { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, .config = ALC883_ACER }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102, + .config = ALC883_ACER }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f, + .config = ALC883_ACER }, { .modelname = "auto", .config = ALC883_AUTO }, {} }; -- GitLab From f3838ba9204cd8af83c4358379221af66d77714e Mon Sep 17 00:00:00 2001 From: Dan Cyr Date: Tue, 26 Sep 2006 15:32:35 +0200 Subject: [PATCH 0729/1619] [ALSA] hda-intel - New pci id for Nvidia MCP61 Added the new PCI id to support Nvidia MCP61 in snd-hda-intel driver. Signed-off-by: Dan Cyr Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a76a778d0a1..feeed12920b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1682,6 +1682,7 @@ static struct pci_device_id azx_ids[] = { { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */ { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */ + { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 03f0 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- GitLab From 92b93d31718a3ccbbcf911d2f570bb345c496d66 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Thu, 28 Sep 2006 12:35:48 +0200 Subject: [PATCH 0730/1619] [ALSA] Fix memory leak in sound/isa/es18xx.c Fixed a memory leak in the error patch. Signed-off-by: Eric Sesterhenn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/isa/es18xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 2398d2c55fe..725c115ff97 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -2154,6 +2154,7 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, } /* Control port initialization */ if (pnp_activate_dev(acard->devc) < 0) { + kfree(cfg); snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); return -EAGAIN; } -- GitLab From 104326f8df9925317cca64b84249d3eac5de7c74 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Fri, 29 Sep 2006 12:55:25 +0200 Subject: [PATCH 0731/1619] [ALSA] Dereference after free in snd_hwdep_release() snd_card_file_remove() may free hw->card so we can't dereference hw->card->module after that. Coverity ID 1420. Signed-off-by: Florin Malita Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/hwdep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 9aa9d94891f..46b47689362 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) { int err = -ENXIO; struct snd_hwdep *hw = file->private_data; + struct module *mod = hw->card->module; mutex_lock(&hw->open_mutex); if (hw->ops.release) { err = hw->ops.release(hw, file); @@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) hw->used--; snd_card_file_remove(hw->card, file); mutex_unlock(&hw->open_mutex); - module_put(hw->card->module); + module_put(mod); return err; } -- GitLab From 9b08c2aa54948361da0e2d26b47e3bcb8f8911e8 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Wed, 4 Oct 2006 17:16:46 +0200 Subject: [PATCH 0732/1619] [ALSA] Fix bug in snd-usb-usx2y's usX2Y_pcms_lock_check() Fix bug in snd-usb-usx2y's usX2Y_pcms_lock_check() substream can be NULL...... in mainline, bug was introduced by: 2006-06-22 [ALSA] Add O_APPEND flag support to PCM Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/usb/usx2y/usx2yhwdeppcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 9acef9d9054..20708d2ffb6 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -632,7 +632,7 @@ static int usX2Y_pcms_lock_check(struct snd_card *card) for (s = 0; s < 2; ++s) { struct snd_pcm_substream *substream; substream = pcm->streams[s].substream; - if (SUBSTREAM_BUSY(substream)) + if (substream && SUBSTREAM_BUSY(substream)) err = -EBUSY; } } -- GitLab From 635bbb355ebb735647ca49fb649a6a7edea9b3ed Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Wed, 4 Oct 2006 17:17:32 +0200 Subject: [PATCH 0733/1619] [ALSA] Repair snd-usb-usx2y for usb 2.6.18 urb->start_frame rolls over beyond MAX_INT now. This is for stable kernel and stable alsa. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/usb/usx2y/usbusx2yaudio.c | 18 ++++++------------ sound/usb/usx2y/usx2yhwdeppcm.c | 15 +++++---------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index e662281a751..367f8a32a66 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -322,7 +322,7 @@ static void i_usX2Y_urb_complete(struct urb *urb) usX2Y_error_urb_status(usX2Y, subs, urb); return; } - if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame)) + if (likely(urb->start_frame == usX2Y->wait_iso_frame)) subs->completed_urb = urb; else { usX2Y_error_sequence(usX2Y, subs, urb); @@ -335,13 +335,9 @@ static void i_usX2Y_urb_complete(struct urb *urb) atomic_read(&capsubs->state) >= state_PREPARED && (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) { - if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) { - if (nr_of_packs() <= urb->start_frame && - urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci - usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs(); - else - usX2Y->wait_iso_frame += nr_of_packs(); - } else { + if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) + usX2Y->wait_iso_frame += nr_of_packs(); + else { snd_printdd("\n"); usX2Y_clients_stop(usX2Y); } @@ -495,7 +491,6 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED) goto start; } - usX2Y->wait_iso_frame = -1; start: usX2Y_subs_startup(subs); @@ -516,10 +511,9 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err); err = -EPIPE; goto cleanup; - } else { - if (0 > usX2Y->wait_iso_frame) + } else + if (i == 0) usX2Y->wait_iso_frame = urb->start_frame; - } urb->transfer_flags = 0; } else { atomic_set(&subs->state, state_STARTING1); diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 20708d2ffb6..8f3e35e24e7 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -243,7 +243,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) usX2Y_error_urb_status(usX2Y, subs, urb); return; } - if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame)) + if (likely(urb->start_frame == usX2Y->wait_iso_frame)) subs->completed_urb = urb; else { usX2Y_error_sequence(usX2Y, subs, urb); @@ -256,13 +256,9 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED && (NULL == capsubs2 || capsubs2->completed_urb) && (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) { - if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) { - if (nr_of_packs() <= urb->start_frame && - urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci - usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs(); - else - usX2Y->wait_iso_frame += nr_of_packs(); - } else { + if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) + usX2Y->wait_iso_frame += nr_of_packs(); + else { snd_printdd("\n"); usX2Y_clients_stop(usX2Y); } @@ -433,7 +429,6 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED) goto start; } - usX2Y->wait_iso_frame = -1; start: usX2Y_usbpcm_subs_startup(subs); @@ -459,7 +454,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) goto cleanup; } else { snd_printdd("%i\n", urb->start_frame); - if (0 > usX2Y->wait_iso_frame) + if (u == 0) usX2Y->wait_iso_frame = urb->start_frame; } urb->transfer_flags = 0; -- GitLab From 4130d59b1ac6e32c130bd59dbce5eb30fede0197 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Wed, 4 Oct 2006 18:21:05 +0200 Subject: [PATCH 0734/1619] [ALSA] emu10k1: Fix outl() in snd_emu10k1_resume_regs() The emu10k1 driver saves the A_IOCFG and HCFG register on suspend and restores it on resumes. Unfortunately, this doesn't work as the arguments to outl() are reversed. Signed-off-by: Arnaud Patard Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index be65d4db8e2..8058059c56e 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1461,8 +1461,8 @@ void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu) /* resore for spdif */ if (emu->audigy) - outl(emu->port + A_IOCFG, emu->saved_a_iocfg); - outl(emu->port + HCFG, emu->saved_hcfg); + outl(emu->saved_a_iocfg, emu->port + A_IOCFG); + outl(emu->saved_hcfg, emu->port + HCFG); val = emu->saved_ptr; for (reg = saved_regs; *reg != 0xff; reg++) -- GitLab From a9edfc60227a1dc5c741666ff252a6055b73b184 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Fri, 6 Oct 2006 16:08:27 +0200 Subject: [PATCH 0735/1619] [ALSA] Handle file operations during snd_card disconnects using static file->f_op Alsa used to kmalloc one file->f_op per file per disconnecting snd_card. This led to oopses sometimes when file->f_op was freed before __fput() finished. Patch adds a virtual device for disconnect: VDD. VDD consists of: LIST_HEAD(shutdown_files) protected by DEFINE_SPINLOCK(shutdown_mutex) static struct file_operations snd_shutdown_f_ops and functions assigned to it Additions to struct snd_monitor_file to specify if instance is hidden by VDD or not. A VDD's instance is created in snd_card_disconnect() under the card->files_lock. cleaned up in snd_card_file_remove() under the card->files_lock. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- include/sound/core.h | 4 +- sound/core/init.c | 92 +++++++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index b056ea925ec..fa1ca0127ba 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -89,10 +89,10 @@ struct snd_device { struct snd_monitor_file { struct file *file; struct snd_monitor_file *next; + const struct file_operations *disconnected_f_op; + struct list_head shutdown_list; }; -struct snd_shutdown_f_ops; /* define it later in init.c */ - /* main structure for soundcard */ struct snd_card { diff --git a/sound/core/init.c b/sound/core/init.c index d7607a25acd..3058d626a90 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -33,10 +33,10 @@ #include #include -struct snd_shutdown_f_ops { - struct file_operations f_ops; - struct snd_shutdown_f_ops *next; -}; +static DEFINE_SPINLOCK(shutdown_lock); +static LIST_HEAD(shutdown_files); + +static struct file_operations snd_shutdown_f_ops; static unsigned int snd_cards_lock; /* locked for registering/using */ struct snd_card *snd_cards[SNDRV_CARDS]; @@ -198,6 +198,25 @@ static ssize_t snd_disconnect_write(struct file *file, const char __user *buf, return -ENODEV; } +static int snd_disconnect_release(struct inode *inode, struct file *file) +{ + struct snd_monitor_file *df = NULL, *_df; + + spin_lock(&shutdown_lock); + list_for_each_entry(_df, &shutdown_files, shutdown_list) { + if (_df->file == file) { + df = _df; + break; + } + } + spin_unlock(&shutdown_lock); + + if (likely(df)) + return df->disconnected_f_op->release(inode, file); + + panic("%s(%p, %p) failed!", __FUNCTION__, inode, file); +} + static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait) { return POLLERR | POLLNVAL; @@ -219,6 +238,22 @@ static int snd_disconnect_fasync(int fd, struct file *file, int on) return -ENODEV; } +static struct file_operations snd_shutdown_f_ops = +{ + .owner = THIS_MODULE, + .llseek = snd_disconnect_llseek, + .read = snd_disconnect_read, + .write = snd_disconnect_write, + .release = snd_disconnect_release, + .poll = snd_disconnect_poll, + .unlocked_ioctl = snd_disconnect_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = snd_disconnect_ioctl, +#endif + .mmap = snd_disconnect_mmap, + .fasync = snd_disconnect_fasync +}; + /** * snd_card_disconnect - disconnect all APIs from the file-operations (user space) * @card: soundcard structure @@ -234,9 +269,6 @@ int snd_card_disconnect(struct snd_card *card) { struct snd_monitor_file *mfile; struct file *file; - struct snd_shutdown_f_ops *s_f_ops; - struct file_operations *f_ops; - const struct file_operations *old_f_ops; int err; spin_lock(&card->files_lock); @@ -261,34 +293,14 @@ int snd_card_disconnect(struct snd_card *card) /* it's critical part, use endless loop */ /* we have no room to fail */ - s_f_ops = kmalloc(sizeof(struct snd_shutdown_f_ops), GFP_ATOMIC); - if (s_f_ops == NULL) - panic("Atomic allocation failed for snd_shutdown_f_ops!"); - - f_ops = &s_f_ops->f_ops; - - memset(f_ops, 0, sizeof(*f_ops)); - f_ops->owner = file->f_op->owner; - f_ops->release = file->f_op->release; - f_ops->llseek = snd_disconnect_llseek; - f_ops->read = snd_disconnect_read; - f_ops->write = snd_disconnect_write; - f_ops->poll = snd_disconnect_poll; - f_ops->unlocked_ioctl = snd_disconnect_ioctl; -#ifdef CONFIG_COMPAT - f_ops->compat_ioctl = snd_disconnect_ioctl; -#endif - f_ops->mmap = snd_disconnect_mmap; - f_ops->fasync = snd_disconnect_fasync; + mfile->disconnected_f_op = mfile->file->f_op; - s_f_ops->next = card->s_f_ops; - card->s_f_ops = s_f_ops; - - f_ops = fops_get(f_ops); + spin_lock(&shutdown_lock); + list_add(&mfile->shutdown_list, &shutdown_files); + spin_unlock(&shutdown_lock); - old_f_ops = file->f_op; - file->f_op = f_ops; /* must be atomic */ - fops_put(old_f_ops); + fops_get(&snd_shutdown_f_ops); + mfile->file->f_op = &snd_shutdown_f_ops; mfile = mfile->next; } @@ -326,8 +338,6 @@ EXPORT_SYMBOL(snd_card_disconnect); */ static int snd_card_do_free(struct snd_card *card) { - struct snd_shutdown_f_ops *s_f_ops; - #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); @@ -351,11 +361,6 @@ static int snd_card_do_free(struct snd_card *card) snd_printk(KERN_WARNING "unable to free card info\n"); /* Not fatal error */ } - while (card->s_f_ops) { - s_f_ops = card->s_f_ops; - card->s_f_ops = s_f_ops->next; - kfree(s_f_ops); - } kfree(card); return 0; } @@ -670,6 +675,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file) if (mfile == NULL) return -ENOMEM; mfile->file = file; + mfile->disconnected_f_op = NULL; mfile->next = NULL; spin_lock(&card->files_lock); if (card->shutdown) { @@ -716,6 +722,12 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) pfile = mfile; mfile = mfile->next; } + if (mfile && mfile->disconnected_f_op) { + fops_put(mfile->disconnected_f_op); + spin_lock(&shutdown_lock); + list_del(&mfile->shutdown_list); + spin_unlock(&shutdown_lock); + } if (card->files == NULL) last_close = 1; spin_unlock(&card->files_lock); -- GitLab From 8a238c7b6a2ec1852419e8fb8b8b0457c55c47e6 Mon Sep 17 00:00:00 2001 From: Amol Lad Date: Fri, 6 Oct 2006 16:45:19 +0200 Subject: [PATCH 0736/1619] [ALSA] sound/pci/au88x0/au88x0.c: ioremap balanced with iounmap Signed-off-by: Amol Lad Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/au88x0/au88x0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index ef189d7f09d..6ed5ad59f5b 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -128,6 +128,7 @@ static int snd_vortex_dev_free(struct snd_device *device) // Take down PCI interface. synchronize_irq(vortex->irq); free_irq(vortex->irq, vortex); + iounmap(vortex->mmio); pci_release_regions(vortex->pci_dev); pci_disable_device(vortex->pci_dev); kfree(vortex); -- GitLab From 5a078351d2d0a7ae834087de3637eb42cfd209e3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 6 Oct 2006 20:28:26 +0200 Subject: [PATCH 0737/1619] [ALSA] version 1.0.13 Signed-off-by: Jaroslav Kysela --- include/sound/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/version.h b/include/sound/version.h index 2ee849d0e19..4ad86eb6440 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ -/* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.12rc1" -#define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)" +/* include/version.h. Generated by alsa/ksync script. */ +#define CONFIG_SND_VERSION "1.0.13" +#define CONFIG_SND_DATE " (Fri Oct 06 18:28:19 2006 UTC)" -- GitLab From c31f28e778ab299a5035ea2bda64f245b8915d7c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 6 Oct 2006 14:56:04 -0400 Subject: [PATCH 0738/1619] drivers/net: eliminate irq handler impossible checks, needless casts - Eliminate check for irq handler 'dev_id==NULL' where the condition never occurs. - Eliminate needless casts to/from void* Signed-off-by: Jeff Garzik --- drivers/net/3c509.c | 7 +------ drivers/net/3c523.c | 7 ++----- drivers/net/3c527.c | 5 ----- drivers/net/8390.c | 8 +------- drivers/net/atp.c | 6 +----- drivers/net/de600.c | 6 ------ drivers/net/declance.c | 4 ++-- drivers/net/dgrs.c | 4 ++-- drivers/net/eepro.c | 8 +------- drivers/net/eexpress.c | 7 ------- drivers/net/irda/ali-ircc.c | 10 ++-------- drivers/net/irda/donauboe.c | 11 +---------- drivers/net/irda/irport.c | 8 ++------ drivers/net/irda/irport.h | 2 +- drivers/net/irda/nsc-ircc.c | 9 ++------- drivers/net/irda/w83977af_ir.c | 9 ++------- drivers/net/lance.c | 5 ----- drivers/net/pcmcia/axnet_cs.c | 8 +------- drivers/net/pcnet32.c | 7 ------- drivers/net/plip.c | 5 ----- drivers/net/saa9730.c | 2 +- drivers/net/sb1000.c | 8 +------- drivers/net/skfp/skfddi.c | 7 +------ drivers/net/sonic.c | 7 +------ drivers/net/sunhme.c | 4 ++-- drivers/net/sunlance.c | 2 +- drivers/net/sunqe.c | 2 +- drivers/net/tokenring/smctr.c | 7 ------- drivers/net/tokenring/tms380tr.c | 5 ----- drivers/net/tulip/de4x5.c | 6 +----- drivers/net/wan/cycx_main.c | 4 ++-- drivers/net/wan/sdla.c | 8 +------- drivers/net/wireless/orinoco.c | 2 +- drivers/net/wireless/wavelan_cs.c | 11 +---------- drivers/net/wireless/wl3501_cs.c | 15 ++++----------- drivers/net/yellowfin.c | 7 ------- drivers/net/znet.c | 5 ----- 37 files changed, 39 insertions(+), 199 deletions(-) diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 7ad0a54779c..f791bf026e5 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -912,16 +912,11 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) static irqreturn_t el3_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct el3_private *lp; int ioaddr, status; int i = max_interrupt_work; - if (dev == NULL) { - printk ("el3_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - lp = netdev_priv(dev); spin_lock(&lp->lock); diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 1c97271112d..91849469b4f 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -902,14 +902,11 @@ static void *alloc_rfa(struct net_device *dev, void *ptr) static irqreturn_t elmc_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; unsigned short stat; struct priv *p; - if (dev == NULL) { - printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", irq); - return IRQ_NONE; - } else if (!netif_running(dev)) { + if (!netif_running(dev)) { /* The 3c523 has this habit of generating interrupts during the reset. I'm not sure if the ni52 has this same problem, but it's really annoying if we haven't finished initializing it. I was diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index d516c3225ca..f4aca5386ad 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1324,11 +1324,6 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) int rx_event = 0; int tx_event = 0; - if (dev == NULL) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); - return IRQ_NONE; - } - ioaddr = dev->base_addr; lp = netdev_priv(dev); diff --git a/drivers/net/8390.c b/drivers/net/8390.c index fa3442cb1a4..3d1c599ac3c 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -406,14 +406,8 @@ irqreturn_t ei_interrupt(int irq, void *dev_id) int interrupts, nr_serviced = 0; struct ei_device *ei_local; - if (dev == NULL) - { - printk ("net_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - e8390_base = dev->base_addr; - ei_local = (struct ei_device *) netdev_priv(dev); + ei_local = netdev_priv(dev); /* * Protect the irq test too. diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 062f80e2087..2d306fcb7f3 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -598,17 +598,13 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) Handle the network interface interrupts. */ static irqreturn_t atp_interrupt(int irq, void *dev_instance) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; struct net_local *lp; long ioaddr; static int num_tx_since_rx; int boguscount = max_interrupt_work; int handled = 0; - if (dev == NULL) { - printk(KERN_ERR "ATP_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } ioaddr = dev->base_addr; lp = netdev_priv(dev); diff --git a/drivers/net/de600.c b/drivers/net/de600.c index d9b006c9e36..690bb40b353 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -265,12 +265,6 @@ static irqreturn_t de600_interrupt(int irq, void *dev_id) int retrig = 0; int boguscount = 0; - /* This might just as well be deleted now, no crummy drivers present :-) */ - if ((dev == NULL) || (DE600_IRQ != irq)) { - printk(KERN_ERR "%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq); - return IRQ_NONE; - } - spin_lock(&de600_lock); select_nic(); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index e179aa1c1ba..00e2a8a134d 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -696,7 +696,7 @@ out: static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; printk("%s: DMA error\n", dev->name); return IRQ_HANDLED; @@ -704,7 +704,7 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id) static irqreturn_t lance_interrupt(const int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int csr0; diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 6b1234b09fb..a79520295fd 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -897,8 +897,8 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) 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; + struct net_device *dev0 = dev_id; + DGRS_PRIV *priv0 = dev0->priv; I596_CB *cbp; int cmd; int i; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index aae454aaa1c..fd6e97891e7 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1198,17 +1198,11 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) static irqreturn_t eepro_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *)dev_id; - /* (struct net_device *)(irq2dev_map[irq]);*/ + struct net_device *dev = dev_id; struct eepro_local *lp; int ioaddr, status, boguscount = 20; int handled = 0; - if (dev == NULL) { - printk (KERN_ERR "eepro_interrupt(): irq %d for unknown device.\\n", irq); - return IRQ_NONE; - } - lp = netdev_priv(dev); spin_lock(&lp->lock); diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 05ca730fe81..e14be020e56 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -796,13 +796,6 @@ static irqreturn_t eexp_irq(int irq, void *dev_info) unsigned short ioaddr,status,ack_cmd; unsigned short old_read_ptr, old_write_ptr; - if (dev==NULL) - { - printk(KERN_WARNING "eexpress: irq %d for unknown device\n", - irq); - return IRQ_NONE; - } - lp = netdev_priv(dev); ioaddr = dev->base_addr; diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 971e2dee1e6..cebf8c374bc 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -662,19 +662,13 @@ static int ali_ircc_read_dongle_id (int i, chipio_t *info) */ static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct ali_ircc_cb *self; int ret; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); - if (!dev) { - IRDA_WARNING("%s: irq %d for unknown device.\n", - ALI_IRCC_DRIVER_NAME, irq); - return IRQ_NONE; - } - - self = (struct ali_ircc_cb *) dev->priv; + self = dev->priv; spin_lock(&self->lock); diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 7a9128181e6..636d0630fe0 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -657,12 +657,6 @@ toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt) return xbofs; } -static int toshoboe_invalid_dev(int irq) -{ - printk (KERN_WARNING DRIVER_NAME ": irq %d for unknown device.\n", irq); - return 1; -} - #ifdef USE_PROBE /***********************************************************************/ /* Probe code */ @@ -711,12 +705,9 @@ stuff_byte (__u8 byte, __u8 * buf) static irqreturn_t toshoboe_probeinterrupt (int irq, void *dev_id) { - struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; + struct toshoboe_cb *self = dev_id; __u8 irqstat; - if (self == NULL && toshoboe_invalid_dev(irq)) - return IRQ_NONE; - irqstat = INB (OBOE_ISR); /* was it us */ diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 6ea78ececca..654a68b490a 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -766,18 +766,14 @@ static inline void irport_receive(struct irport_cb *self) */ static irqreturn_t irport_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct irport_cb *self; int boguscount = 0; int iobase; int iir, lsr; int handled = 0; - if (!dev) { - IRDA_WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq); - return IRQ_NONE; - } - self = (struct irport_cb *) dev->priv; + self = dev->priv; spin_lock(&self->lock); diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h index 4393168347e..3f46b84c6c8 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); + irqreturn_t (*interrupt)(int irq, void *dev_id); }; #endif /* IRPORT_H */ diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index ea12e999814..29b5ccd29d0 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -2068,17 +2068,12 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, */ static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct nsc_ircc_cb *self; __u8 bsr, eir; int iobase; - if (!dev) { - IRDA_WARNING("%s: irq %d for unknown device.\n", - driver_name, irq); - return IRQ_NONE; - } - self = (struct nsc_ircc_cb *) dev->priv; + self = dev->priv; spin_lock(&self->lock); diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index b4fb92a7baa..4212657fa4f 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -1113,17 +1113,12 @@ static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr) */ static irqreturn_t w83977af_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct w83977af_ir *self; __u8 set, icr, isr; int iobase; - if (!dev) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); - return IRQ_NONE; - } - self = (struct w83977af_ir *) dev->priv; + self = dev->priv; iobase = self->io.fir_base; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 7afac47e59a..6efbd499d75 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -1019,11 +1019,6 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) int csr0, ioaddr, boguscnt=10; int must_restart; - if (dev == NULL) { - printk ("lance_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - ioaddr = dev->base_addr; lp = dev->priv; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index e5f36691091..5ddd5742f77 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1201,14 +1201,8 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) struct ei_device *ei_local; int handled = 0; - if (dev == NULL) - { - printk ("net_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - e8390_base = dev->base_addr; - ei_local = (struct ei_device *) netdev_priv(dev); + ei_local = netdev_priv(dev); /* * Protect the irq test too. diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index c73e2f21077..36f9d988278 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2569,13 +2569,6 @@ pcnet32_interrupt(int irq, void *dev_id) u16 csr0; int boguscnt = max_interrupt_work; - if (!dev) { - if (pcnet32_debug & NETIF_MSG_INTR) - printk(KERN_DEBUG "%s(): irq %d for unknown device\n", - __FUNCTION__, irq); - return IRQ_NONE; - } - ioaddr = dev->base_addr; lp = dev->priv; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index c0b333d2917..71afb274498 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -909,11 +909,6 @@ plip_interrupt(int irq, void *dev_id) struct plip_local *rcv; unsigned char c0; - if (dev == NULL) { - printk(KERN_DEBUG "plip_interrupt: irq %d for unknown device.\n", irq); - return; - } - nl = netdev_priv(dev); rcv = &nl->rcv_data; diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index c9efad8a917..b269513cde4 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -747,7 +747,7 @@ static int lan_saa9730_rx(struct net_device *dev) static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct lan_saa9730_private *lp = netdev_priv(dev); if (lan_saa9730_debug > 5) diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index dc30dee5537..b9fa4fbb139 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -1084,19 +1084,13 @@ static irqreturn_t sb1000_interrupt(int irq, void *dev_id) char *name; unsigned char st; int ioaddr[2]; - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct sb1000_private *lp = netdev_priv(dev); const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00}; const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; const int MaxRxErrorCount = 6; - if (dev == NULL) { - printk(KERN_ERR "sb1000_interrupt(): irq %d for unknown device.\n", - irq); - return IRQ_NONE; - } - ioaddr[0] = dev->base_addr; /* mem_start holds the second I/O address */ ioaddr[1] = dev->mem_start; diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 06ea2626c6f..9733a11c614 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -616,15 +616,10 @@ static int skfp_close(struct net_device *dev) irqreturn_t skfp_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct s_smc *smc; /* private board structure pointer */ skfddi_priv *bp; - if (dev == NULL) { - printk("%s: irq %d for unknown device\n", dev->name, irq); - return IRQ_NONE; - } - smc = netdev_priv(dev); bp = &smc->os; diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index cfece9676af..ed7aa0a5acc 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -295,15 +295,10 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) */ static irqreturn_t sonic_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct sonic_local *lp = netdev_priv(dev); int status; - if (dev == NULL) { - printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) return IRQ_NONE; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 45d07faf7b9..9d7cd130c19 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2095,8 +2095,8 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) 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; + struct net_device *dev = dev_id; + struct happy_meal *hp = netdev_priv(dev); u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("happy_meal_interrupt: status=%08x ", happy_status)); diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 9207e19cac3..5b00d79b557 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -822,7 +822,7 @@ out: static irqreturn_t lance_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct lance_private *lp = netdev_priv(dev); int csr0; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 020e7817059..7874eb1ef04 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -468,7 +468,7 @@ static void qe_tx_reclaim(struct sunqe *qep); */ static irqreturn_t qec_interrupt(int irq, void *dev_id) { - struct sunqec *qecp = (struct sunqec *) dev_id; + struct sunqec *qecp = dev_id; u32 qec_status; int channel = 0; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 9bd4cba8787..46dabdb1207 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -1990,15 +1990,8 @@ static irqreturn_t smctr_interrupt(int irq, void *dev_id) __u8 isb_type, isb_subtype; __u16 isb_index; - if(dev == NULL) - { - printk(KERN_CRIT "%s: irq %d for unknown device.\n", dev->name, irq); - return IRQ_NONE; - } - ioaddr = dev->base_addr; tp = netdev_priv(dev); - if(tp->status == NOT_INITIALIZED) return IRQ_NONE; diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index c0ab6e44eb1..ea797ca2b98 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -751,11 +751,6 @@ irqreturn_t tms380tr_interrupt(int irq, void *dev_id) unsigned short irq_type; int handled = 0; - if(dev == NULL) { - printk(KERN_INFO "%s: irq %d for unknown device.\n", dev->name, irq); - return IRQ_NONE; - } - tp = netdev_priv(dev); irq_type = SIFREADW(SIFSTS); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index e17f9779ead..3f4b6408b75 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1540,16 +1540,12 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) static irqreturn_t de4x5_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct de4x5_private *lp; s32 imr, omr, sts, limit; u_long iobase; unsigned int handled = 0; - if (dev == NULL) { - printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } lp = netdev_priv(dev); spin_lock(&lp->lock); iobase = dev->base_addr; diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 12363e056b6..6e5f1c89851 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -303,9 +303,9 @@ out: return ret; */ static irqreturn_t cycx_isr(int irq, void *dev_id) { - struct cycx_device *card = (struct cycx_device *)dev_id; + struct cycx_device *card = dev_id; - if (!card || card->wandev.state == WAN_UNCONFIGURED) + if (card->wandev.state == WAN_UNCONFIGURED) goto out; if (card->in_isr) { diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 5715d25271f..6a485f0556f 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -875,13 +875,7 @@ static irqreturn_t sdla_isr(int irq, void *dev_id) dev = dev_id; - if (dev == NULL) - { - printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - - flp = dev->priv; + flp = netdev_priv(dev); if (!flp->initialized) { diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 793da5f6934..b779c7dcc1a 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1954,7 +1954,7 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) irqreturn_t orinoco_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int count = MAX_IRQLOOPS_PER_IRQ; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index cadfe132db8..aafb301041b 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4119,21 +4119,12 @@ static irqreturn_t wavelan_interrupt(int irq, void * dev_id) { - struct net_device * dev; + struct net_device * dev = dev_id; net_local * lp; kio_addr_t base; int status0; u_int tx_status; - if ((dev = dev_id) == NULL) - { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", - irq); -#endif - return IRQ_NONE; - } - #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); #endif diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index a1430352169..5b98a787698 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1155,25 +1155,18 @@ static inline void wl3501_ack_interrupt(struct wl3501_card *this) */ static irqreturn_t wl3501_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct wl3501_card *this; - int handled = 1; - if (!dev) - goto unknown; - this = dev->priv; + this = netdev_priv(dev); spin_lock(&this->lock); wl3501_ack_interrupt(this); wl3501_block_interrupt(this); wl3501_rx_interrupt(dev); wl3501_unblock_interrupt(this); spin_unlock(&this->lock); -out: - return IRQ_RETVAL(handled); -unknown: - handled = 0; - printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq); - goto out; + + return IRQ_HANDLED; } static int wl3501_reset_board(struct wl3501_card *this) diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index ac600212d9a..2412ce4917f 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -896,13 +896,6 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) int boguscnt = max_interrupt_work; unsigned int handled = 0; -#ifndef final_version /* Can never occur. */ - if (dev == NULL) { - printk (KERN_ERR "yellowfin_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } -#endif - yp = netdev_priv(dev); ioaddr = yp->base; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 2068a109a86..b24b0727108 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -610,11 +610,6 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id) int boguscnt = 20; int handled = 0; - if (dev == NULL) { - printk(KERN_WARNING "znet_interrupt(): IRQ %d for unknown device.\n", irq); - return IRQ_NONE; - } - spin_lock (&znet->lock); ioaddr = dev->base_addr; -- GitLab From c7bec5aba52392aa8d675b8722735caf4a8b7265 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 6 Oct 2006 15:00:58 -0400 Subject: [PATCH 0739/1619] Various drivers' irq handlers: kill dead code, needless casts - Eliminate casts to/from void* - Eliminate checks for conditions that never occur. These typically fall into two classes: 1) Checking for 'dev_id == NULL', then it is never called with NULL as an argument. 2) Checking for invalid irq number, when the only caller (the system) guarantees the irq handler is called with the proper 'irq' number argument. Signed-off-by: Jeff Garzik --- drivers/atm/ambassador.c | 7 +------ drivers/atm/horizon.c | 9 --------- drivers/atm/lanai.c | 4 +--- drivers/block/DAC960.c | 14 +++++++------- drivers/cdrom/mcdx.c | 4 ---- drivers/char/rio/func.h | 2 +- drivers/char/rio/rio_linux.c | 4 ++-- drivers/char/rio/riointr.c | 2 +- drivers/char/riscom8.c | 7 +++---- drivers/char/specialix.c | 2 +- drivers/media/video/zoran_device.c | 2 +- drivers/pcmcia/at91_cf.c | 2 +- drivers/pcmcia/hd64465_ss.c | 7 +++---- drivers/scsi/NCR53c406a.c | 8 ++++---- drivers/scsi/aha152x.c | 7 +------ drivers/scsi/aic7xxx_old.c | 12 ++++++------ drivers/scsi/dc395x.c | 2 +- drivers/scsi/qlogicfas408.c | 6 +++--- drivers/scsi/tmscsim.c | 8 ++++---- drivers/scsi/ultrastor.c | 8 ++++---- drivers/serial/68360serial.c | 2 +- drivers/serial/jsm/jsm_neo.c | 2 +- drivers/serial/mpc52xx_uart.c | 10 +--------- drivers/serial/netx-serial.c | 2 +- drivers/serial/pxa.c | 2 +- drivers/sn/ioc3.c | 2 +- drivers/spi/pxa2xx_spi.c | 2 +- sound/isa/gus/gusmax.c | 2 +- sound/isa/gus/interwave.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/vwsnd.c | 2 +- sound/pci/korg1212/korg1212.c | 4 ---- 35 files changed, 59 insertions(+), 98 deletions(-) diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 8ff5c4e5082..323592de047 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -862,15 +862,10 @@ static inline void interrupts_off (amb_dev * dev) { /********** interrupt handling **********/ static irqreturn_t interrupt_handler(int irq, void *dev_id) { - amb_dev * dev = (amb_dev *) dev_id; + amb_dev * dev = dev_id; PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id); - if (!dev_id) { - PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq); - return IRQ_NONE; - } - { u32 interrupt = rd_plain (dev, offsetof(amb_mem, interrupt)); diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 33e9ee47392..f59349206dd 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -1389,15 +1389,6 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) { PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id); - if (!dev_id) { - PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq); - return IRQ_NONE; - } - if (irq != dev->irq) { - PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq); - return IRQ_NONE; - } - // definitely for us irq_ok = 0; while ((int_source = rd_regl (dev, INT_SOURCE_REG_OFF) diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 8895f026bea..267825501df 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1892,11 +1892,9 @@ static inline void lanai_int_1(struct lanai_dev *lanai, u32 reason) static irqreturn_t lanai_int(int irq, void *devid) { - struct lanai_dev *lanai = (struct lanai_dev *) devid; + struct lanai_dev *lanai = devid; u32 reason; - (void) irq; /* unused variables */ - #ifdef USE_POWERDOWN /* * If we're powered down we shouldn't be generating any interrupts - diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 3e8ab84b944..742d0740310 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -5254,7 +5254,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5295,7 +5295,7 @@ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5337,7 +5337,7 @@ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V2_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5379,7 +5379,7 @@ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5417,7 +5417,7 @@ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; DAC960_V1_StatusMailbox_T *NextStatusMailbox; unsigned long flags; @@ -5455,7 +5455,7 @@ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; unsigned long flags; @@ -5493,7 +5493,7 @@ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) { - DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + DAC960_Controller_T *Controller = DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; unsigned long flags; diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 60e1978ec0e..f574962f428 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -850,10 +850,6 @@ static irqreturn_t mcdx_intr(int irq, void *dev_id) struct s_drive_stuff *stuffp = dev_id; unsigned char b; - if (stuffp == NULL) { - xwarn("mcdx: no device for intr %d\n", irq); - return IRQ_NONE; - } #ifdef AK2 if (!stuffp->busy && stuffp->pending) stuffp->int_err = 1; diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h index 6b039186856..9e7283bd81a 100644 --- a/drivers/char/rio/func.h +++ b/drivers/char/rio/func.h @@ -88,7 +88,7 @@ void RIOHostReset(unsigned int, struct DpRam __iomem *, unsigned int); /* riointr.c */ void RIOTxEnable(char *); -void RIOServiceHost(struct rio_info *, struct Host *, int); +void RIOServiceHost(struct rio_info *, struct Host *); int riotproc(struct rio_info *, struct ttystatics *, int, int); /* rioparam.c */ diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 3bea594600d..c382df0f82f 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -368,7 +368,7 @@ static irqreturn_t rio_interrupt(int irq, void *ptr) struct Host *HostP; func_enter(); - HostP = (struct Host *) ptr; /* &p->RIOHosts[(long)ptr]; */ + HostP = ptr; /* &p->RIOHosts[(long)ptr]; */ rio_dprintk(RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec); /* AAargh! The order in which to do these things is essential and @@ -402,7 +402,7 @@ static irqreturn_t rio_interrupt(int irq, void *ptr) return IRQ_HANDLED; } - RIOServiceHost(p, HostP, irq); + RIOServiceHost(p, HostP); rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", ptr, HostP->Type); diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index 0bd09040a5c..eeda40c5e18 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -181,7 +181,7 @@ static int RupIntr; static int RxIntr; static int TxIntr; -void RIOServiceHost(struct rio_info *p, struct Host *HostP, int From) +void RIOServiceHost(struct rio_info *p, struct Host *HostP) { rio_spin_lock(&HostP->HostLock); if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index be68cfb0ae6..5ab32b38f45 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -559,11 +559,10 @@ static irqreturn_t rc_interrupt(int irq, void * dev_id) int handled = 0; bp = IRQ_to_board[irq]; - - if (!bp || !(bp->flags & RC_BOARD_ACTIVE)) { + + if (!(bp->flags & RC_BOARD_ACTIVE)) return IRQ_NONE; - } - + while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) & (RC_BSR_TOUT | RC_BSR_TINT | RC_BSR_MINT | RC_BSR_RINT))) { diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 6022495571a..d0b88d0e87f 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -912,7 +912,7 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id) spin_lock_irqsave(&bp->lock, flags); dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1); - if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) { + if (!(bp->flags & SX_BOARD_ACTIVE)) { dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq); spin_unlock_irqrestore(&bp->lock, flags); func_exit(); diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index d9d5020a222..168e431d7c7 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -1415,7 +1415,7 @@ zoran_irq (int irq, struct zoran *zr; unsigned long flags; - zr = (struct zoran *) dev_id; + zr = dev_id; count = 0; if (zr->testing) { diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 991e084db2d..7f5df9a9f39 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -66,7 +66,7 @@ static int at91_cf_ss_init(struct pcmcia_socket *s) static irqreturn_t at91_cf_irq(int irq, void *_cf) { - struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf; + struct at91_cf_socket *cf = _cf; if (irq == cf->board->det_pin) { unsigned present = at91_cf_present(cf); diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index db3c26b5de1..caca0dc9d30 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -650,7 +650,7 @@ static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) */ static int hs_irq_demux(int irq, void *dev) { - hs_socket_t *sp = (hs_socket_t *)dev; + hs_socket_t *sp = dev; u_int cscr; DPRINTK("hs_irq_demux(irq=%d)\n", irq); @@ -673,11 +673,10 @@ static int hs_irq_demux(int irq, void *dev) static irqreturn_t hs_interrupt(int irq, void *dev) { - hs_socket_t *sp = (hs_socket_t *)dev; + hs_socket_t *sp = dev; u_int events = 0; u_int cscr; - - + cscr = hs_in(sp, CSCR); DPRINTK("hs_interrupt, cscr=%04x\n", cscr); diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index 3896278594c..d4613815f68 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -168,7 +168,7 @@ enum Phase { }; /* Static function prototypes */ -static void NCR53c406a_intr(int, void *); +static void NCR53c406a_intr(void *); static irqreturn_t do_NCR53c406a_intr(int, void *); static void chip_init(void); static void calc_port_addr(void); @@ -685,7 +685,7 @@ static void wait_intr(void) return; } - NCR53c406a_intr(0, NULL, NULL); + NCR53c406a_intr(NULL); } #endif @@ -767,12 +767,12 @@ static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id) struct Scsi_Host *dev = dev_id; spin_lock_irqsave(dev->host_lock, flags); - NCR53c406a_intr(0, dev_id); + NCR53c406a_intr(dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } -static void NCR53c406a_intr(int unused, void *dev_id) +static void NCR53c406a_intr(void *dev_id) { DEB(unsigned char fifo_size; ) diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index e04c2bc1932..a0d1cee0be7 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -759,12 +759,7 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp) static irqreturn_t swintr(int irqno, void *dev_id) { - struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id; - - if (!shpnt) { - printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno); - return IRQ_NONE; - } + struct Scsi_Host *shpnt = dev_id; HOSTDATA(shpnt)->swint++; diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 7f0adf9c4c7..bcd7fffab90 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -6345,12 +6345,12 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) * SCSI controller interrupt handler. *-F*************************************************************************/ static void -aic7xxx_isr(int irq, void *dev_id) +aic7xxx_isr(void *dev_id) { struct aic7xxx_host *p; unsigned char intstat; - p = (struct aic7xxx_host *)dev_id; + p = dev_id; /* * Just a few sanity checks. Make sure that we have an int pending. @@ -6489,7 +6489,7 @@ do_aic7xxx_isr(int irq, void *dev_id) p->flags |= AHC_IN_ISR; do { - aic7xxx_isr(irq, dev_id); + aic7xxx_isr(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); + aic7xxx_isr(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); + aic7xxx_isr(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); + aic7xxx_isr(p); pause_sequencer(p); } aic7xxx_done_cmds_complete(p); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 81e3ee51d89..23f5e418ab5 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1815,7 +1815,7 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, static irqreturn_t dc395x_interrupt(int irq, void *dev_id) { - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id; + struct AdapterCtlBlk *acb = dev_id; u16 scsi_status; u8 dma_status; irqreturn_t handled = IRQ_NONE; diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 1a7de3bd796..e0725353c99 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -405,10 +405,10 @@ static unsigned int ql_pcmd(Scsi_Cmnd * cmd) * Interrupt handler */ -static void ql_ihandl(int irq, void *dev_id) +static void ql_ihandl(void *dev_id) { Scsi_Cmnd *icmd; - struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + struct Scsi_Host *host = dev_id; struct qlogicfas408_priv *priv = get_priv_by_host(host); int qbase = priv->qbase; REG0; @@ -438,7 +438,7 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) struct Scsi_Host *host = dev_id; spin_lock_irqsave(host->host_lock, flags); - ql_ihandl(irq, dev_id); + ql_ihandl(dev_id); spin_unlock_irqrestore(host->host_lock, flags); return IRQ_HANDLED; } diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 0f0ac925d31..d03aa6ce8fe 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -700,9 +700,9 @@ dc390_InvalidCmd(struct dc390_acb* pACB) static irqreturn_t __inline__ -DC390_Interrupt(int irq, void *dev_id) +DC390_Interrupt(void *dev_id) { - struct dc390_acb *pACB = (struct dc390_acb*)dev_id; + struct dc390_acb *pACB = dev_id; struct dc390_dcb *pDCB; struct dc390_srb *pSRB; u8 sstatus=0; @@ -811,12 +811,12 @@ DC390_Interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id) +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); + ret = DC390_Interrupt(dev_id); DEBUG1(printk (".. IRQ returned\n")); return ret; } diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 107f0fc3494..56906aba5ee 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -287,7 +287,7 @@ static const unsigned short ultrastor_ports_14f[] = { }; #endif -static void ultrastor_interrupt(int, void *); +static void ultrastor_interrupt(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); + ultrastor_interrupt(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) +static void ultrastor_interrupt(void *dev_id) { unsigned int status; #if ULTRASTOR_MAX_CMDS > 1 @@ -1177,7 +1177,7 @@ static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id) struct Scsi_Host *dev = dev_id; spin_lock_irqsave(dev->host_lock, flags); - ultrastor_interrupt(irq, dev_id); + ultrastor_interrupt(dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 4e56ec80386..634ecca36a7 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -620,7 +620,7 @@ static void rs_360_interrupt(int vec, void *dev_id) volatile struct smc_regs *smcp; volatile struct scc_regs *sccp; - info = (ser_info_t *)dev_id; + info = dev_id; idx = PORT_NUM(info->state->smc_scc_num); if (info->state->smc_scc_num & NUM_IS_SCC) { diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c index 8fa31e68989..8be8da37f62 100644 --- a/drivers/serial/jsm/jsm_neo.c +++ b/drivers/serial/jsm/jsm_neo.c @@ -1116,7 +1116,7 @@ static void neo_param(struct jsm_channel *ch) */ static irqreturn_t neo_intr(int irq, void *voidbrd) { - struct jsm_board *brd = (struct jsm_board *) voidbrd; + struct jsm_board *brd = voidbrd; struct jsm_channel *ch; int port = 0; int type = 0; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 039c2fd6d49..4f80c5b4a75 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -512,19 +512,11 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id) { - struct uart_port *port = (struct uart_port *) dev_id; + struct uart_port *port = dev_id; unsigned long pass = ISR_PASS_LIMIT; unsigned int keepgoing; unsigned short status; - if ( irq != port->irq ) { - printk( KERN_WARNING - "mpc52xx_uart_int : " \ - "Received wrong int %d. Waiting for %d\n", - irq, port->irq); - return IRQ_NONE; - } - spin_lock(&port->lock); /* While we have stuff to do, we continue */ diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index e92d7e1c22c..062bad457b1 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -247,7 +247,7 @@ static void netx_rxint(struct uart_port *port) static irqreturn_t netx_int(int irq, void *dev_id) { - struct uart_port *port = (struct uart_port *)dev_id; + struct uart_port *port = dev_id; unsigned long flags; unsigned char status; diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 846089f222d..415fe9633a9 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -232,7 +232,7 @@ static inline void check_modem_status(struct uart_pxa_port *up) */ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) { - struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id; + struct uart_pxa_port *up = dev_id; unsigned int iir, lsr; iir = serial_in(up, UART_IIR); diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 3d91b6b9287..cd6b65333b7 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c @@ -401,7 +401,7 @@ static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd) static irqreturn_t ioc3_intr_io(int irq, void *arg) { unsigned long flags; - struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg; + struct ioc3_driver_data *idd = arg; int handled = 1, id; unsigned int pending; diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 77122edeb20..72025df5561 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -669,7 +669,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) static irqreturn_t ssp_int(int irq, void *dev_id) { - struct driver_data *drv_data = (struct driver_data *)dev_id; + struct driver_data *drv_data = dev_id; void *reg = drv_data->ioaddr; if (!drv_data->cur_msg) { diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 52498c9d411..c1c69e3cbfd 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -107,7 +107,7 @@ static int __init snd_gusmax_detect(struct snd_gus_card * gus) static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id) { - struct snd_gusmax *maxcard = (struct snd_gusmax *) dev_id; + struct snd_gusmax *maxcard = dev_id; int loop, max = 5; int handled = 0; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 5c474b831ed..f12cd09d1fc 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -301,7 +301,7 @@ static int __devinit snd_interwave_detect(struct snd_interwave *iwcard, static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id) { - struct snd_interwave *iwcard = (struct snd_interwave *) dev_id; + struct snd_interwave *iwcard = dev_id; int loop, max = 5; int handled = 0; diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index 2562f4769b9..ddf6b0a0bca 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -1102,7 +1102,7 @@ static void es1371_handle_midi(struct es1371_state *s) static irqreturn_t es1371_interrupt(int irq, void *dev_id) { - struct es1371_state *s = (struct es1371_state *)dev_id; + struct es1371_state *s = dev_id; unsigned int intsrc, sctl; /* fastpath out, to ease interrupt sharing */ diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c index 7807abac062..784bdd70705 100644 --- a/sound/oss/hal2.c +++ b/sound/oss/hal2.c @@ -372,7 +372,7 @@ static void hal2_adc_interrupt(struct hal2_codec *adc) static irqreturn_t hal2_interrupt(int irq, void *dev_id) { - struct hal2_card *hal2 = (struct hal2_card*)dev_id; + struct hal2_card *hal2 = dev_id; irqreturn_t ret = IRQ_NONE; /* decide what caused this interrupt */ diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index a48af879b46..240cc7939b6 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -1525,7 +1525,7 @@ static void i810_channel_interrupt(struct i810_card *card) static irqreturn_t i810_interrupt(int irq, void *dev_id) { - struct i810_card *card = (struct i810_card *)dev_id; + struct i810_card *card = dev_id; u32 status; spin_lock(&card->lock); diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 58d4a5d05a2..e9622054197 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -435,7 +435,7 @@ static void mpu401_input_loop(struct mpu_config *devc) static irqreturn_t mpuintr(int irq, void *dev_id) { struct mpu_config *devc; - int dev = (int) dev_id; + int dev = (int)(unsigned long) dev_id; int handled = 0; devc = &dev_conf[dev]; diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 0cd4d6ec986..6dfb9f4b03e 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c @@ -2235,7 +2235,7 @@ static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status) static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id) { - vwsnd_dev_t *devc = (vwsnd_dev_t *) dev_id; + vwsnd_dev_t *devc = dev_id; unsigned int status; DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id); diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 398aa10a06e..fa8cd8cecc2 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1124,9 +1124,6 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) u32 doorbellValue; struct snd_korg1212 *korg1212 = dev_id; - if(irq != korg1212->irq) - return IRQ_NONE; - doorbellValue = readl(korg1212->inDoorbellPtr); if (!doorbellValue) @@ -1140,7 +1137,6 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) korg1212->inIRQ++; - switch (doorbellValue) { case K1212_DB_DSPDownloadDone: K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DNLD count - %ld, %x, [%s].\n", -- GitLab From 8f4aff6cb178b0a580ee206e7cca63e2d31f4a4e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 6 Oct 2006 15:03:04 -0400 Subject: [PATCH 0740/1619] drivers/net/eepro: kill dead code The irq2dev_map has not been used for a long time. Signed-off-by: Jeff Garzik --- drivers/net/eepro.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index fd6e97891e7..a4eb0dc99ec 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -994,16 +994,6 @@ static int eepro_open(struct net_device *dev) return -EAGAIN; } -#ifdef irq2dev_map - if (((irq2dev_map[dev->irq] != 0) - || (irq2dev_map[dev->irq] = dev) == 0) && - (irq2dev_map[dev->irq]!=dev)) { - /* printk("%s: IRQ map wrong\n", dev->name); */ - free_irq(dev->irq, dev); - return -EAGAIN; - } -#endif - /* Initialize the 82595. */ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ @@ -1282,10 +1272,6 @@ static int eepro_close(struct net_device *dev) /* release the interrupt */ free_irq(dev->irq, dev); -#ifdef irq2dev_map - irq2dev_map[dev->irq] = 0; -#endif - /* Update the statistics here. What statistics? */ return 0; -- GitLab From d87dbede030d17770aa6a6170e70ab6f8044e5ae Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 6 Oct 2006 15:04:35 -0400 Subject: [PATCH 0741/1619] drivers/isdn/act2000: kill irq2card_map Eliminate irq->card lookup table, by properly passing the card pointer via request_irq() like other drivers. Signed-off-by: Jeff Garzik --- drivers/isdn/act2000/act2000_isa.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c index 3014495b7ff..3cac2373934 100644 --- a/drivers/isdn/act2000/act2000_isa.c +++ b/drivers/isdn/act2000/act2000_isa.c @@ -16,8 +16,6 @@ #include "act2000_isa.h" #include "capi.h" -static act2000_card *irq2card_map[16]; - /* * Reset Controller, then try to read the Card's signature. + Return: @@ -65,14 +63,9 @@ act2000_isa_detect(unsigned short portbase) static irqreturn_t act2000_isa_interrupt(int irq, void *dev_id) { - act2000_card *card = irq2card_map[irq]; + act2000_card *card = dev_id; u_char istatus; - if (!card) { - printk(KERN_WARNING - "act2000: Spurious interrupt!\n"); - return IRQ_NONE; - } istatus = (inb(ISA_PORT_ISR) & 0x07); if (istatus & ISA_ISR_OUT) { /* RX fifo has data */ @@ -139,17 +132,15 @@ int act2000_isa_config_irq(act2000_card * card, short irq) { if (card->flags & ACT2000_FLAGS_IVALID) { - free_irq(card->irq, NULL); - irq2card_map[card->irq] = NULL; + free_irq(card->irq, card); } card->flags &= ~ACT2000_FLAGS_IVALID; outb(ISA_COR_IRQOFF, ISA_PORT_COR); if (!irq) return 0; - if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) { + if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) { card->irq = irq; - irq2card_map[card->irq] = card; card->flags |= ACT2000_FLAGS_IVALID; printk(KERN_WARNING "act2000: Could not request irq %d\n",irq); @@ -188,10 +179,9 @@ act2000_isa_release(act2000_card * card) unsigned long flags; spin_lock_irqsave(&card->lock, flags); - if (card->flags & ACT2000_FLAGS_IVALID) { - free_irq(card->irq, NULL); - irq2card_map[card->irq] = NULL; - } + if (card->flags & ACT2000_FLAGS_IVALID) + free_irq(card->irq, card); + card->flags &= ~ACT2000_FLAGS_IVALID; if (card->flags & ACT2000_FLAGS_PVALID) release_region(card->port, ISA_REGION); -- GitLab From b7696ee3c050a76a6cebccdbadfc93896b336e44 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 6 Oct 2006 20:53:10 +0200 Subject: [PATCH 0742/1619] [PATCH] fix mesh compile errors after irq changes drivers/scsi/mesh.c:469: error: too many arguments to function 'mesh_interrupt' drivers/scsi/mesh.c:507: error: too many arguments to function 'mesh_interrupt' Signed-off-by: Olaf Hering Signed-off-by: Linus Torvalds --- drivers/scsi/mesh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index c773e35dace..1fd3c7590d3 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x", MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - mesh_interrupt(0, (void *)ms, NULL); + mesh_interrupt(0, (void *)ms); if (ms->phase != arbitrating) return; } @@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x", MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - mesh_interrupt(0, (void *)ms, NULL); + mesh_interrupt(0, (void *)ms); if (ms->phase != arbitrating) return; dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x", -- GitLab From e317c8ccaaf900abf39cc3240e4dc5ba82a3cc67 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Fri, 6 Oct 2006 18:58:24 +0000 Subject: [PATCH 0743/1619] [PATCH] ixp4xxdefconfig arm fixes With the following patch, the ixp4xxdefconfig builds correctly. I'll test some more configs if I get some time. Signed-off-by: Frederik Deweerdt Signed-off-by: Linus Torvalds --- arch/arm/kernel/time.c | 3 ++- kernel/irq/resend.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index b094e3e8198..c03cab5c4c7 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -327,7 +328,7 @@ EXPORT_SYMBOL(restore_time_delta); void timer_tick(void) { struct pt_regs *regs = get_irq_regs(); - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); do_leds(); do_set_rtc(); do_timer(1); diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 35f10f7ff94..5bfeaed7e48 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -38,7 +38,7 @@ static void resend_irqs(unsigned long arg) clear_bit(irq, irqs_resend); desc = irq_desc + irq; local_irq_disable(); - desc->handle_irq(irq, desc, NULL); + desc->handle_irq(irq, desc); local_irq_enable(); } } -- GitLab From e630015504cdd4d166c371fec39b8ca258fcbc0e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 6 Oct 2006 13:11:15 -0700 Subject: [PATCH 0744/1619] ARM: fix up nested irq regs usage This should fix up the per-cpu irq register pointer if we have nested hardware interrupts. Signed-off-by: Linus Torvalds --- arch/arm/kernel/irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index e999b11de2c..2c4ff1cbe33 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -111,6 +111,7 @@ static struct irq_desc bad_irq_desc = { */ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); struct irqdesc *desc = irq_desc + irq; /* @@ -122,13 +123,13 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) irq_enter(); - set_irq_regs(regs); desc_handle_irq(irq, desc); /* AT91 specific workaround */ irq_finish(irq); irq_exit(); + set_irq_regs(old_regs); } void set_irq_flags(unsigned int irq, unsigned int iflags) -- GitLab From d150ad7bd946f066c98a9725685109dcffae0cba Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 6 Oct 2006 13:28:09 -0700 Subject: [PATCH 0745/1619] [PATCH] x86_64 irq_regs fix smp_apic_timer_interrupt() needs to stack the pt_regs* for profile_tick. If any other of those APIC interrupt handlers want to run get_irq_regs() then their C entrypoint handlers will need the same treatment. Cc: Andi Kleen Cc: David Howells Signed-off-by: Andrew Morton Acked-by: Andrew Vasquez Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/apic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index af4a1c71a80..4d9d5ed942b 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -913,8 +913,10 @@ void smp_local_timer_interrupt(void) * [ 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(void) +void smp_apic_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); + /* * the NMI deadlock-detector uses this. */ @@ -934,6 +936,7 @@ void smp_apic_timer_interrupt(void) irq_enter(); smp_local_timer_interrupt(); irq_exit(); + set_irq_regs(old_regs); } /* -- GitLab From 268f3be177ce93791da38facc34126b5038cd851 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 6 Oct 2006 21:47:09 +0000 Subject: [PATCH 0746/1619] [CIFS] readdir (ffirst) enablement of accurate timestamps from legacy servers Signed-off-by: Steve French --- fs/cifs/netmisc.c | 39 ++++++++++++++++++--------------------- fs/cifs/readdir.c | 18 +++++++++--------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index fa5124d9af1..3d86b31cf2e 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -918,45 +918,42 @@ __le64 cnvrtDosCifsTm(__u16 date, __u16 time) { return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time))); } + struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) { - __u8 dt[2]; - __u8 tm[2]; struct timespec ts; - int sec,min, days, month, year; - struct timespec removeme; /* BB removeme BB */ -/* SMB_TIME * st = (SMB_TIME *)&time;*/ + int sec, min, days, month, year; + SMB_TIME * st = (SMB_TIME *)&time; + SMB_DATE * sd = (SMB_DATE *)&date; cFYI(1,("date %d time %d",date, time)); - dt[0] = date & 0xFF; - dt[1] = (date & 0xFF00) >> 8; - tm[0] = time & 0xFF; - tm[1] = (time & 0xFF00) >> 8; - - sec = tm[0] & 0x1F; - sec = 2 * sec; - min = ((tm[0] >>5)&0xFF) + ((tm[1] & 0x7)<<3); - + sec = 2 * st->TwoSeconds; + min = st->Minutes; + if((sec > 59) || (min > 59)) + cERROR(1,("illegal time min %d sec %d", min, sec)); sec += (min * 60); - sec += 60 * 60 * ((tm[1] >> 3) &0xFF) /* hours */; - days = (dt[0] & 0x1F) - 1; - month = ((dt[0] >> 5) & 0xFF) + ((dt[1] & 0x1) <<3); - if(month > 12) - cERROR(1,("illegal month %d in date", month)); + sec += 60 * 60 * st->Hours; + if(st->Hours > 24) + cERROR(1,("illegal hours %d",st->Hours)); + days = sd->Day; + month = sd->Month; + if((days > 31) || (month > 12)) + cERROR(1,("illegal date, month %d day: %d", month, days)); month -= 1; days += total_days_of_prev_months[month]; days += 3653; /* account for difference in days between 1980 and 1970 */ - year = (dt[1]>>1) & 0xFF; + year = sd->Year; days += year * 365; days += (year/4); /* leap year */ /* adjust for leap year where we are still before leap day */ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); sec += 24 * 60 * 60 * days; - removeme = CURRENT_TIME; /* BB removeme BB */ ts.tv_sec = sec; + /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */ + ts.tv_nsec = 0; return ts; } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b0e5db10664..81e7b2e5fb4 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -139,19 +139,19 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, FIND_FILE_STANDARD_INFO * pfindData = (FIND_FILE_STANDARD_INFO *)buf; -/* ts = cnvrtDosUnixTm( + tmp_inode->i_mtime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastWriteDate), - le16_to_cpu(pfindData->LastWriteTime));*/ + le16_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_atime = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastAccessDate), + le16_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_ctime = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastWriteDate), + le16_to_cpu(pfindData->LastWriteTime)); + attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); - /* do not need to use current_fs_time helper function since - time not stored for this case so atime can not "go backwards" - by pulling newer older from disk when inode refrenshed */ - tmp_inode->i_atime = CURRENT_TIME; - /* tmp_inode->i_mtime = BB FIXME - add dos time handling - tmp_inode->i_ctime = 0; BB FIXME */ - } /* Linux can not store file creation time unfortunately so ignore it */ -- GitLab From 2b00b254debd707571f20149dbd4b45264a120e5 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 5 Oct 2006 21:16:48 -0500 Subject: [PATCH 0747/1619] [POWERPC] Fix fsl_soc build breaks Hrm, there's no way this ever built at time of merge. There's a missing } and the wrong type on phy_irq. Also, another const for get_property(). CC arch/powerpc/sysdev/fsl_soc.o arch/powerpc/sysdev/fsl_soc.c: In function 'fs_enet_of_init': arch/powerpc/sysdev/fsl_soc.c:625: error: assignment of read-only variable 'phy_irq' arch/powerpc/sysdev/fsl_soc.c:625: warning: assignment makes integer from pointer without a cast arch/powerpc/sysdev/fsl_soc.c:661: warning: assignment discards qualifiers from pointer target type arch/powerpc/sysdev/fsl_soc.c:684: error: subscripted value is neither array nor pointer arch/powerpc/sysdev/fsl_soc.c:687: error: subscripted value is neither array nor pointer arch/powerpc/sysdev/fsl_soc.c:722: warning: ISO C90 forbids mixed declarations and code arch/powerpc/sysdev/fsl_soc.c:728: error: invalid storage class for function 'cpm_uart_of_init' arch/powerpc/sysdev/fsl_soc.c:798: error: initializer element is not constant arch/powerpc/sysdev/fsl_soc.c:798: error: expected declaration or statement at end of input make[1]: *** [arch/powerpc/sysdev/fsl_soc.o] Error 1 Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/fsl_soc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 7d759f1c26b..dbe92ae2033 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -567,7 +567,7 @@ static int __init fs_enet_of_init(void) struct resource r[4]; struct device_node *phy, *mdio; struct fs_platform_info fs_enet_data; - const unsigned int *id, *phy_addr, phy_irq; + const unsigned int *id, *phy_addr, *phy_irq; const void *mac_addr; const phandle *ph; const char *model; @@ -641,7 +641,7 @@ static int __init fs_enet_of_init(void) if (strstr(model, "FCC")) { int fcc_index = *id - 1; - unsigned char* mdio_bb_prop; + const unsigned char *mdio_bb_prop; fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); fs_enet_data.rx_ring = 32; @@ -708,8 +708,9 @@ static int __init fs_enet_of_init(void) ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, sizeof(struct fs_platform_info)); - if (ret) - goto unreg; + if (ret) + goto unreg; + } } return 0; -- GitLab From b75f3f751c17e01544bd6706e54efae35d66d446 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 6 Oct 2006 13:53:12 +1000 Subject: [PATCH 0748/1619] [POWERPC] Update iseries_defconfig This make sure that an iseries_defconfig does not inlude other platforms. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/configs/iseries_defconfig | 86 +++++++++++++++++++++----- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig index d58f82f836f..b5005506c2f 100644 --- a/arch/powerpc/configs/iseries_defconfig +++ b/arch/powerpc/configs/iseries_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc6 -# Sun Sep 10 10:22:57 2006 +# Linux kernel version: 2.6.19-rc1 +# Fri Oct 6 13:25:04 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_PPC_OF=y # CONFIG_PPC_UDBG_16550 is not set # CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y # CONFIG_DEFAULT_UIMAGE is not set # @@ -52,10 +53,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -CONFIG_SYSCTL=y +# CONFIG_UTS_NS is not set CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y CONFIG_IKCONFIG=y @@ -64,7 +66,9 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -73,12 +77,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -97,6 +101,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_BLK_DEV_IO_TRACE is not set # @@ -115,13 +120,18 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # Platform support # -# CONFIG_PPC_MULTIPLATFORM is not set -CONFIG_PPC_ISERIES=y +CONFIG_PPC_MULTIPLATFORM=y # CONFIG_EMBEDDED6xx is not set # CONFIG_APUS is not set +# CONFIG_PPC_PSERIES is not set +CONFIG_PPC_ISERIES=y +# CONFIG_PPC_PMAC is not set +# CONFIG_PPC_MAPLE is not set +# CONFIG_PPC_PASEMI is not set # CONFIG_PPC_CELL is not set # CONFIG_PPC_CELL_NATIVE is not set -# CONFIG_UDBG_RTAS_CONSOLE is not set +# CONFIG_PPC_IBM_CELL_BLADE is not set +# CONFIG_U3_DART is not set # CONFIG_PPC_RTAS is not set # CONFIG_MMIO_NVRAM is not set CONFIG_IBMVIO=y @@ -147,12 +157,15 @@ CONFIG_BINFMT_ELF=y CONFIG_FORCE_MAX_ZONEORDER=13 CONFIG_IOMMU_VMERGE=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set CONFIG_IRQ_ALL_CPUS=y CONFIG_LPARCFG=y # CONFIG_NUMA is not set CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -179,6 +192,7 @@ CONFIG_GENERIC_ISA_DMA=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # @@ -206,6 +220,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y CONFIG_XFRM_USER=m +CONFIG_XFRM_SUB_POLICY=y CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -224,10 +239,12 @@ CONFIG_INET_XFRM_TUNNEL=m CONFIG_INET_TUNNEL=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=m CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # # IP: Virtual Server Configuration @@ -247,6 +264,7 @@ CONFIG_NETFILTER=y CONFIG_NETFILTER_XTABLES=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m CONFIG_NETFILTER_XT_TARGET_NOTRACK=m @@ -255,6 +273,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m # CONFIG_NETFILTER_XT_MATCH_DCCP is not set +CONFIG_NETFILTER_XT_MATCH_DSCP=m # CONFIG_NETFILTER_XT_MATCH_ESP is not set CONFIG_NETFILTER_XT_MATCH_HELPER=m CONFIG_NETFILTER_XT_MATCH_LENGTH=m @@ -294,7 +313,6 @@ CONFIG_IP_NF_MATCH_IPRANGE=m CONFIG_IP_NF_MATCH_TOS=m CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m # CONFIG_IP_NF_MATCH_AH is not set CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_OWNER=m @@ -319,7 +337,6 @@ CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_RAW=m @@ -351,7 +368,6 @@ CONFIG_LLC=y # 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 @@ -433,6 +449,7 @@ CONFIG_BLK_DEV_INITRD=y # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -454,12 +471,14 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_LIBSAS_DEBUG=y # # SCSI low-level drivers @@ -472,10 +491,11 @@ CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set -# CONFIG_ATA is not set # CONFIG_SCSI_HPTIOP is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set @@ -486,15 +506,21 @@ CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_IBMVSCSI=m # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + # # Multi-device support (RAID and LVM) # @@ -508,6 +534,7 @@ CONFIG_MD_RAID10=m CONFIG_MD_MULTIPATH=m CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m @@ -573,6 +600,7 @@ CONFIG_MII=y # CONFIG_HP100 is not set CONFIG_NET_PCI=y CONFIG_PCNET32=y +CONFIG_PCNET32_NAPI=y # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set @@ -610,6 +638,7 @@ CONFIG_E1000=m # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -649,6 +678,7 @@ CONFIG_PPP_BSDCOMP=m # CONFIG_PPP_MPPE is not set CONFIG_PPPOE=m # CONFIG_SLIP is not set +CONFIG_SLHC=m # CONFIG_NET_FC is not set # CONFIG_SHAPER is not set CONFIG_NETCONSOLE=y @@ -671,6 +701,7 @@ CONFIG_NET_POLL_CONTROLLER=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -774,12 +805,12 @@ CONFIG_MAX_RAW_DEVS=256 # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -893,6 +924,9 @@ CONFIG_XFS_FS=m CONFIG_XFS_SECURITY=y CONFIG_XFS_POSIX_ACL=y # CONFIG_XFS_RT is not set +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GFS2_FS_LOCKING_DLM=m # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -929,12 +963,14 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set +CONFIG_CONFIGFS_FS=m # # Miscellaneous filesystems @@ -988,6 +1024,7 @@ CONFIG_CIFS_POSIX=y # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # CONFIG_9P_FS is not set +CONFIG_GENERIC_ACL=y # # Partition Types @@ -1039,6 +1076,12 @@ CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set +# +# Distributed Lock Manager +# +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set + # # iSeries device drivers # @@ -1073,6 +1116,7 @@ CONFIG_PLIST=y # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y @@ -1091,6 +1135,7 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FORCED_INLINING is not set # CONFIG_RCU_TORTURE_TEST is not set CONFIG_DEBUG_STACKOVERFLOW=y @@ -1109,6 +1154,10 @@ CONFIG_IRQSTACKS=y # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_MD4=m @@ -1118,9 +1167,12 @@ CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m -- GitLab From 27db2d0cb9b56210dc1e29bc89a7413f3ae67b91 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 6 Oct 2006 13:54:28 +1000 Subject: [PATCH 0749/1619] [POWERPC] Fix viocons for irq breakage Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/char/viocons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index a362ee9c92d..6d2e314860d 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -947,7 +947,7 @@ static void vioHandleData(struct HvLpEvent *event) */ continue; } else if (vio_sysrq_pressed) { - handle_sysrq(cevent->data[index], NULL, tty); + handle_sysrq(cevent->data[index], tty); vio_sysrq_pressed = 0; /* * continue because we don't want to add -- GitLab From 1224f373c974eacc46fe5e1073422c794d0b0d34 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 6 Oct 2006 13:55:26 +1000 Subject: [PATCH 0750/1619] [POWERPC] Fix iseries/smp.c for irq breakage Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/irq.c | 7 ++----- arch/powerpc/platforms/iseries/smp.c | 6 ++++-- arch/powerpc/platforms/iseries/smp.h | 6 ++++++ 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/smp.h diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index e32446877e7..44c245672dd 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -43,10 +43,7 @@ #include "irq.h" #include "pci.h" #include "call_pci.h" - -#if defined(CONFIG_SMP) -extern void iSeries_smp_message_recv(struct pt_regs *); -#endif +#include "smp.h" #ifdef CONFIG_PCI @@ -315,7 +312,7 @@ unsigned int iSeries_get_irq(struct pt_regs *regs) #ifdef CONFIG_SMP if (get_lppaca()->int_dword.fields.ipi_cnt) { get_lppaca()->int_dword.fields.ipi_cnt = 0; - iSeries_smp_message_recv(regs); + iSeries_smp_message_recv(); } #endif /* CONFIG_SMP */ if (hvlpevent_is_pending()) diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 2eb095edb47..aee5908df70 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -43,9 +43,11 @@ #include #include +#include "smp.h" + static unsigned long iSeries_smp_message[NR_CPUS]; -void iSeries_smp_message_recv(struct pt_regs *regs) +void iSeries_smp_message_recv(void) { int cpu = smp_processor_id(); int msg; @@ -55,7 +57,7 @@ void iSeries_smp_message_recv(struct pt_regs *regs) for (msg = 0; msg < 4; msg++) if (test_and_clear_bit(msg, &iSeries_smp_message[cpu])) - smp_message_recv(msg, regs); + smp_message_recv(msg); } static inline void smp_iSeries_do_message(int cpu, int msg) diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h new file mode 100644 index 00000000000..d501f7de01e --- /dev/null +++ b/arch/powerpc/platforms/iseries/smp.h @@ -0,0 +1,6 @@ +#ifndef _PLATFORMS_ISERIES_SMP_H +#define _PLATFORMS_ISERIES_SMP_H + +extern void iSeries_smp_message_recv(void); + +#endif /* _PLATFORMS_ISERIES_SMP_H */ -- GitLab From be577a5220b25e0a6e3fbf96bbfc8b31d63e9ea9 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 6 Oct 2006 20:47:23 -0600 Subject: [PATCH 0751/1619] Build fixes for struct pt_regs removal Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/irq.c | 6 +++--- arch/parisc/kernel/time.c | 2 +- drivers/input/keyboard/hil_kbd.c | 2 +- drivers/input/mouse/hil_ptr.c | 2 +- drivers/input/serio/gscps2.c | 4 ++-- drivers/input/serio/hil_mlc.c | 32 ++++++++++++++++---------------- drivers/net/lasi_82596.c | 2 +- drivers/parisc/dino.c | 2 +- drivers/parisc/eisa.c | 2 +- drivers/serial/mux.c | 2 +- include/asm-parisc/irq_regs.h | 1 + 11 files changed, 29 insertions(+), 28 deletions(-) create mode 100644 include/asm-parisc/irq_regs.h diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 9bdd0197ceb..2ece7c7939f 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -35,8 +35,8 @@ #undef PARISC_IRQ_CR16_COUNTS -extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); -extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); +extern irqreturn_t timer_interrupt(int, void *); +extern irqreturn_t ipi_interrupt(int, void *); #define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq)) @@ -375,7 +375,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) goto set_out; } #endif - __do_IRQ(irq, regs); + __do_IRQ(irq); out: irq_exit(); diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 1d58ce0e37a..b44839203e6 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -66,7 +66,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* gcc can optimize for "read-only" case with a local clocktick */ unsigned long cpt = clocktick; - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); /* Initialize next_tick to the expected tick time. */ next_tick = cpu_data[cpu].it_value; diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index c9b0b8978cd..e774dd31e99 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -328,7 +328,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) kbd->dev->id.vendor = PCI_VENDOR_ID_HP; kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ - kbd->dev->dev = &serio->dev; + kbd->dev->cdev.dev = &serio->dev; for (i = 0; i < 128; i++) { set_bit(hil_kbd_set1[i], kbd->dev->keybit); diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index 402b057e986..4f2b503c1ac 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -375,7 +375,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) ptr->dev->id.vendor = PCI_VENDOR_ID_HP; ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */ ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */ - ptr->dev->dev = &serio->dev; + ptr->dev->cdev.dev = &serio->dev; input_register_device(ptr->dev); printk(KERN_INFO "input: %s (%s), ID: %d\n", diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 081fdc3c773..74f14e09778 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -166,7 +166,7 @@ static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) /* make sure any received data is returned as fast as possible */ /* this is important e.g. when we set the LEDs on the keyboard */ - gscps2_interrupt(0, NULL, NULL); + gscps2_interrupt(0, NULL); return 1; } @@ -306,7 +306,7 @@ static int gscps2_open(struct serio *port) /* enable it */ gscps2_enable(ps2port, ENABLE); - gscps2_interrupt(0, NULL, NULL); + gscps2_interrupt(0, NULL); return 0; } diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index bbbe15e2190..bdfde046b74 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -162,10 +162,10 @@ static void hil_mlc_send_polls(hil_mlc *mlc) { if (did != (p & HIL_PKT_ADDR_MASK) >> 8) { if (drv == NULL || drv->interrupt == NULL) goto skip; - drv->interrupt(serio, 0, 0, NULL); - drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); - drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); - drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL); + drv->interrupt(serio, 0, 0); + drv->interrupt(serio, HIL_ERR_INT >> 16, 0); + drv->interrupt(serio, HIL_PKT_CMD >> 8, 0); + drv->interrupt(serio, HIL_CMD_POL + cnt, 0); skip: did = (p & HIL_PKT_ADDR_MASK) >> 8; serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL; @@ -174,10 +174,10 @@ static void hil_mlc_send_polls(hil_mlc *mlc) { } cnt++; i++; if (drv == NULL || drv->interrupt == NULL) continue; - drv->interrupt(serio, (p >> 24), 0, NULL); - drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL); - drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL); - drv->interrupt(serio, p & 0xff, 0, NULL); + drv->interrupt(serio, (p >> 24), 0); + drv->interrupt(serio, (p >> 16) & 0xff, 0); + drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0); + drv->interrupt(serio, p & 0xff, 0); } } @@ -780,16 +780,16 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) { while ((last != idx) && (*last == 0)) last--; while (idx != last) { - drv->interrupt(serio, 0, 0, NULL); - drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); - drv->interrupt(serio, 0, 0, NULL); - drv->interrupt(serio, *idx, 0, NULL); + drv->interrupt(serio, 0, 0); + drv->interrupt(serio, HIL_ERR_INT >> 16, 0); + drv->interrupt(serio, 0, 0); + drv->interrupt(serio, *idx, 0); idx++; } - drv->interrupt(serio, 0, 0, NULL); - drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); - drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); - drv->interrupt(serio, *idx, 0, NULL); + drv->interrupt(serio, 0, 0); + drv->interrupt(serio, HIL_ERR_INT >> 16, 0); + drv->interrupt(serio, HIL_PKT_CMD >> 8, 0); + drv->interrupt(serio, *idx, 0); mlc->serio_oidx[map->didx] = 0; mlc->serio_opacket[map->didx] = 0; diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 8cbd940f0ac..f4d815bca64 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1252,7 +1252,7 @@ static int __devinit i82596_probe(struct net_device *dev, static void i596_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - i596_interrupt(dev->irq, dev, NULL); + i596_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index a0a8fd8d212..03c763c2d0e 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -389,7 +389,7 @@ ilr_again: int irq = dino_dev->global_irq[local_irq]; DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", __FUNCTION__, irq, intr_dev, mask); - __do_IRQ(irq, regs); + __do_IRQ(irq); mask &= ~(1 << local_irq); } while (mask); diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 094562e044f..e97cecbc4d1 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -234,7 +234,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev) } spin_unlock_irqrestore(&eisa_irq_lock, flags); - __do_IRQ(irq, regs); + __do_IRQ(irq); spin_lock_irqsave(&eisa_irq_lock, flags); /* unmask */ diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index aa819d3f8ee..8ad1b8c5ec5 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -230,7 +230,7 @@ static void mux_read(struct uart_port *port) continue; } - if (uart_handle_sysrq_char(port, data & 0xffu, NULL)) + if (uart_handle_sysrq_char(port, data & 0xffu)) continue; tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); diff --git a/include/asm-parisc/irq_regs.h b/include/asm-parisc/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-parisc/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From e11e30a063b515e95fb590f1558b5fea21273c63 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sat, 7 Oct 2006 05:11:07 -0600 Subject: [PATCH 0752/1619] [PARISC] Use set_irq_regs Actually set the irq_regs pointer. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/irq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 2ece7c7939f..b39c5b9aff4 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -347,12 +347,14 @@ static inline int eirr_to_irq(unsigned long eirr) /* ONLY called from entry.S:intr_extint() */ void do_cpu_irq_mask(struct pt_regs *regs) { + struct pt_regs *old_regs; unsigned long eirr_val; int irq, cpu = smp_processor_id(); #ifdef CONFIG_SMP cpumask_t dest; #endif + old_regs = set_irq_regs(regs); local_irq_disable(); irq_enter(); @@ -379,6 +381,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) out: irq_exit(); + set_irq_regs(old_regs); return; set_out: -- GitLab From ba0e427f215b1c58881a737f46d30ae03b83178c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 4 Oct 2006 22:57:28 -0600 Subject: [PATCH 0753/1619] [PA-RISC] Fix boot breakage Conditionals were the wrong way around. Turns out I was booting the wrong kernel when testing the original fix. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/drivers.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 2b257e4f17d..d6c486e9501 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -424,7 +424,7 @@ struct parisc_device * create_tree_node(char id, struct device *parent) /* make the generic dma mask a pointer to the parisc one */ dev->dev.dma_mask = &dev->dma_mask; dev->dev.coherent_dma_mask = dev->dma_mask; - if (!device_register(&dev->dev)) { + if (device_register(&dev->dev)) { kfree(dev); return NULL; } @@ -853,9 +853,9 @@ static void print_parisc_device(struct parisc_device *dev) */ void init_parisc_bus(void) { - if (!bus_register(&parisc_bus_type)) + if (bus_register(&parisc_bus_type)) panic("Could not register PA-RISC bus type\n"); - if (!device_register(&root)) + if (device_register(&root)) panic("Could not register PA-RISC root device\n"); get_device(&root); } -- GitLab From 09690b18b7b9696bb719b246e77c7af9952da12c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 5 Oct 2006 23:45:45 -0400 Subject: [PATCH 0754/1619] [PARISC] Make firmware calls irqsafe-ish... There's no reason why we shouldn't be using _irqsave instead of _irq for any of these calls. fwiw, this fixes the "start_kernel(): bug: interrupts were enabled early" message displayed on bootup recently. Signed-off-by: Kyle McMartin Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/firmware.c | 250 +++++++++++++++++++++------------- arch/parisc/kernel/time.c | 8 +- 2 files changed, 159 insertions(+), 99 deletions(-) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index c2531ae032c..9158b707c0d 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -160,13 +160,14 @@ void __init set_firmware_width(void) { #ifdef __LP64__ int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0); convert_to_wide(pdc_result); if(pdc_result[0] != NARROW_FIRMWARE) parisc_narrow_firmware = 0; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); #endif } @@ -196,10 +197,11 @@ void pdc_emergency_unlock(void) int pdc_add_valid(unsigned long address) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -216,15 +218,16 @@ EXPORT_SYMBOL(pdc_add_valid); int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); memcpy(&pdc_result, chassis_info, sizeof(*chassis_info)); memcpy(&pdc_result2, led_info, len); retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO, __pa(pdc_result), __pa(pdc_result2), len); memcpy(chassis_info, pdc_result, sizeof(*chassis_info)); memcpy(led_info, pdc_result2, len); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -239,13 +242,14 @@ int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_inf int pdc_pat_chassis_send_log(unsigned long state, unsigned long data) { int retval = 0; + unsigned long flags; if (!is_pdc_pat()) return -1; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -258,10 +262,11 @@ int pdc_pat_chassis_send_log(unsigned long state, unsigned long data) int pdc_chassis_disp(unsigned long disp) { int retval = 0; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -273,11 +278,12 @@ int pdc_chassis_disp(unsigned long disp) int pdc_chassis_warn(unsigned long *warn) { int retval = 0; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result)); *warn = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -292,15 +298,16 @@ int pdc_chassis_warn(unsigned long *warn) int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result)); convert_to_wide(pdc_result); pdc_coproc_info->ccr_functional = pdc_result[0]; pdc_coproc_info->ccr_present = pdc_result[1]; pdc_coproc_info->revision = pdc_result[17]; pdc_coproc_info->model = pdc_result[18]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -320,14 +327,15 @@ int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index, void *iodc_data, unsigned int iodc_data_size) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa, index, __pa(pdc_result2), iodc_data_size); convert_to_wide(pdc_result); *actcnt = pdc_result[0]; memcpy(iodc_data, pdc_result2, iodc_data_size); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -346,14 +354,15 @@ int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info, struct pdc_module_path *mod_path, long mod_index) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result), __pa(pdc_result2), mod_index); convert_to_wide(pdc_result); memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info)); memcpy(mod_path, pdc_result2, sizeof(*mod_path)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr); return retval; @@ -372,13 +381,14 @@ int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, long mod_index, long addr_index) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result), mod_index, addr_index); convert_to_wide(pdc_result); memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr); return retval; @@ -393,12 +403,13 @@ int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, int pdc_model_info(struct pdc_model *model) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0); convert_to_wide(pdc_result); memcpy(model, pdc_result, sizeof(*model)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -414,8 +425,9 @@ int pdc_model_info(struct pdc_model *model) int pdc_model_sysmodel(char *name) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result), OS_ID_HPUX, __pa(name)); convert_to_wide(pdc_result); @@ -425,7 +437,7 @@ int pdc_model_sysmodel(char *name) } else { name[0] = 0; } - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -443,12 +455,13 @@ int pdc_model_sysmodel(char *name) int pdc_model_versions(unsigned long *versions, int id) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id); convert_to_wide(pdc_result); *versions = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -463,13 +476,14 @@ int pdc_model_versions(unsigned long *versions, int id) int pdc_model_cpuid(unsigned long *cpu_id) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); pdc_result[0] = 0; /* preset zero (call may not be implemented!) */ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0); convert_to_wide(pdc_result); *cpu_id = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -484,13 +498,14 @@ int pdc_model_cpuid(unsigned long *cpu_id) int pdc_model_capabilities(unsigned long *capabilities) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); pdc_result[0] = 0; /* preset zero (call may not be implemented!) */ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0); convert_to_wide(pdc_result); *capabilities = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -504,12 +519,13 @@ int pdc_model_capabilities(unsigned long *capabilities) int pdc_cache_info(struct pdc_cache_info *cache_info) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0); convert_to_wide(pdc_result); memcpy(cache_info, pdc_result, sizeof(*cache_info)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -523,13 +539,14 @@ int pdc_cache_info(struct pdc_cache_info *cache_info) int pdc_spaceid_bits(unsigned long *space_bits) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); pdc_result[0] = 0; retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0); convert_to_wide(pdc_result); *space_bits = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -544,11 +561,12 @@ int pdc_spaceid_bits(unsigned long *space_bits) int pdc_btlb_info(struct pdc_btlb_info *btlb) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0); memcpy(btlb, pdc_result, sizeof(*btlb)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); if(retval < 0) { btlb->max_size = 0; @@ -572,13 +590,14 @@ int pdc_mem_map_hpa(struct pdc_memory_map *address, struct pdc_module_path *mod_path) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); memcpy(pdc_result2, mod_path, sizeof(*mod_path)); retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result), __pa(pdc_result2)); memcpy(address, pdc_result, sizeof(*address)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -594,8 +613,9 @@ int pdc_mem_map_hpa(struct pdc_memory_map *address, int pdc_lan_station_id(char *lan_addr, unsigned long hpa) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ, __pa(pdc_result), hpa); if (retval < 0) { @@ -604,7 +624,7 @@ int pdc_lan_station_id(char *lan_addr, unsigned long hpa) } else { memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE); } - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -623,13 +643,14 @@ EXPORT_SYMBOL(pdc_lan_station_id); int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_READ, staddr, __pa(pdc_result), count); convert_to_wide(pdc_result); memcpy(memaddr, pdc_result, count); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -648,13 +669,14 @@ EXPORT_SYMBOL(pdc_stable_read); int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); memcpy(pdc_result, memaddr, count); convert_to_wide(pdc_result); retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_WRITE, staddr, __pa(pdc_result), count); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -672,11 +694,12 @@ EXPORT_SYMBOL(pdc_stable_write); int pdc_stable_get_size(unsigned long *size) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_RETURN_SIZE, __pa(pdc_result)); *size = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -691,10 +714,11 @@ EXPORT_SYMBOL(pdc_stable_get_size); int pdc_stable_verify_contents(void) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_VERIFY_CONTENTS); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -709,10 +733,11 @@ EXPORT_SYMBOL(pdc_stable_verify_contents); int pdc_stable_initialize(void) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_INITIALIZE); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -735,8 +760,9 @@ EXPORT_SYMBOL(pdc_stable_initialize); int pdc_get_initiator(struct hardware_path *hwpath, struct pdc_initiator *initiator) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); /* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */ #define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \ @@ -776,7 +802,8 @@ int pdc_get_initiator(struct hardware_path *hwpath, struct pdc_initiator *initia } out: - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); + return (retval >= PDC_OK); } EXPORT_SYMBOL(pdc_get_initiator); @@ -794,13 +821,14 @@ EXPORT_SYMBOL(pdc_get_initiator); int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE, __pa(pdc_result), hpa); convert_to_wide(pdc_result); *num_entries = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -817,14 +845,15 @@ int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa) int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl) { int retval; + unsigned long flags; BUG_ON((unsigned long)tbl & 0x7); - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); pdc_result[0] = num_entries; retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, __pa(pdc_result), hpa, __pa(tbl)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -842,12 +871,15 @@ int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl) unsigned int pdc_pci_config_read(void *hpa, unsigned long cfg_addr) { int retval; - spin_lock_irq(&pdc_lock); + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); pdc_result[0] = 0; pdc_result[1] = 0; retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_READ_CONFIG, __pa(pdc_result), hpa, cfg_addr&~3UL, 4UL); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); + return retval ? ~0 : (unsigned int) pdc_result[0]; } @@ -863,12 +895,15 @@ unsigned int pdc_pci_config_read(void *hpa, unsigned long cfg_addr) void pdc_pci_config_write(void *hpa, unsigned long cfg_addr, unsigned int val) { int retval; - spin_lock_irq(&pdc_lock); + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); pdc_result[0] = 0; retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_WRITE_CONFIG, __pa(pdc_result), hpa, cfg_addr&~3UL, 4UL, (unsigned long) val); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); + return retval; } #endif /* UNTESTED CODE */ @@ -882,12 +917,13 @@ void pdc_pci_config_write(void *hpa, unsigned long cfg_addr, unsigned int val) int pdc_tod_read(struct pdc_tod *tod) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0); convert_to_wide(pdc_result); memcpy(tod, pdc_result, sizeof(*tod)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -903,10 +939,11 @@ EXPORT_SYMBOL(pdc_tod_read); int pdc_tod_set(unsigned long sec, unsigned long usec) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -917,13 +954,14 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr, struct pdc_memory_table *tbl, unsigned long entries) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries); convert_to_wide(pdc_result); memcpy(r_addr, pdc_result, sizeof(*r_addr)); memcpy(tbl, pdc_result2, entries * sizeof(*tbl)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -936,11 +974,12 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr, int pdc_do_firm_test_reset(unsigned long ftc_bitmap) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC, ftc_bitmap); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -953,10 +992,11 @@ int pdc_do_firm_test_reset(unsigned long ftc_bitmap) int pdc_do_reset(void) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -970,16 +1010,17 @@ int pdc_do_reset(void) int __init pdc_soft_power_info(unsigned long *power_reg) { int retval; + unsigned long flags; *power_reg = (unsigned long) (-1); - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0); if (retval == PDC_OK) { convert_to_wide(pdc_result); *power_reg = f_extend(pdc_result[0]); } - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -998,9 +1039,12 @@ int __init pdc_soft_power_info(unsigned long *power_reg) int pdc_soft_power_button(int sw_control) { int retval; - spin_lock_irq(&pdc_lock); + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); + return retval; } @@ -1011,9 +1055,11 @@ int pdc_soft_power_button(int sw_control) */ void pdc_io_reset(void) { - spin_lock_irq(&pdc_lock); + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); mem_pdc_call(PDC_IO, PDC_IO_RESET, 0); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); } /* @@ -1027,9 +1073,11 @@ void pdc_io_reset(void) */ void pdc_io_reset_devices(void) { - spin_lock_irq(&pdc_lock); + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); mem_pdc_call(PDC_IO, PDC_IO_RESET_DEVICES, 0); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); } @@ -1146,10 +1194,11 @@ int pdc_sti_call(unsigned long func, unsigned long flags, unsigned long glob_cfg) { int retval; + unsigned long irqflags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, irqflags); retval = real32_call(func, flags, inptr, outputr, glob_cfg); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, irqflags); return retval; } @@ -1166,11 +1215,12 @@ EXPORT_SYMBOL(pdc_sti_call); int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result)); memcpy(cell_info, pdc_result, sizeof(*cell_info)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1190,16 +1240,17 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long unsigned long view_type, void *mem_addr) { int retval; + unsigned long flags; static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8))); - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result), ploc, mod, view_type, __pa(&result)); if(!retval) { *actcnt = pdc_result[0]; memcpy(mem_addr, &result, *actcnt); } - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1214,12 +1265,13 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER, __pa(&pdc_result), hpa); memcpy(cpu_info, pdc_result, sizeof(*cpu_info)); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1235,12 +1287,13 @@ int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa) int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE, __pa(pdc_result), cell_num); *num_entries = pdc_result[0]; - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1255,11 +1308,12 @@ int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num) int pdc_pat_get_irt(void *r_addr, unsigned long cell_num) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE, __pa(r_addr), cell_num); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1276,13 +1330,14 @@ int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, unsigned long count, unsigned long offset) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result), __pa(pdc_result2), count, offset); *actual_len = pdc_result[0]; memcpy(mem_addr, pdc_result2, *actual_len); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1297,7 +1352,9 @@ int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr) { int retval; - spin_lock_irq(&pdc_lock); + unsigned long flags; + + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_READ, __pa(pdc_result), pci_addr, pci_size); switch(pci_size) { @@ -1305,7 +1362,7 @@ int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr) case 2: *(u16 *)mem_addr = (u16) pdc_result[0]; case 4: *(u32 *)mem_addr = (u32) pdc_result[0]; } - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } @@ -1321,11 +1378,12 @@ int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr) int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val) { int retval; + unsigned long flags; - spin_lock_irq(&pdc_lock); + spin_lock_irqsave(&pdc_lock, flags); retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_WRITE, pci_addr, pci_size, val); - spin_unlock_irq(&pdc_lock); + spin_unlock_irqrestore(&pdc_lock, flags); return retval; } diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index b44839203e6..8c9b8a7ef24 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -319,13 +319,15 @@ void __init time_init(void) start_cpu_itimer(); /* get CPU 0 started */ - if(pdc_tod_read(&tod_data) == 0) { - write_seqlock_irq(&xtime_lock); + if (pdc_tod_read(&tod_data) == 0) { + unsigned long flags; + + write_seqlock_irqsave(&xtime_lock, flags); xtime.tv_sec = tod_data.tod_sec; xtime.tv_nsec = tod_data.tod_usec * 1000; set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - write_sequnlock_irq(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock, flags); } else { printk(KERN_ERR "Error reading tod clock\n"); xtime.tv_sec = 0; -- GitLab From bbd6330ea1154fc13a351263160d4f9cca2ff5d9 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 6 Oct 2006 23:45:09 -0400 Subject: [PATCH 0755/1619] [PARISC] pdc_init no longer exists Just a stale prototype Signed-off-by: Matthew Wilcox --- include/asm-parisc/pdc.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index c9b2e35326e..423c2b84b4a 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -774,8 +774,6 @@ int pdc_sti_call(unsigned long func, unsigned long flags, unsigned long inptr, unsigned long outputr, unsigned long glob_cfg); -extern void pdc_init(void); - static inline char * os_id_to_string(u16 os_id) { switch(os_id) { case OS_ID_NONE: return "No OS"; -- GitLab From c7753f18711782738936f224aaa421468e87f6ed Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sat, 7 Oct 2006 06:01:11 -0600 Subject: [PATCH 0756/1619] [PARISC] More pt_regs removal Remove pt_regs from ipi_interrupt and timer_interrupt. Inline smp_do_timer() into its only caller, and unify the SMP and non-SMP paths. Fixes a profiling bug. Signed-off-by: Matthew Wilcox --- arch/parisc/kernel/smp.c | 15 +-------------- arch/parisc/kernel/time.c | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index faad338f310..4a23a97b06c 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -154,7 +154,7 @@ halt_processor(void) irqreturn_t -ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +ipi_interrupt(int irq, void *dev_id) { int this_cpu = smp_processor_id(); struct cpuinfo_parisc *p = &cpu_data[this_cpu]; @@ -414,19 +414,6 @@ smp_flush_tlb_all(void) on_each_cpu(flush_tlb_all_local, NULL, 1, 1); } - -void -smp_do_timer(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - struct cpuinfo_parisc *data = &cpu_data[cpu]; - - if (!--data->prof_counter) { - data->prof_counter = data->prof_multiplier; - update_process_times(user_mode(regs)); - } -} - /* * Called by secondaries to update state and initialize CPU registers. */ diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 8c9b8a7ef24..bad7d1eb62b 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -34,10 +34,6 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */ -#ifdef CONFIG_SMP -extern void smp_do_timer(struct pt_regs *regs); -#endif - /* * We keep time on PA-RISC Linux by using the Interval Timer which is * a pair of registers; one is read-only and one is write-only; both @@ -55,13 +51,14 @@ extern void smp_do_timer(struct pt_regs *regs); * held off for an arbitrarily long period of time by interrupts being * disabled, so we may miss one or more ticks. */ -irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t timer_interrupt(int irq, void *dev_id) { unsigned long now; unsigned long next_tick; unsigned long cycles_elapsed, ticks_elapsed; unsigned long cycles_remainder; unsigned int cpu = smp_processor_id(); + struct cpuinfo_parisc *cpuinfo = &cpu_data[cpu]; /* gcc can optimize for "read-only" case with a local clocktick */ unsigned long cpt = clocktick; @@ -69,7 +66,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) profile_tick(CPU_PROFILING); /* Initialize next_tick to the expected tick time. */ - next_tick = cpu_data[cpu].it_value; + next_tick = cpuinfo->it_value; /* Get current interval timer. * CR16 reads as 64 bits in CPU wide mode. @@ -120,7 +117,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ next_tick = now + cycles_remainder; - cpu_data[cpu].it_value = next_tick; + cpuinfo->it_value = next_tick; /* Skip one clocktick on purpose if we are likely to miss next_tick. * We want to avoid the new next_tick being less than CR16. @@ -131,18 +128,19 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) next_tick += cpt; /* Program the IT when to deliver the next interrupt. */ - /* Only bottom 32-bits of next_tick are written to cr16. */ + /* Only bottom 32-bits of next_tick are written to cr16. */ mtctl(next_tick, 16); /* Done mucking with unreliable delivery of interrupts. * Go do system house keeping. */ -#ifdef CONFIG_SMP - smp_do_timer(regs); -#else - update_process_times(user_mode(regs)); -#endif + + if (!--cpuinfo->prof_counter) { + cpuinfo->prof_counter = cpuinfo->prof_multiplier; + update_process_times(user_mode(get_irq_regs())); + } + if (cpu == 0) { write_seqlock(&xtime_lock); do_timer(ticks_elapsed); -- GitLab From 35a84c2f56e0f77ea2c5a4327b17104705f4c8c7 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sat, 7 Oct 2006 22:08:26 +1000 Subject: [PATCH 0757/1619] [POWERPC] Fix up after irq changes Remove struct pt_regs * from all handlers. Also remove the regs argument from get_irq() functions. Compile tested with arch/powerpc/config/* and arch/ppc/configs/prep_defconfig Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ibmebus.c | 2 +- arch/powerpc/kernel/irq.c | 2 +- arch/powerpc/kernel/time.c | 2 +- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 5 ++--- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 5 ++--- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 7 ++++--- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 5 ++--- arch/powerpc/platforms/cell/interrupt.c | 5 ++--- arch/powerpc/platforms/chrp/setup.c | 7 +++---- arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 5 ++--- arch/powerpc/platforms/iseries/irq.c | 10 +++++----- arch/powerpc/platforms/iseries/irq.h | 2 +- arch/powerpc/platforms/iseries/lpevents.c | 4 ++-- arch/powerpc/platforms/iseries/mf.c | 4 ++-- arch/powerpc/platforms/iseries/viopath.c | 2 +- arch/powerpc/platforms/powermac/pic.c | 12 ++++++------ arch/powerpc/platforms/powermac/pic.h | 4 ++-- arch/powerpc/platforms/powermac/smp.c | 8 ++++---- arch/powerpc/platforms/pseries/setup.c | 2 +- arch/powerpc/platforms/pseries/xics.c | 4 ++-- arch/powerpc/sysdev/cpm2_pic.c | 2 +- arch/powerpc/sysdev/cpm2_pic.h | 2 +- arch/powerpc/sysdev/i8259.c | 2 +- arch/powerpc/sysdev/ipic.c | 2 +- arch/powerpc/sysdev/mpic.c | 6 +++--- arch/powerpc/sysdev/qe_lib/qe_ic.c | 14 ++++++-------- arch/powerpc/sysdev/tsi108_pci.c | 3 +-- arch/ppc/platforms/85xx/mpc8560_ads.c | 6 +++--- arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 6 +++--- arch/ppc/platforms/85xx/stx_gp3.c | 6 +++--- arch/ppc/platforms/85xx/tqm85xx.c | 6 +++--- arch/ppc/syslib/i8259.c | 2 +- include/asm-powerpc/i8259.h | 4 ++-- include/asm-powerpc/ibmebus.h | 2 +- include/asm-powerpc/ipic.h | 4 ++-- include/asm-powerpc/iseries/hv_lp_event.h | 2 +- include/asm-powerpc/iseries/it_lp_queue.h | 2 +- include/asm-powerpc/machdep.h | 2 +- include/asm-powerpc/mpic.h | 4 ++-- include/asm-ppc/machdep.h | 2 +- 40 files changed, 84 insertions(+), 92 deletions(-) diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 124dbcba94a..da9fe254eb9 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -319,7 +319,7 @@ EXPORT_SYMBOL(ibmebus_unregister_driver); int ibmebus_request_irq(struct ibmebus_dev *dev, u32 ist, - irqreturn_t (*handler)(int, void*, struct pt_regs *), + irqreturn_t (*handler)(int, void*), unsigned long irq_flags, const char * devname, void *dev_id) { diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5deaab3090b..829ac18b566 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -217,7 +217,7 @@ void do_IRQ(struct pt_regs *regs) * The value -2 is for buggy hardware and means that this IRQ * has already been handled. -- Tom */ - irq = ppc_md.get_irq(regs); + irq = ppc_md.get_irq(); if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { #ifdef CONFIG_IRQSTACKS diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index d210d0a5006..5b59bc18dfe 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -706,7 +706,7 @@ void timer_interrupt(struct pt_regs * regs) #ifdef CONFIG_PPC_ISERIES if (hvlpevent_is_pending()) - process_hvlpevents(regs); + process_hvlpevents(); #endif #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 4276f087f26..0cea42a8053 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -384,8 +384,7 @@ struct hw_interrupt_type m82xx_pci_ic = { }; static void -m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc) { unsigned long stat, mask, pend; int bit; @@ -398,7 +397,7 @@ m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc, break; for (bit = 0; pend != 0; ++bit, pend <<= 1) { if (pend & 0x80000000) - __do_IRQ(pci_int_base + bit, regs); + __do_IRQ(pci_int_base + bit); } } } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 8af7126fc6b..d3e669d69c7 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -66,12 +66,11 @@ mpc85xx_pcibios_fixup(void) #ifdef CONFIG_CPM2 -static void cpm2_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) { int cascade_irq; - while ((cascade_irq = cpm2_get_irq(regs)) >= 0) { + while ((cascade_irq = cpm2_get_irq()) >= 0) { generic_handle_irq(cascade_irq); } desc->chip->eoi(irq); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index b92fc6976a4..953cd5dd3f5 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -132,10 +132,9 @@ mpc85xx_cds_pcibios_fixup(void) #ifdef CONFIG_PPC_I8259 #warning The i8259 PIC support is currently broken -static void mpc85xx_8259_cascade(unsigned int irq, struct - irq_desc *desc, struct pt_regs *regs) +static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { - unsigned int cascade_irq = i8259_irq(regs); + unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); @@ -150,8 +149,10 @@ void __init mpc85xx_cds_pic_init(void) struct mpic *mpic; struct resource r; struct device_node *np = NULL; +#ifdef CONFIG_PPC_I8259 struct device_node *cascade_node = NULL; int cascade_irq; +#endif np = of_find_node_by_type(np, "open-pic"); diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 8218703babd..1a1c226ad4d 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -53,10 +53,9 @@ unsigned long pci_dram_offset = 0; #ifdef CONFIG_PCI -static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { - unsigned int cascade_irq = i8259_irq(regs); + unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); desc->chip->eoi(irq); diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index f8768b096f0..a914c12b406 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -98,8 +98,7 @@ static void iic_ioexc_eoi(unsigned int irq) { } -static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc) { struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data; unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC; @@ -140,7 +139,7 @@ static struct irq_chip iic_ioexc_chip = { }; /* Get an IRQ number from the pending state register of the IIC */ -static unsigned int iic_get_irq(struct pt_regs *regs) +static unsigned int iic_get_irq(void) { struct cbe_iic_pending_bits pending; struct iic *iic; diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 35cd7a5f683..cae3d13229b 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -70,7 +70,7 @@ unsigned long event_scan_interval; * has to include (to get irqreturn_t), which * causes all sorts of problems. -- paulus */ -extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); +extern irqreturn_t xmon_irq(int, void *); extern unsigned long loops_per_jiffy; @@ -335,10 +335,9 @@ chrp_event_scan(unsigned long unused) jiffies + event_scan_interval); } -static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc) { - unsigned int cascade_irq = i8259_irq(regs); + unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); desc->chip->eoi(irq); diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index cb6f084844f..bdb475c65cb 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -61,8 +61,7 @@ pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET; extern int tsi108_setup_pci(struct device_node *dev); extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); extern void tsi108_pci_int_init(void); -extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs); +extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc); int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) { @@ -200,7 +199,7 @@ static void __init mpc7448_hpc2_init_IRQ(void) tsi_pic = of_find_node_by_type(NULL, "open-pic"); if (tsi_pic) { unsigned int size; - void *prop = get_property(tsi_pic, "reg", &size); + const void *prop = get_property(tsi_pic, "reg", &size); mpic_paddr = of_translate_address(tsi_pic, prop); } diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 44c245672dd..5225abfafd9 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -85,7 +85,7 @@ static DEFINE_SPINLOCK(pending_irqs_lock); static int num_pending_irqs; static int pending_irqs[NR_IRQS]; -static void int_received(struct pci_event *event, struct pt_regs *regs) +static void int_received(struct pci_event *event) { int irq; @@ -143,11 +143,11 @@ static void int_received(struct pci_event *event, struct pt_regs *regs) } } -static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs) +static void pci_event_handler(struct HvLpEvent *event) { if (event && (event->xType == HvLpEvent_Type_PciIo)) { if (hvlpevent_is_int(event)) - int_received((struct pci_event *)event, regs); + int_received((struct pci_event *)event); else printk(KERN_ERR "pci_event_handler: unexpected ack received\n"); @@ -305,7 +305,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus, /* * Get the next pending IRQ. */ -unsigned int iSeries_get_irq(struct pt_regs *regs) +unsigned int iSeries_get_irq(void) { int irq = NO_IRQ_IGNORE; @@ -316,7 +316,7 @@ unsigned int iSeries_get_irq(struct pt_regs *regs) } #endif /* CONFIG_SMP */ if (hvlpevent_is_pending()) - process_hvlpevents(regs); + process_hvlpevents(); #ifdef CONFIG_PCI if (num_pending_irqs) { diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h index 1ee8985140e..69f1b437fc7 100644 --- a/arch/powerpc/platforms/iseries/irq.h +++ b/arch/powerpc/platforms/iseries/irq.h @@ -4,6 +4,6 @@ extern void iSeries_init_IRQ(void); extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32); extern void iSeries_activate_IRQs(void); -extern unsigned int iSeries_get_irq(struct pt_regs *); +extern unsigned int iSeries_get_irq(void); #endif /* _ISERIES_IRQ_H */ diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index 98c1c2440aa..e3e929e1b46 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -116,7 +116,7 @@ static void hvlpevent_clear_valid(struct HvLpEvent * event) hvlpevent_invalidate(event); } -void process_hvlpevents(struct pt_regs *regs) +void process_hvlpevents(void) { struct HvLpEvent * event; @@ -144,7 +144,7 @@ void process_hvlpevents(struct pt_regs *regs) __get_cpu_var(hvlpevent_counts)[event->xType]++; if (event->xType < HvLpEvent_Type_NumTypes && lpEventHandler[event->xType]) - lpEventHandler[event->xType](event, regs); + lpEventHandler[event->xType](event); else printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType ); diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 1983b640bac..b5737d68d6c 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -513,7 +513,7 @@ static void handle_ack(struct io_mf_lp_event *event) * parse it enough to know if it is an interrupt or an * acknowledge. */ -static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs) +static void hv_handler(struct HvLpEvent *event) { if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { if (hvlpevent_is_ack(event)) @@ -847,7 +847,7 @@ static int mf_get_boot_rtc(struct rtc_time *tm) /* We need to poll here as we are not yet taking interrupts */ while (rtc_data.busy) { if (hvlpevent_is_pending()) - process_hvlpevents(NULL); + process_hvlpevents(); } return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); } diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index 9baa4ee8259..04e07e5da0c 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -378,7 +378,7 @@ void vio_set_hostlp(void) } EXPORT_SYMBOL(vio_set_hostlp); -static void vio_handleEvent(struct HvLpEvent *event, struct pt_regs *regs) +static void vio_handleEvent(struct HvLpEvent *event) { HvLpIndex remoteLp; int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 5da677835c0..39db1289021 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -42,7 +42,7 @@ * has to include (to get irqreturn_t), which * causes all sorts of problems. -- paulus */ -extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); +extern irqreturn_t xmon_irq(int, void *); #ifdef CONFIG_PPC32 struct pmac_irq_hw { @@ -210,7 +210,7 @@ static struct irq_chip pmac_pic = { .retrigger = pmac_retrigger, }; -static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) +static irqreturn_t gatwick_action(int cpl, void *dev_id) { unsigned long flags; int irq, bits; @@ -235,18 +235,18 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) return rc; } -static unsigned int pmac_pic_get_irq(struct pt_regs *regs) +static unsigned int pmac_pic_get_irq(void) { int irq; unsigned long bits = 0; unsigned long flags; #ifdef CONFIG_SMP - void psurge_smp_message_recv(struct pt_regs *); + void psurge_smp_message_recv(void); /* IPI's are a hack on the powersurge -- Cort */ if ( smp_processor_id() != 0 ) { - psurge_smp_message_recv(regs); + psurge_smp_message_recv(); return NO_IRQ_IGNORE; /* ignore, already handled */ } #endif /* CONFIG_SMP */ @@ -444,7 +444,7 @@ 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, get_irq_regs()); + unsigned int cascade_irq = mpic_get_one_irq(mpic); if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); desc->chip->eoi(irq); diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h index 664103dfeef..c44c89f5e53 100644 --- a/arch/powerpc/platforms/powermac/pic.h +++ b/arch/powerpc/platforms/powermac/pic.h @@ -5,7 +5,7 @@ extern struct hw_interrupt_type pmac_pic; -void pmac_pic_init(void); -int pmac_get_irq(struct pt_regs *regs); +extern void pmac_pic_init(void); +extern int pmac_get_irq(void); #endif /* __PPC_PLATFORMS_PMAC_PIC_H */ diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 1949b657b09..574cd205b30 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -160,7 +160,7 @@ static inline void psurge_clr_ipi(int cpu) */ static unsigned long psurge_smp_message[NR_CPUS]; -void psurge_smp_message_recv(struct pt_regs *regs) +void psurge_smp_message_recv(void) { int cpu = smp_processor_id(); int msg; @@ -174,12 +174,12 @@ void psurge_smp_message_recv(struct pt_regs *regs) /* make sure there is a message there */ for (msg = 0; msg < 4; msg++) if (test_and_clear_bit(msg, &psurge_smp_message[cpu])) - smp_message_recv(msg, regs); + smp_message_recv(msg); } -irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs) +irqreturn_t psurge_primary_intr(int irq, void *d) { - psurge_smp_message_recv(regs); + psurge_smp_message_recv(); return IRQ_HANDLED; } diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ad9aec2c6fe..89a8119f988 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -123,7 +123,7 @@ static void __init fwnmi_init(void) void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc) { - unsigned int cascade_irq = i8259_irq(get_irq_regs()); + unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) 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 f6bd2f28515..d071abe78ab 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -308,14 +308,14 @@ static inline unsigned int xics_remap_irq(unsigned int vec) return NO_IRQ; } -static unsigned int xics_get_irq_direct(struct pt_regs *regs) +static unsigned int xics_get_irq_direct(void) { unsigned int cpu = smp_processor_id(); return xics_remap_irq(direct_xirr_info_get(cpu)); } -static unsigned int xics_get_irq_lpar(struct pt_regs *regs) +static unsigned int xics_get_irq_lpar(void) { unsigned int cpu = smp_processor_id(); diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 28b01899474..767ee6651ad 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -147,7 +147,7 @@ static struct irq_chip cpm2_pic = { .end = cpm2_end_irq, }; -unsigned int cpm2_get_irq(struct pt_regs *regs) +unsigned int cpm2_get_irq(void) { int irq; unsigned long bits; diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h index 3c513e5a688..2840616529e 100644 --- a/arch/powerpc/sysdev/cpm2_pic.h +++ b/arch/powerpc/sysdev/cpm2_pic.h @@ -3,7 +3,7 @@ extern intctl_cpm2_t *cpm2_intctl; -extern unsigned int cpm2_get_irq(struct pt_regs *regs); +extern unsigned int cpm2_get_irq(void); extern void cpm2_pic_init(struct device_node*); diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 26a6a3becd6..0450265d73b 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -34,7 +34,7 @@ static struct irq_host *i8259_host; * which is called. It should be noted that polling is broken on some * IBM and Motorola PReP boxes so we must use the int-ack feature on them. */ -unsigned int i8259_irq(struct pt_regs *regs) +unsigned int i8259_irq(void) { int irq; int lock = 0; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 6ebdae8e6f6..bc4d4a7f965 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -709,7 +709,7 @@ void ipic_clear_mcp_status(u32 mask) } /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ -unsigned int ipic_get_irq(struct pt_regs *regs) +unsigned int ipic_get_irq(void) { int irq; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 195215560fd..ba4833f57d4 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1217,7 +1217,7 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); } -unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) +unsigned int mpic_get_one_irq(struct mpic *mpic) { u32 src; @@ -1230,13 +1230,13 @@ unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) return irq_linear_revmap(mpic->irqhost, src); } -unsigned int mpic_get_irq(struct pt_regs *regs) +unsigned int mpic_get_irq(void) { struct mpic *mpic = mpic_primary; BUG_ON(mpic == NULL); - return mpic_get_one_irq(mpic, regs); + return mpic_get_one_irq(mpic); } diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 0dec010bcbb..6995f51b948 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -300,7 +300,7 @@ static struct irq_host_ops qe_ic_host_ops = { }; /* 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) +unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) { int irq; @@ -316,7 +316,7 @@ unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic, struct pt_regs *regs) } /* 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) +unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) { int irq; @@ -333,13 +333,12 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic, struct pt_regs *regs) /* 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) +void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc) { 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); + unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); chip->mask_ack(irq); if (cascade_irq != NO_IRQ) @@ -349,13 +348,12 @@ void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc, /* 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) +void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc) { 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); + unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); chip->mask_ack(irq); if (cascade_irq != NO_IRQ) diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 14f4a1ab6d1..322f86e93de 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -405,8 +405,7 @@ void __init tsi108_pci_int_init(void) init_pci_source(); } -void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc) { unsigned int cascade_irq = get_pci_source(); if (cascade_irq != NO_IRQ) diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c index 94badafe4ef..14ecec7bbed 100644 --- a/arch/ppc/platforms/85xx/mpc8560_ads.c +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -211,10 +211,10 @@ mpc8560ads_setup_arch(void) #endif } -static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cpm2_cascade(int irq, void *dev_id) { - while ((irq = cpm2_get_irq(regs)) >= 0) - __do_IRQ(irq, regs); + while ((irq = cpm2_get_irq()) >= 0) + __do_IRQ(irq); return IRQ_HANDLED; } diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 75204588a3e..5ce0f69c1db 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -127,10 +127,10 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m) } #ifdef CONFIG_CPM2 -static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cpm2_cascade(int irq, void *dev_id) { - while((irq = cpm2_get_irq(regs)) >= 0) - __do_IRQ(irq, regs); + while((irq = cpm2_get_irq()) >= 0) + __do_IRQ(irq); return IRQ_HANDLED; } diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 495aa79bb3a..4bb18ab2767 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -156,10 +156,10 @@ gp3_setup_arch(void) printk ("bi_immr_base = %8.8lx\n", binfo->bi_immr_base); } -static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cpm2_cascade(int irq, void *dev_id) { - while ((irq = cpm2_get_irq(regs)) >= 0) - __do_IRQ(irq, regs); + while ((irq = cpm2_get_irq()) >= 0) + __do_IRQ(irq); return IRQ_HANDLED; } diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c index 189ed4175f9..dd45f2e1844 100644 --- a/arch/ppc/platforms/85xx/tqm85xx.c +++ b/arch/ppc/platforms/85xx/tqm85xx.c @@ -181,10 +181,10 @@ tqm85xx_setup_arch(void) } #ifdef CONFIG_MPC8560 -static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cpm2_cascade(int irq, void *dev_id) { - while ((irq = cpm2_get_irq(regs)) >= 0) - __do_IRQ(irq, regs); + while ((irq = cpm2_get_irq()) >= 0) + __do_IRQ(irq); return IRQ_HANDLED; } diff --git a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c index eb35353af83..a43dda5a833 100644 --- a/arch/ppc/syslib/i8259.c +++ b/arch/ppc/syslib/i8259.c @@ -28,7 +28,7 @@ static int i8259_pic_irq_offset; * which is called. It should be noted that polling is broken on some * IBM and Motorola PReP boxes so we must use the int-ack feature on them. */ -int i8259_irq(struct pt_regs *regs) +int i8259_irq(void) { int irq; diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h index c80e113052c..78489fb8d14 100644 --- a/include/asm-powerpc/i8259.h +++ b/include/asm-powerpc/i8259.h @@ -6,10 +6,10 @@ #ifdef CONFIG_PPC_MERGE extern void i8259_init(struct device_node *node, unsigned long intack_addr); -extern unsigned int i8259_irq(struct pt_regs *regs); +extern unsigned int i8259_irq(void); #else extern void i8259_init(unsigned long intack_addr, int offset); -extern int i8259_irq(struct pt_regs *regs); +extern int i8259_irq(void); #endif #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h index 7ab195a2788..9d25f2063b0 100644 --- a/include/asm-powerpc/ibmebus.h +++ b/include/asm-powerpc/ibmebus.h @@ -65,7 +65,7 @@ void ibmebus_unregister_driver(struct ibmebus_driver *drv); int ibmebus_request_irq(struct ibmebus_dev *dev, u32 ist, - irqreturn_t (*handler)(int, void*, struct pt_regs *), + irqreturn_t (*handler)(int, void*), unsigned long irq_flags, const char * devname, void *dev_id); void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id); diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h index 1ce09a35906..9fbb0341586 100644 --- a/include/asm-powerpc/ipic.h +++ b/include/asm-powerpc/ipic.h @@ -79,12 +79,12 @@ extern void ipic_clear_mcp_status(u32 mask); #ifdef CONFIG_PPC_MERGE extern void ipic_init(struct device_node *node, unsigned int flags); -extern unsigned int ipic_get_irq(struct pt_regs *regs); +extern unsigned int ipic_get_irq(void); #else extern void ipic_init(phys_addr_t phys_addr, unsigned int flags, unsigned int irq_offset, unsigned char *senses, unsigned int senses_count); -extern int ipic_get_irq(struct pt_regs *regs); +extern int ipic_get_irq(void); #endif #endif /* __ASM_IPIC_H__ */ diff --git a/include/asm-powerpc/iseries/hv_lp_event.h b/include/asm-powerpc/iseries/hv_lp_event.h index 4065a4de493..6ce2ce1e269 100644 --- a/include/asm-powerpc/iseries/hv_lp_event.h +++ b/include/asm-powerpc/iseries/hv_lp_event.h @@ -50,7 +50,7 @@ struct HvLpEvent { u64 xCorrelationToken; /* Unique value for source/type x10-x17 */ }; -typedef void (*LpEventHandler)(struct HvLpEvent *, struct pt_regs *); +typedef void (*LpEventHandler)(struct HvLpEvent *); /* Register a handler for an event type - returns 0 on success */ extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType, diff --git a/include/asm-powerpc/iseries/it_lp_queue.h b/include/asm-powerpc/iseries/it_lp_queue.h index 3f681476929..42827883882 100644 --- a/include/asm-powerpc/iseries/it_lp_queue.h +++ b/include/asm-powerpc/iseries/it_lp_queue.h @@ -72,7 +72,7 @@ struct hvlpevent_queue { extern struct hvlpevent_queue hvlpevent_queue; extern int hvlpevent_is_pending(void); -extern void process_hvlpevents(struct pt_regs *); +extern void process_hvlpevents(void); extern void setup_hvlpevent_queue(void); #endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */ diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index c17c1374240..dac90dc341c 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -97,7 +97,7 @@ struct machdep_calls { void (*show_percpuinfo)(struct seq_file *m, int i); void (*init_IRQ)(void); - unsigned int (*get_irq)(struct pt_regs *); + unsigned int (*get_irq)(void); #ifdef CONFIG_KEXEC void (*kexec_cpu_down)(int crash_shutdown, int secondary); #endif diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index a9f9604b9ef..ef0a5458d2b 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -409,9 +409,9 @@ extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); void smp_mpic_message_pass(int target, int msg); /* Fetch interrupt from a given mpic */ -extern unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs); +extern unsigned int mpic_get_one_irq(struct mpic *mpic); /* This one gets to the primary mpic */ -extern unsigned int mpic_get_irq(struct pt_regs *regs); +extern unsigned int mpic_get_irq(void); /* Set the EPIC clock ratio */ void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio); diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index da7746738ae..293a444a1d7 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -43,7 +43,7 @@ struct machdep_calls { /* Optional, may be NULL. */ unsigned int (*irq_canonicalize)(unsigned int irq); void (*init_IRQ)(void); - int (*get_irq)(struct pt_regs *); + int (*get_irq)(void); /* A general init function, called by ppc_init in init/main.c. May be NULL. DEPRECATED ! */ -- GitLab From f5a924581a4e7b9bc29a49ee1397dcaaacd5f25f Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 6 Oct 2006 22:52:16 +0200 Subject: [PATCH 0758/1619] [POWERPC] SPU fixup after irq changes Remove struct pt_regs * from remaining spu irq functions. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ac5f12662db..ccfd0c4db87 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -147,7 +147,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) } static irqreturn_t -spu_irq_class_0(int irq, void *data, struct pt_regs *regs) +spu_irq_class_0(int irq, void *data) { struct spu *spu; @@ -186,7 +186,7 @@ spu_irq_class_0_bottom(struct spu *spu) EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom); static irqreturn_t -spu_irq_class_1(int irq, void *data, struct pt_regs *regs) +spu_irq_class_1(int irq, void *data) { struct spu *spu; unsigned long stat, mask, dar, dsisr; @@ -224,7 +224,7 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom); static irqreturn_t -spu_irq_class_2(int irq, void *data, struct pt_regs *regs) +spu_irq_class_2(int irq, void *data) { struct spu *spu; unsigned long stat; -- GitLab From 40a5f7ca07f8e1d77acdba5ae0c11c15cb7520c1 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 6 Oct 2006 23:06:48 +0200 Subject: [PATCH 0759/1619] [POWERPC] PReP fixup after irq changes Compile fixes for PReP in ARCH=ppc. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- arch/ppc/syslib/open_pic.c | 14 +++++++------- include/asm-ppc/open_pic.h | 6 +++--- include/asm-ppc/smp.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index aa0b9578870..18ec9473329 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -45,7 +45,7 @@ static u_int NumSources; static int open_pic_irq_offset; static volatile OpenPIC_Source __iomem *ISR[NR_IRQS]; static int openpic_cascade_irq = -1; -static int (*openpic_cascade_fn)(struct pt_regs *); +static int (*openpic_cascade_fn)(void); /* Global Operations */ static void openpic_disable_8259_pass_through(void); @@ -54,7 +54,7 @@ static void openpic_set_spurious(u_int vector); #ifdef CONFIG_SMP /* Interprocessor Interrupts */ static void openpic_initipi(u_int ipi, u_int pri, u_int vector); -static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *); +static irqreturn_t openpic_ipi_action(int cpl, void *dev_id); #endif /* Timer Interrupts */ @@ -700,7 +700,7 @@ static struct irqaction openpic_cascade_irqaction = { void __init openpic_hookup_cascade(u_int irq, char *name, - int (*cascade_fn)(struct pt_regs *)) + int (*cascade_fn)(void)) { openpic_cascade_irq = irq; openpic_cascade_fn = cascade_fn; @@ -857,16 +857,16 @@ static void openpic_end_ipi(unsigned int irq_nr) { } -static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) +static irqreturn_t openpic_ipi_action(int cpl, void *dev_id) { - smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs); + smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset); return IRQ_HANDLED; } #endif /* CONFIG_SMP */ int -openpic_get_irq(struct pt_regs *regs) +openpic_get_irq(void) { int irq = openpic_irq(); @@ -876,7 +876,7 @@ openpic_get_irq(struct pt_regs *regs) * This should move to irq.c eventually. -- paulus */ if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) { - int cirq = openpic_cascade_fn(regs); + int cirq = openpic_cascade_fn(); /* Allow for the cascade being shared with other devices */ if (cirq != -1) { diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h index a4fe962d9f7..778d5726212 100644 --- a/include/asm-ppc/open_pic.h +++ b/include/asm-ppc/open_pic.h @@ -48,12 +48,12 @@ extern void openpic_init(int linux_irq_offset); extern void openpic_init_nmi_irq(u_int irq); extern void openpic_set_irq_priority(u_int irq, u_int pri); extern void openpic_hookup_cascade(u_int irq, char *name, - int (*cascade_fn)(struct pt_regs *)); + int (*cascade_fn)(void)); extern u_int openpic_irq(void); extern void openpic_eoi(void); extern void openpic_request_IPIs(void); extern void do_openpic_setup_cpu(void); -extern int openpic_get_irq(struct pt_regs *regs); +extern int openpic_get_irq(void); extern void openpic_reset_processor_phys(u_int cpumask); extern void openpic_setup_ISU(int isu_num, unsigned long addr); extern void openpic_cause_IPI(u_int ipi, cpumask_t cpumask); @@ -93,6 +93,6 @@ extern void openpic2_init(int linux_irq_offset); extern void openpic2_init_nmi_irq(u_int irq); extern u_int openpic2_irq(void); extern void openpic2_eoi(void); -extern int openpic2_get_irq(struct pt_regs *regs); +extern int openpic2_get_irq(void); extern void openpic2_setup_ISU(int isu_num, unsigned long addr); #endif /* _PPC_KERNEL_OPEN_PIC_H */ diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index 0b7fa89589d..e75791ea33a 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -39,7 +39,7 @@ extern struct smp_ops_t *smp_ops; extern void smp_send_tlb_invalidate(int); extern void smp_send_xmon_break(int cpu); struct pt_regs; -extern void smp_message_recv(int, struct pt_regs *); +extern void smp_message_recv(int); extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); -- GitLab From dcbd4ec4c258f88d4cfd3c309c8a56faff061340 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 6 Oct 2006 22:19:44 -0700 Subject: [PATCH 0760/1619] [PATCH] slab: remove wrongly placed BUG_ON Init list is called with a list parameter that is not equal to the cachep->nodelists entry under NUMA if more than one node exists. This is fully legitimatei. One may want to populate the list fields before switching nodelist pointers. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mm/slab.c b/mm/slab.c index 64fb0d770b0..266449d604b 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1328,7 +1328,6 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list, { struct kmem_list3 *ptr; - BUG_ON(cachep->nodelists[nodeid] != list); ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, nodeid); BUG_ON(!ptr); -- GitLab From 5c339d4541995df2fd3ca31a84c042e7afe9b3c1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 6 Oct 2006 22:19:44 -0700 Subject: [PATCH 0761/1619] [PATCH] swsusp: Make userland suspend work on SMP again Unfortunately one of the recent changes in swsusp has broken the userland suspend on SMP. Fix it. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/power/user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/user.c b/kernel/power/user.c index 72825c853cd..93b5dd283de 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -145,10 +145,10 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, error = freeze_processes(); if (error) { thaw_processes(); + enable_nonboot_cpus(); error = -EBUSY; } } - enable_nonboot_cpus(); up(&pm_sem); if (!error) data->frozen = 1; -- GitLab From 00079e04fe478cd3c59ae2106ef2fbe779e67024 Mon Sep 17 00:00:00 2001 From: Eric Eric Sesterhenn Date: Fri, 6 Oct 2006 22:19:45 -0700 Subject: [PATCH 0762/1619] [PATCH] reiserfs: null pointer dereferencing in reiserfs_read_bitmap_block null pointer dereferencing in reiserfs_read_bitmap_block. Signed-off-by: Alexander Zarochentsev Cc: Jeff Mahoney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/bitmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 1bfae42117c..e3d466a228d 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -1304,8 +1304,8 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, bh = sb_bread(sb, block); if (bh == NULL) - reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%lu) " - "reading failed", __FUNCTION__, bh->b_blocknr); + reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) " + "reading failed", __FUNCTION__, block); else { if (buffer_locked(bh)) { PROC_INFO_INC(sb, scan_bitmap.wait); -- GitLab From 2850bc273776cbb1b510c5828e9e456dffb50a32 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 7 Oct 2006 14:16:45 +0100 Subject: [PATCH 0763/1619] [PATCH] m68k pt_regs fixes m68k_handle_int() split in two functions: __m68k_handle_int() takes pt_regs * and does set_irq_regs(); m68k_handle_int() doesn't get pt_regs *. Places where we used to call m68k_handle_int() recursively with the same pt_regs have simply lost the second argument, the rest is switched to __m68k_handle_int(). The rest of patch is just dropping pt_regs * where needed. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m68k/amiga/amiints.c | 40 ++++++++++++++++----------------- arch/m68k/amiga/cia.c | 4 ++-- arch/m68k/amiga/config.c | 5 ++--- arch/m68k/apollo/config.c | 14 ++++++------ arch/m68k/apollo/dn_ints.c | 2 +- arch/m68k/atari/config.c | 2 +- arch/m68k/atari/stdma.c | 11 +++++---- arch/m68k/atari/time.c | 2 +- arch/m68k/bvme6000/config.c | 12 +++++----- arch/m68k/hp300/time.c | 8 +++---- arch/m68k/hp300/time.h | 2 +- arch/m68k/kernel/entry.S | 4 ++-- arch/m68k/kernel/ints.c | 20 ++++++++++++----- arch/m68k/kernel/setup.c | 2 +- arch/m68k/kernel/time.c | 7 +++--- arch/m68k/mac/baboon.c | 6 ++--- arch/m68k/mac/config.c | 4 ++-- arch/m68k/mac/iop.c | 22 +++++++++--------- arch/m68k/mac/macints.c | 16 +++++++------ arch/m68k/mac/oss.c | 16 ++++++------- arch/m68k/mac/psc.c | 6 ++--- arch/m68k/mac/via.c | 24 ++++++++++---------- arch/m68k/mvme147/config.c | 10 ++++----- arch/m68k/mvme16x/config.c | 12 +++++----- arch/m68k/q40/config.c | 2 +- arch/m68k/q40/q40ints.c | 16 ++++++------- arch/m68k/sun3/config.c | 2 +- arch/m68k/sun3/sun3ints.c | 11 ++++----- arch/m68k/sun3x/time.c | 2 +- arch/m68k/sun3x/time.h | 2 +- drivers/char/vme_scc.c | 2 +- drivers/macintosh/adb-iop.c | 2 +- drivers/macintosh/via-macii.c | 2 +- drivers/macintosh/via-maciisi.c | 2 +- drivers/macintosh/via-pmu68k.c | 6 ++--- drivers/net/7990.c | 2 +- drivers/parport/parport_mfc3.c | 2 +- include/asm-m68k/atari_stdma.h | 3 +-- include/asm-m68k/floppy.h | 10 ++++----- include/asm-m68k/ide.h | 2 +- include/asm-m68k/irq.h | 11 ++++----- include/asm-m68k/mac_iop.h | 6 ++--- include/asm-m68k/machdep.h | 2 +- include/asm-m68k/sun3xflop.h | 7 +++--- 44 files changed, 176 insertions(+), 169 deletions(-) diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index 96c79d840cf..28d95cfe8ac 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c @@ -47,10 +47,10 @@ static void amiga_enable_irq(unsigned int irq); static void amiga_disable_irq(unsigned int irq); -static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp); -static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp); -static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp); -static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp); +static irqreturn_t ami_int1(int irq, void *dev_id); +static irqreturn_t ami_int3(int irq, void *dev_id); +static irqreturn_t ami_int4(int irq, void *dev_id); +static irqreturn_t ami_int5(int irq, void *dev_id); static struct irq_controller amiga_irq_controller = { .name = "amiga", @@ -113,98 +113,98 @@ static void amiga_disable_irq(unsigned int irq) * The builtin Amiga hardware interrupt handlers. */ -static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t ami_int1(int irq, void *dev_id) { unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; /* if serial transmit buffer empty, interrupt */ if (ints & IF_TBE) { amiga_custom.intreq = IF_TBE; - m68k_handle_int(IRQ_AMIGA_TBE, fp); + m68k_handle_int(IRQ_AMIGA_TBE); } /* if floppy disk transfer complete, interrupt */ if (ints & IF_DSKBLK) { amiga_custom.intreq = IF_DSKBLK; - m68k_handle_int(IRQ_AMIGA_DSKBLK, fp); + m68k_handle_int(IRQ_AMIGA_DSKBLK); } /* if software interrupt set, interrupt */ if (ints & IF_SOFT) { amiga_custom.intreq = IF_SOFT; - m68k_handle_int(IRQ_AMIGA_SOFT, fp); + m68k_handle_int(IRQ_AMIGA_SOFT); } return IRQ_HANDLED; } -static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t ami_int3(int irq, void *dev_id) { unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; /* if a blitter interrupt */ if (ints & IF_BLIT) { amiga_custom.intreq = IF_BLIT; - m68k_handle_int(IRQ_AMIGA_BLIT, fp); + m68k_handle_int(IRQ_AMIGA_BLIT); } /* if a copper interrupt */ if (ints & IF_COPER) { amiga_custom.intreq = IF_COPER; - m68k_handle_int(IRQ_AMIGA_COPPER, fp); + m68k_handle_int(IRQ_AMIGA_COPPER); } /* if a vertical blank interrupt */ if (ints & IF_VERTB) { amiga_custom.intreq = IF_VERTB; - m68k_handle_int(IRQ_AMIGA_VERTB, fp); + m68k_handle_int(IRQ_AMIGA_VERTB); } return IRQ_HANDLED; } -static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t ami_int4(int irq, void *dev_id) { unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; /* if audio 0 interrupt */ if (ints & IF_AUD0) { amiga_custom.intreq = IF_AUD0; - m68k_handle_int(IRQ_AMIGA_AUD0, fp); + m68k_handle_int(IRQ_AMIGA_AUD0); } /* if audio 1 interrupt */ if (ints & IF_AUD1) { amiga_custom.intreq = IF_AUD1; - m68k_handle_int(IRQ_AMIGA_AUD1, fp); + m68k_handle_int(IRQ_AMIGA_AUD1); } /* if audio 2 interrupt */ if (ints & IF_AUD2) { amiga_custom.intreq = IF_AUD2; - m68k_handle_int(IRQ_AMIGA_AUD2, fp); + m68k_handle_int(IRQ_AMIGA_AUD2); } /* if audio 3 interrupt */ if (ints & IF_AUD3) { amiga_custom.intreq = IF_AUD3; - m68k_handle_int(IRQ_AMIGA_AUD3, fp); + m68k_handle_int(IRQ_AMIGA_AUD3); } return IRQ_HANDLED; } -static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t ami_int5(int irq, void *dev_id) { unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; /* if serial receive buffer full interrupt */ if (ints & IF_RBF) { /* acknowledge of IF_RBF must be done by the serial interrupt */ - m68k_handle_int(IRQ_AMIGA_RBF, fp); + m68k_handle_int(IRQ_AMIGA_RBF); } /* if a disk sync interrupt */ if (ints & IF_DSKSYN) { amiga_custom.intreq = IF_DSKSYN; - m68k_handle_int(IRQ_AMIGA_DSKSYN, fp); + m68k_handle_int(IRQ_AMIGA_DSKSYN); } return IRQ_HANDLED; } diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index dbad3005472..7a20058eb38 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -82,7 +82,7 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask) return old; } -static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t cia_handler(int irq, void *dev_id) { struct ciabase *base = (struct ciabase *)dev_id; int mach_irq; @@ -93,7 +93,7 @@ static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp) amiga_custom.intreq = base->int_mask; for (; ints; mach_irq++, ints >>= 1) { if (ints & 1) - m68k_handle_int(mach_irq, fp); + m68k_handle_int(mach_irq); } return IRQ_HANDLED; } diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 092e50d2cb1..6f63d62bd7d 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -83,7 +83,7 @@ static char amiga_model_name[13] = "Amiga "; extern char m68k_debug_device[]; -static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +static void amiga_sched_init(irqreturn_t (*handler)(int, void *)); /* amiga specific irq functions */ extern void amiga_init_IRQ (void); static void amiga_get_model(char *model); @@ -487,8 +487,7 @@ void __init config_amiga(void) static unsigned short jiffy_ticks; -static void __init amiga_sched_init(irqreturn_t (*timer_routine)(int, void *, - struct pt_regs *)) +static void __init amiga_sched_init(irqreturn_t (*timer_routine)(int, void *)) { static struct resource sched_res = { .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c index 6f4581575fb..b2eea00796a 100644 --- a/arch/m68k/apollo/config.c +++ b/arch/m68k/apollo/config.c @@ -25,7 +25,7 @@ u_long cpuctrl_physaddr; u_long timer_physaddr; u_long apollo_model; -extern void dn_sched_init(irqreturn_t (*handler)(int,void *,struct pt_regs *)); +extern void dn_sched_init(irqreturn_t (*handler)(int,void *)); extern void dn_init_IRQ(void); extern unsigned long dn_gettimeoffset(void); extern int dn_dummy_hwclk(int, struct rtc_time *); @@ -38,7 +38,7 @@ extern irqreturn_t dn_process_int(int irq, struct pt_regs *fp); #ifdef CONFIG_HEARTBEAT static void dn_heartbeat(int on); #endif -static irqreturn_t dn_timer_int(int irq,void *, struct pt_regs *); +static irqreturn_t dn_timer_int(int irq,void *); static void dn_get_model(char *model); static const char *apollo_models[] = { [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)", @@ -174,13 +174,13 @@ void config_apollo(void) { } -irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) +irqreturn_t dn_timer_int(int irq, void *dev_id) { - irqreturn_t (*timer_handler)(int, void *, struct pt_regs *) = dev_id; + irqreturn_t (*timer_handler)(int, void *) = dev_id; volatile unsigned char x; - timer_handler(irq, dev_id, fp); + timer_handler(irq, dev_id); x=*(volatile unsigned char *)(timer+3); x=*(volatile unsigned char *)(timer+5); @@ -188,8 +188,8 @@ irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) return IRQ_HANDLED; } -void dn_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) { - +void dn_sched_init(irqreturn_t (*timer_routine)(int, void *)) +{ /* program timer 1 */ *(volatile unsigned char *)(timer+3)=0x01; *(volatile unsigned char *)(timer+1)=0x40; diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c index 9fe07803797..4274af12599 100644 --- a/arch/m68k/apollo/dn_ints.c +++ b/arch/m68k/apollo/dn_ints.c @@ -6,7 +6,7 @@ void dn_process_int(unsigned int irq, struct pt_regs *fp) { - m68k_handle_int(irq, fp); + __m68k_handle_int(irq, fp); *(volatile unsigned char *)(pica)=0x20; *(volatile unsigned char *)(picb)=0x20; diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index b2079252a95..76760eebbbc 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -62,7 +62,7 @@ static void atari_heartbeat( int on ); #endif /* atari specific timer functions (in time.c) */ -extern void atari_sched_init(irqreturn_t (*)(int, void *, struct pt_regs *)); +extern void atari_sched_init(irqreturn_t (*)(int, void *)); extern unsigned long atari_gettimeoffset (void); extern int atari_mste_hwclk (int, struct rtc_time *); extern int atari_tt_hwclk (int, struct rtc_time *); diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 288f5e6a124..5283c73d3f7 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -44,7 +44,7 @@ static int stdma_locked; /* the semaphore */ /* int func to be called */ -static irqreturn_t (*stdma_isr)(int, void *, struct pt_regs *); +static irqreturn_t (*stdma_isr)(int, void *); static void *stdma_isr_data; /* data passed to isr */ static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ @@ -53,7 +53,7 @@ static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ /***************************** Prototypes *****************************/ -static irqreturn_t stdma_int (int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t stdma_int (int irq, void *dummy); /************************* End of Prototypes **************************/ @@ -75,8 +75,7 @@ static irqreturn_t stdma_int (int irq, void *dummy, struct pt_regs *fp); * */ -void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *), - void *data) +void stdma_lock(irqreturn_t (*handler)(int, void *), void *data) { unsigned long flags; @@ -188,9 +187,9 @@ void __init stdma_init(void) * */ -static irqreturn_t stdma_int(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t stdma_int(int irq, void *dummy) { if (stdma_isr) - (*stdma_isr)(irq, stdma_isr_data, fp); + (*stdma_isr)(irq, stdma_isr_data); return IRQ_HANDLED; } diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index e79bbc94216..b8fe71cfc62 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -20,7 +20,7 @@ #include void __init -atari_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) +atari_sched_init(irqreturn_t (*timer_routine)(int, void *)) { /* set Timer C data Register */ mfp.tim_dt_c = INT_TICKS; diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index d1e916ae55a..df64efc940c 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -38,7 +38,7 @@ static void bvme6000_get_model(char *model); static int bvme6000_get_hardware_list(char *buffer); -extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *)); extern unsigned long bvme6000_gettimeoffset (void); extern int bvme6000_hwclk (int, struct rtc_time *); extern int bvme6000_set_clock_mmss (unsigned long); @@ -52,7 +52,7 @@ static unsigned char bin2bcd (unsigned char b); /* Save tick handler routine pointer, will point to do_timer() in * kernel/sched.c, called via bvme6000_process_int() */ -static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *); +static irqreturn_t (*tick_handler)(int, void *); int bvme6000_parse_bootinfo(const struct bi_record *bi) @@ -154,7 +154,7 @@ void __init config_bvme6000(void) } -irqreturn_t bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp) +irqreturn_t bvme6000_abort_int (int irq, void *dev_id) { unsigned long *new = (unsigned long *)vectors; unsigned long *old = (unsigned long *)0xf8000000; @@ -171,14 +171,14 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp) } -static irqreturn_t bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t bvme6000_timer_int (int irq, void *dev_id) { volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; unsigned char msr = rtc->msr & 0xc0; rtc->msr = msr | 0x20; /* Ack the interrupt */ - return tick_handler(irq, dev_id, fp); + return tick_handler(irq, dev_id); } /* @@ -190,7 +190,7 @@ static irqreturn_t bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp * so divide by 8 to get the microsecond result. */ -void bvme6000_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) +void bvme6000_sched_init (irqreturn_t (*timer_routine)(int, void *)) { volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; unsigned char msr = rtc->msr & 0xc0; diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c index 7df05662b27..086058fd838 100644 --- a/arch/m68k/hp300/time.c +++ b/arch/m68k/hp300/time.c @@ -36,15 +36,15 @@ #define INTVAL ((10000 / 4) - 1) -static irqreturn_t hp300_tick(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t hp300_tick(int irq, void *dev_id) { unsigned long tmp; - irqreturn_t (*vector)(int, void *, struct pt_regs *) = dev_id; + irqreturn_t (*vector)(int, void *) = dev_id; in_8(CLOCKBASE + CLKSR); asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE)); /* Turn off the network and SCSI leds */ blinken_leds(0, 0xe0); - return vector(irq, NULL, regs); + return vector(irq, NULL); } unsigned long hp300_gettimeoffset(void) @@ -63,7 +63,7 @@ unsigned long hp300_gettimeoffset(void) return (USECS_PER_JIFFY * ticks) / INTVAL; } -void __init hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *)) +void __init hp300_sched_init(irqreturn_t (*vector)(int, void *)) { out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */ out_8(CLOCKBASE + CLKCR1, 0x1); /* reset */ diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h index 8ef9987b49a..ca66a039d6f 100644 --- a/arch/m68k/hp300/time.h +++ b/arch/m68k/hp300/time.h @@ -1,4 +1,4 @@ -extern void hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *)); +extern void hp300_sched_init(irqreturn_t (*vector)(int, void *)); extern unsigned long hp300_gettimeoffset (void); diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 9083c8b7659..34bf7bd126d 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -205,7 +205,7 @@ ENTRY(auto_inthandler) movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack auto_irqhandler_fixup = . + 2 - jsr m68k_handle_int | process the IRQ + jsr __m68k_handle_int | process the IRQ addql #8,%sp | pop parameters off stack ret_from_interrupt: @@ -239,7 +239,7 @@ user_irqvec_fixup = . + 2 movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack user_irqhandler_fixup = . + 2 - jsr m68k_handle_int | process the IRQ + jsr __m68k_handle_int | process the IRQ addql #8,%sp | pop parameters off stack subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index b33e37fb7b0..6fa893fc5fd 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef CONFIG_Q40 #include @@ -104,7 +105,7 @@ void __init init_IRQ(void) * @handler: called from auto vector interrupts * * setup the handler to be called from auto vector interrupts instead of the - * standard m68k_handle_int(), it will be called with irq numbers in the range + * standard __m68k_handle_int(), it will be called with irq numbers in the range * from IRQ_AUTO_1 - IRQ_AUTO_7. */ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) @@ -123,7 +124,7 @@ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_re * setup user vector interrupts, this includes activating the specified range * of interrupts, only then these interrupts can be requested (note: this is * different from auto vector interrupts). An optional handler can be installed - * to be called instead of the default m68k_handle_int(), it will be called + * to be called instead of the default __m68k_handle_int(), it will be called * with irq numbers starting from IRQ_USER. */ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, @@ -215,7 +216,7 @@ int setup_irq(unsigned int irq, struct irq_node *node) } int request_irq(unsigned int irq, - irqreturn_t (*handler) (int, void *, struct pt_regs *), + irqreturn_t (*handler) (int, void *), unsigned long flags, const char *devname, void *dev_id) { struct irq_node *node; @@ -379,18 +380,25 @@ unsigned int irq_canonicalize(unsigned int irq) EXPORT_SYMBOL(irq_canonicalize); -asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) +asmlinkage void m68k_handle_int(unsigned int irq) { struct irq_node *node; - kstat_cpu(0).irqs[irq]++; node = irq_list[irq]; do { - node->handler(irq, node->dev_id, regs); + node->handler(irq, node->dev_id); node = node->next; } while (node); } +asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs) +{ + struct pt_regs *old_regs; + old_regs = set_irq_regs(regs); + m68k_handle_int(irq); + set_irq_regs(old_regs); +} + asmlinkage void handle_badint(struct pt_regs *regs) { kstat_cpu(0).irqs[0]++; diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index f2d7ee0ee18..869c4861346 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -64,7 +64,7 @@ static char m68k_command_line[CL_SIZE]; char m68k_debug_device[6] = ""; -void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; +void (*mach_sched_init) (irqreturn_t (*handler)(int, void *)) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; void (*mach_get_model) (char *model); diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 28b2fefa451..2a599c3ed78 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -37,13 +38,13 @@ 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) { do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #ifdef CONFIG_HEARTBEAT /* use power LED as a heartbeat instead -- much more useful diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index 6eaa881793d..a1c7ec70674 100644 --- a/arch/m68k/mac/baboon.c +++ b/arch/m68k/mac/baboon.c @@ -25,7 +25,7 @@ int baboon_present,baboon_active; volatile struct baboon *baboon; -irqreturn_t baboon_irq(int, void *, struct pt_regs *); +irqreturn_t baboon_irq(int, void *); #if 0 extern int macide_ack_intr(struct ata_channel *); @@ -64,7 +64,7 @@ void __init baboon_register_interrupts(void) * Baboon interrupt handler. This works a lot like a VIA. */ -irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t baboon_irq(int irq, void *dev_id) { int irq_bit,i; unsigned char events; @@ -81,7 +81,7 @@ irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs) for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { if (events & irq_bit/* & baboon_active*/) { baboon_active &= ~irq_bit; - m68k_handle_int(IRQ_BABOON_0 + i, regs); + m68k_handle_int(IRQ_BABOON_0 + i); baboon_active |= irq_bit; baboon->mb_ifr &= ~irq_bit; } diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 85dda1095b1..029bae65c5d 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -72,7 +72,7 @@ extern int show_mac_interrupts(struct seq_file *, void *); extern void iop_preinit(void); extern void iop_init(void); extern void via_init(void); -extern void via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *)); +extern void via_init_clock(irqreturn_t (*func)(int, void *)); extern void via_flush_cache(void); extern void oss_init(void); extern void psc_init(void); @@ -88,7 +88,7 @@ extern void mac_debugging_long(int, long); static void mac_get_model(char *str); -static void mac_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *)) +static void mac_sched_init(irqreturn_t (*vector)(int, void *)) { via_init_clock(vector); } diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index bc657b1057a..0cea21f5819 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c @@ -132,7 +132,7 @@ static int iop_get_proc_info(char *, char **, off_t, int); struct listener { const char *devname; - void (*handler)(struct iop_msg *, struct pt_regs *); + void (*handler)(struct iop_msg *); }; /* @@ -152,7 +152,7 @@ static struct iop_msg iop_msg_pool[NUM_IOP_MSGS]; static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN]; static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN]; -irqreturn_t iop_ism_irq(int, void *, struct pt_regs *); +irqreturn_t iop_ism_irq(int, void *); extern void oss_irq_enable(int); @@ -342,7 +342,7 @@ void __init iop_register_interrupts(void) */ int iop_listen(uint iop_num, uint chan, - void (*handler)(struct iop_msg *, struct pt_regs *), + void (*handler)(struct iop_msg *), const char *devname) { if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; @@ -407,7 +407,7 @@ static void iop_do_send(struct iop_msg *msg) * has gone into the IOP_MSG_COMPLETE state. */ -static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs) +static void iop_handle_send(uint iop_num, uint chan) { volatile struct mac_iop *iop = iop_base[iop_num]; struct iop_msg *msg,*msg2; @@ -426,7 +426,7 @@ static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs) for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { msg->reply[i] = iop_readb(iop, offset); } - if (msg->handler) (*msg->handler)(msg, regs); + if (msg->handler) (*msg->handler)(msg); msg2 = msg; msg = msg->next; iop_free_msg(msg2); @@ -440,7 +440,7 @@ static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs) * gone into the IOP_MSG_NEW state. */ -static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs) +static void iop_handle_recv(uint iop_num, uint chan) { volatile struct mac_iop *iop = iop_base[iop_num]; int i,offset; @@ -468,7 +468,7 @@ static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs) /* the message ourselves to avoid possible stalls. */ if (msg->handler) { - (*msg->handler)(msg, regs); + (*msg->handler)(msg); } else { #ifdef DEBUG_IOP printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan); @@ -492,7 +492,7 @@ static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs) int iop_send_message(uint iop_num, uint chan, void *privdata, uint msg_len, __u8 *msg_data, - void (*handler)(struct iop_msg *, struct pt_regs *)) + void (*handler)(struct iop_msg *)) { struct iop_msg *msg, *q; @@ -584,7 +584,7 @@ __u8 *iop_compare_code(uint iop_num, __u8 *code_start, * Handle an ISM IOP interrupt */ -irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t iop_ism_irq(int irq, void *dev_id) { uint iop_num = (uint) dev_id; volatile struct mac_iop *iop = iop_base[iop_num]; @@ -608,7 +608,7 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs) printk(" %02X", state); #endif if (state == IOP_MSG_COMPLETE) { - iop_handle_send(iop_num, i, regs); + iop_handle_send(iop_num, i); } } #ifdef DEBUG_IOP @@ -628,7 +628,7 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs) printk(" %02X", state); #endif if (state == IOP_MSG_NEW) { - iop_handle_recv(iop_num, i, regs); + iop_handle_recv(iop_num, i); } } #ifdef DEBUG_IOP diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index 694b14bb0de..f6fcd754d8f 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -133,6 +133,7 @@ #include #include #include +#include #define DEBUG_SPURIOUS #define SHUTUP_SONIC @@ -208,8 +209,8 @@ static void scc_irq_disable(unsigned int); * console_loglevel determines NMI handler function */ -irqreturn_t mac_nmi_handler(int, void *, struct pt_regs *); -irqreturn_t mac_debug_handler(int, void *, struct pt_regs *); +irqreturn_t mac_nmi_handler(int, void *); +irqreturn_t mac_debug_handler(int, void *); /* #define DEBUG_MACINTS */ @@ -393,7 +394,7 @@ int mac_irq_pending(unsigned int irq) static int num_debug[8]; -irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t mac_debug_handler(int irq, void *dev_id) { if (num_debug[irq] < 10) { printk("DEBUG: Unexpected IRQ %d\n", irq); @@ -405,7 +406,7 @@ irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs) static int in_nmi; static volatile int nmi_hold; -irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp) +irqreturn_t mac_nmi_handler(int irq, void *dev_id) { int i; /* @@ -432,6 +433,7 @@ irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp) if (console_loglevel >= 8) { #if 0 + struct pt_regs *fp = get_irq_regs(); show_state(); printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", @@ -479,7 +481,7 @@ static void scc_irq_disable(unsigned int irq) * here is cleaner than hacking it into drivers/char/macserial.c. */ -void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs) +void mac_scc_dispatch(int irq, void *dev_id) { volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2; unsigned char reg; @@ -504,7 +506,7 @@ void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs) /* pretty much kill the system. */ if (reg & 0x38) - m68k_handle_int(IRQ_SCCA, regs); + m68k_handle_int(IRQ_SCCA); if (reg & 0x07) - m68k_handle_int(IRQ_SCCB, regs); + m68k_handle_int(IRQ_SCCB); } diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index 63e04365191..63690819565 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -30,11 +30,11 @@ int oss_present; volatile struct mac_oss *oss; -irqreturn_t oss_irq(int, void *, struct pt_regs *); -irqreturn_t oss_nubus_irq(int, void *, struct pt_regs *); +irqreturn_t oss_irq(int, void *); +irqreturn_t oss_nubus_irq(int, void *); -extern irqreturn_t via1_irq(int, void *, struct pt_regs *); -extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *); +extern irqreturn_t via1_irq(int, void *); +extern irqreturn_t mac_scc_dispatch(int, void *); /* * Initialize the OSS @@ -92,7 +92,7 @@ void __init oss_nubus_init(void) * and SCSI; everything else is routed to its own autovector IRQ. */ -irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t oss_irq(int irq, void *dev_id) { int events; @@ -113,7 +113,7 @@ irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs) oss->irq_pending &= ~OSS_IP_SOUND; } else if (events & OSS_IP_SCSI) { oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; - m68k_handle_int(IRQ_MAC_SCSI, regs); + m68k_handle_int(IRQ_MAC_SCSI); oss->irq_pending &= ~OSS_IP_SCSI; oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; } else { @@ -128,7 +128,7 @@ irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs) * Unlike the VIA/RBV this is on its own autovector interrupt level. */ -irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t oss_nubus_irq(int irq, void *dev_id) { int events, irq_bit, i; @@ -146,7 +146,7 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { if (events & irq_bit) { oss->irq_level[i] = OSS_IRQLEV_DISABLED; - m68k_handle_int(NUBUS_SOURCE_BASE + i, regs); + m68k_handle_int(NUBUS_SOURCE_BASE + i); oss->irq_pending &= ~irq_bit; oss->irq_level[i] = OSS_IRQLEV_NUBUS; } diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index e2621809175..15378a5878c 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -30,7 +30,7 @@ int psc_present; volatile __u8 *psc; -irqreturn_t psc_irq(int, void *, struct pt_regs *); +irqreturn_t psc_irq(int, void *); /* * Debugging dump, used in various places to see what's going on. @@ -127,7 +127,7 @@ void __init psc_register_interrupts(void) * PSC interrupt handler. It's a lot like the VIA interrupt handler. */ -irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t psc_irq(int irq, void *dev_id) { int pIFR = pIFRbase + ((int) dev_id); int pIER = pIERbase + ((int) dev_id); @@ -149,7 +149,7 @@ irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs) for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { if (events & irq_bit) { psc_write_byte(pIER, irq_bit); - m68k_handle_int(base_irq + i, regs); + m68k_handle_int(base_irq + i); psc_write_byte(pIFR, irq_bit); psc_write_byte(pIER, irq_bit | 0x80); } diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index c4aa345d544..9b6c80c4bbe 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -63,14 +63,14 @@ static int gIER,gIFR,gBufA,gBufB; static int nubus_active; void via_debug_dump(void); -irqreturn_t via1_irq(int, void *, struct pt_regs *); -irqreturn_t via2_irq(int, void *, struct pt_regs *); -irqreturn_t via_nubus_irq(int, void *, struct pt_regs *); +irqreturn_t via1_irq(int, void *); +irqreturn_t via2_irq(int, void *); +irqreturn_t via_nubus_irq(int, void *); void via_irq_enable(int irq); void via_irq_disable(int irq); void via_irq_clear(int irq); -extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *); +extern irqreturn_t mac_scc_dispatch(int, void *); extern int oss_present; /* @@ -235,7 +235,7 @@ void __init via_init(void) * Start the 100 Hz clock */ -void __init via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *)) +void __init via_init_clock(irqreturn_t (*func)(int, void *)) { via1[vACR] |= 0x40; via1[vT1LL] = MAC_CLOCK_LOW; @@ -412,7 +412,7 @@ void __init via_nubus_init(void) * the machspec interrupt number after clearing the interrupt. */ -irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t via1_irq(int irq, void *dev_id) { int irq_bit, i; unsigned char events, mask; @@ -424,7 +424,7 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs) for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) if (events & irq_bit) { via1[vIER] = irq_bit; - m68k_handle_int(VIA1_SOURCE_BASE + i, regs); + m68k_handle_int(VIA1_SOURCE_BASE + i); via1[vIFR] = irq_bit; via1[vIER] = irq_bit | 0x80; } @@ -439,14 +439,14 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs) /* No, it won't be set. that's why we're doing this. */ via_irq_disable(IRQ_MAC_NUBUS); via_irq_clear(IRQ_MAC_NUBUS); - m68k_handle_int(IRQ_MAC_NUBUS, regs); + m68k_handle_int(IRQ_MAC_NUBUS); via_irq_enable(IRQ_MAC_NUBUS); } #endif return IRQ_HANDLED; } -irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t via2_irq(int irq, void *dev_id) { int irq_bit, i; unsigned char events, mask; @@ -459,7 +459,7 @@ irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs) if (events & irq_bit) { via2[gIER] = irq_bit; via2[gIFR] = irq_bit | rbv_clear; - m68k_handle_int(VIA2_SOURCE_BASE + i, regs); + m68k_handle_int(VIA2_SOURCE_BASE + i); via2[gIER] = irq_bit | 0x80; } return IRQ_HANDLED; @@ -470,7 +470,7 @@ irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs) * VIA2 dispatcher as a fast interrupt handler. */ -irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t via_nubus_irq(int irq, void *dev_id) { int irq_bit, i; unsigned char events; @@ -481,7 +481,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { if (events & irq_bit) { via_irq_disable(NUBUS_SOURCE_BASE + i); - m68k_handle_int(NUBUS_SOURCE_BASE + i, regs); + m68k_handle_int(NUBUS_SOURCE_BASE + i); via_irq_enable(NUBUS_SOURCE_BASE + i); } } diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 0cd0e5bddce..c864d641518 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -38,7 +38,7 @@ static void mvme147_get_model(char *model); static int mvme147_get_hardware_list(char *buffer); -extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *)); extern unsigned long mvme147_gettimeoffset (void); extern int mvme147_hwclk (int, struct rtc_time *); extern int mvme147_set_clock_mmss (unsigned long); @@ -51,7 +51,7 @@ static int bcd2int (unsigned char b); /* Save tick handler routine pointer, will point to do_timer() in * kernel/sched.c, called via mvme147_process_int() */ -irqreturn_t (*tick_handler)(int, void *, struct pt_regs *); +irqreturn_t (*tick_handler)(int, void *); int mvme147_parse_bootinfo(const struct bi_record *bi) @@ -114,15 +114,15 @@ void __init config_mvme147(void) /* Using pcc tick timer 1 */ -static irqreturn_t mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t mvme147_timer_int (int irq, void *dev_id) { m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; - return tick_handler(irq, dev_id, fp); + return tick_handler(irq, dev_id); } -void mvme147_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) +void mvme147_sched_init (irqreturn_t (*timer_routine)(int, void *)) { tick_handler = timer_routine; request_irq (PCC_IRQ_TIMER1, mvme147_timer_int, diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index ce2727ed1bc..2c91cee1709 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -42,7 +42,7 @@ static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE; static void mvme16x_get_model(char *model); static int mvme16x_get_hardware_list(char *buffer); -extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *)); extern unsigned long mvme16x_gettimeoffset (void); extern int mvme16x_hwclk (int, struct rtc_time *); extern int mvme16x_set_clock_mmss (unsigned long); @@ -54,7 +54,7 @@ int bcd2int (unsigned char b); /* Save tick handler routine pointer, will point to do_timer() in * kernel/sched.c, called via mvme16x_process_int() */ -static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *); +static irqreturn_t (*tick_handler)(int, void *); unsigned short mvme16x_config; @@ -190,7 +190,7 @@ void __init config_mvme16x(void) } } -static irqreturn_t mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) { p_bdid p = &mvme_bdid; unsigned long *new = (unsigned long *)vectors; @@ -218,13 +218,13 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp) return IRQ_HANDLED; } -static irqreturn_t mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) { *(volatile unsigned char *)0xfff4201b |= 8; - return tick_handler(irq, dev_id, fp); + return tick_handler(irq, dev_id); } -void mvme16x_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) +void mvme16x_sched_init (irqreturn_t (*timer_routine)(int, void *)) { p_bdid p = &mvme_bdid; int irq; diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 9a182787640..5123f693948 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c @@ -39,7 +39,7 @@ extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); extern void q40_init_IRQ (void); static void q40_get_model(char *model); static int q40_get_hardware_list(char *buffer); -extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +extern void q40_sched_init(irqreturn_t (*handler)(int, void *)); extern unsigned long q40_gettimeoffset (void); extern int q40_hwclk (int, struct rtc_time *); diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 472f41c4158..4a4ee4dfa6f 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -125,9 +125,9 @@ void q40_mksound(unsigned int hz, unsigned int ticks) sound_ticks = ticks << 1; } -static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *); +static irqreturn_t (*q40_timer_routine)(int, void *); -static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs) +static irqreturn_t q40_timer_int (int irq, void * dev) { ql_ticks = ql_ticks ? 0 : 1; if (sound_ticks) { @@ -138,11 +138,11 @@ static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs) } if (!ql_ticks) - q40_timer_routine(irq, dev, regs); + q40_timer_routine(irq, dev); return IRQ_HANDLED; } -void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) +void q40_sched_init (irqreturn_t (*timer_routine)(int, void *)) { int timer_irq; @@ -218,11 +218,11 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp) switch (irq) { case 4: case 6: - m68k_handle_int(Q40_IRQ_SAMPLE, fp); + __m68k_handle_int(Q40_IRQ_SAMPLE, fp); return; } if (mir & Q40_IRQ_FRAME_MASK) { - m68k_handle_int(Q40_IRQ_FRAME, fp); + __m68k_handle_int(Q40_IRQ_FRAME, fp); master_outb(-1, FRAME_CLEAR_REG); } if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) { @@ -257,7 +257,7 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp) goto iirq; } q40_state[irq] |= IRQ_INPROGRESS; - m68k_handle_int(irq, fp); + __m68k_handle_int(irq, fp); q40_state[irq] &= ~IRQ_INPROGRESS; /* naively enable everything, if that fails than */ @@ -288,7 +288,7 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp) mir = master_inb(IIRQ_REG); /* should test whether keyboard irq is really enabled, doing it in defhand */ if (mir & Q40_IRQ_KEYB_MASK) - m68k_handle_int(Q40_IRQ_KEYBOARD, fp); + __m68k_handle_int(Q40_IRQ_KEYBOARD, fp); return; } diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index d09d03b3d95..db930f9070e 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -162,7 +162,7 @@ void __init config_sun3(void) sun3_bootmem_alloc(memory_start, memory_end); } -void __init sun3_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) +void __init sun3_sched_init(irqreturn_t (*timer_routine)(int, void *)) { sun3_disable_interrupts(); intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE); diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c index dc4ea7e074a..baf74e8de8b 100644 --- a/arch/m68k/sun3/sun3ints.c +++ b/arch/m68k/sun3/sun3ints.c @@ -15,6 +15,7 @@ #include #include #include +#include #include extern void sun3_leds (unsigned char); @@ -48,7 +49,7 @@ void sun3_disable_irq(unsigned int irq) *sun3_intreg &= ~(1 << irq); } -static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t sun3_int7(int irq, void *dev_id) { *sun3_intreg |= (1 << irq); if (!(kstat_cpu(0).irqs[irq] % 2000)) @@ -56,7 +57,7 @@ static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp) return IRQ_HANDLED; } -static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t sun3_int5(int irq, void *dev_id) { #ifdef CONFIG_SUN3 intersil_clear(); @@ -67,14 +68,14 @@ static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp) #endif do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(fp)); + update_process_times(user_mode(get_irq_regs())); #endif if (!(kstat_cpu(0).irqs[irq] % 20)) sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]); return IRQ_HANDLED; } -static irqreturn_t sun3_vec255(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t sun3_vec255(int irq, void *dev_id) { // intersil_clear(); return IRQ_HANDLED; @@ -84,7 +85,7 @@ static void sun3_inthandle(unsigned int irq, struct pt_regs *fp) { *sun3_intreg &= ~(1 << irq); - m68k_handle_int(irq, fp); + __m68k_handle_int(irq, fp); } static struct irq_controller sun3_irq_controller = { diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c index 6f4204fbecd..33eb1ecc888 100644 --- a/arch/m68k/sun3x/time.c +++ b/arch/m68k/sun3x/time.c @@ -90,7 +90,7 @@ static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs) } #endif -void __init sun3x_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *)) +void __init sun3x_sched_init(irqreturn_t (*vector)(int, void *)) { sun3_disable_interrupts(); diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h index e7e43b4ec4a..e39079c781d 100644 --- a/arch/m68k/sun3x/time.h +++ b/arch/m68k/sun3x/time.h @@ -3,7 +3,7 @@ extern int sun3x_hwclk(int set, struct rtc_time *t); unsigned long sun3x_gettimeoffset (void); -void sun3x_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *)); +void sun3x_sched_init(irqreturn_t (*vector)(int, void *)); struct mostek_dt { volatile unsigned char csr; diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 0cdbaa70cf9..d0b94dd1af6 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -593,7 +593,7 @@ static void scc_enable_tx_interrupts(void *ptr) local_irq_save(flags); SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); /* restart the transmitter */ - scc_tx_int (0, port, 0); + scc_tx_int (0, port); local_irq_restore(flags); } diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index 1ffee7aaff2..17ef5d3c01b 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -266,7 +266,7 @@ int adb_iop_autopoll(int devs) void adb_iop_poll(void) { if (adb_iop_state == idle) adb_iop_start(); - iop_ism_irq(0, (void *) ADB_IOP, NULL); + iop_ism_irq(0, (void *) ADB_IOP); } int adb_iop_reset_bus(void) diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index ad4bd579f61..5d88d5b0ad9 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -295,7 +295,7 @@ static void macii_poll(void) unsigned long flags; local_irq_save(flags); - if (via[IFR] & SR_INT) macii_interrupt(0, NULL, NULL); + if (via[IFR] & SR_INT) macii_interrupt(0, NULL); local_irq_restore(flags); } diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 789ee52086f..1f0aa5dc9aa 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c @@ -421,7 +421,7 @@ maciisi_poll(void) local_irq_save(flags); if (via[IFR] & SR_INT) { - maciisi_interrupt(0, NULL, NULL); + maciisi_interrupt(0, NULL); } else /* avoid calling this function too quickly in a loop */ udelay(ADB_DELAY); diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 98ec915d040..d9986f3a3fb 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -221,7 +221,7 @@ pmu_init(void) } if (pmu_state == idle) { adb_int_pending = 1; - pmu_interrupt(0, NULL, NULL); + pmu_interrupt(0, NULL); } pmu_poll(); udelay(10); @@ -562,11 +562,11 @@ pmu_poll(void) local_irq_save(flags); if (via1[IFR] & SR_INT) { via1[IFR] = SR_INT; - pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL); + pmu_interrupt(IRQ_MAC_ADB_SR, NULL); } if (via1[IFR] & CB1_INT) { via1[IFR] = CB1_INT; - pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL); + pmu_interrupt(IRQ_MAC_ADB_CL, NULL); } local_irq_restore(flags); } diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 8e996b4a34e..7733697f777 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -674,7 +674,7 @@ void lance_poll(struct net_device *dev) WRITERAP(lp, LE_CSR0); WRITERDP(lp, LE_C0_STRT); spin_unlock (&lp->devlock); - lance_interrupt(dev->irq, dev, NULL); + lance_interrupt(dev->irq, dev); } #endif diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c index 6541cde4df0..e5b0a544de4 100644 --- a/drivers/parport/parport_mfc3.c +++ b/drivers/parport/parport_mfc3.c @@ -219,7 +219,7 @@ static irqreturn_t mfc3_interrupt(int irq, void *dev_id) if (this_port[i] != NULL) if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */ dummy = pia(this_port[i])->pprb; /* clear irq bit */ - parport_generic_irq(irq, this_port[i], regs); + parport_generic_irq(irq, this_port[i]); } return IRQ_HANDLED; } diff --git a/include/asm-m68k/atari_stdma.h b/include/asm-m68k/atari_stdma.h index b4eadf85273..a6986af7915 100644 --- a/include/asm-m68k/atari_stdma.h +++ b/include/asm-m68k/atari_stdma.h @@ -8,8 +8,7 @@ /***************************** Prototypes *****************************/ -void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *), - void *data); +void stdma_lock(irqreturn_t (*handler)(int, void *), void *data); void stdma_release( void ); int stdma_others_waiting( void ); int stdma_islocked( void ); diff --git a/include/asm-m68k/floppy.h b/include/asm-m68k/floppy.h index 57f4fdda65a..45dc908932a 100644 --- a/include/asm-m68k/floppy.h +++ b/include/asm-m68k/floppy.h @@ -17,8 +17,7 @@ #include -asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id, - struct pt_regs *regs); +asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id); /* constants... */ @@ -184,8 +183,7 @@ static void fd_disable_dma(void) /* this is the only truly Q40 specific function */ -asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id, - struct pt_regs *regs) +asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id) { register unsigned char st; @@ -198,7 +196,7 @@ asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id, static int dma_wait=0; #endif if(!doing_pdma) { - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); return IRQ_HANDLED; } @@ -246,7 +244,7 @@ asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id, 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-m68k/ide.h b/include/asm-m68k/ide.h index 365f76fb801..896683a7a1f 100644 --- a/include/asm-m68k/ide.h +++ b/include/asm-m68k/ide.h @@ -123,7 +123,7 @@ static __inline__ void ide_release_lock (void) } static __inline__ void -ide_get_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *), void *data) +ide_get_lock(irqreturn_t (*handler)(int, void *), void *data) { if (MACH_IS_ATARI) { if (falconide_intr_lock == 0) { diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h index 3257f988100..4901cb105e2 100644 --- a/include/asm-m68k/irq.h +++ b/include/asm-m68k/irq.h @@ -83,7 +83,7 @@ struct pt_regs; * interrupt source (if it supports chaining). */ typedef struct irq_node { - int (*handler)(int, void *, struct pt_regs *); + int (*handler)(int, void *); void *dev_id; struct irq_node *next; unsigned long flags; @@ -93,12 +93,12 @@ typedef struct irq_node { /* * This structure has only 4 elements for speed reasons */ -typedef struct irq_handler { - int (*handler)(int, void *, struct pt_regs *); +struct irq_handler { + int (*handler)(int, void *); unsigned long flags; void *dev_id; const char *devname; -} irq_handler_t; +}; struct irq_controller { const char *name; @@ -122,6 +122,7 @@ extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, void (*handler)(unsigned int, struct pt_regs *)); extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int); -asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *); +asmlinkage void m68k_handle_int(unsigned int); +asmlinkage void __m68k_handle_int(unsigned int, struct pt_regs *); #endif /* _M68K_IRQ_H_ */ diff --git a/include/asm-m68k/mac_iop.h b/include/asm-m68k/mac_iop.h index b0d2e347353..a2c7e6fcca3 100644 --- a/include/asm-m68k/mac_iop.h +++ b/include/asm-m68k/mac_iop.h @@ -143,17 +143,17 @@ struct iop_msg { int status; /* status of this message */ __u8 message[IOP_MSG_LEN]; /* the message being sent/received */ __u8 reply[IOP_MSG_LEN]; /* the reply to the message */ - void (*handler)(struct iop_msg *, struct pt_regs *); + void (*handler)(struct iop_msg *); /* function to call when reply recvd */ }; extern int iop_scc_present,iop_ism_present; extern int iop_listen(uint, uint, - void (*handler)(struct iop_msg *, struct pt_regs *), + void (*handler)(struct iop_msg *), const char *); extern int iop_send_message(uint, uint, void *, uint, __u8 *, - void (*)(struct iop_msg *, struct pt_regs *)); + void (*)(struct iop_msg *)); extern void iop_complete_message(struct iop_msg *); extern void iop_upload_code(uint, __u8 *, uint, __u16); extern void iop_download_code(uint, __u8 *, uint, __u16); diff --git a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h index df898f27e43..862afa4c35d 100644 --- a/include/asm-m68k/machdep.h +++ b/include/asm-m68k/machdep.h @@ -10,7 +10,7 @@ struct rtc_time; struct rtc_pll_info; struct buffer_head; -extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)); +extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *)); /* machine dependent irq functions */ extern void (*mach_init_IRQ) (void); extern void (*mach_get_model) (char *model); diff --git a/include/asm-m68k/sun3xflop.h b/include/asm-m68k/sun3xflop.h index ca8cc411384..32c45f84ac6 100644 --- a/include/asm-m68k/sun3xflop.h +++ b/include/asm-m68k/sun3xflop.h @@ -111,8 +111,7 @@ static void sun3x_82072_fd_outb(unsigned char value, int port) } -asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id, - struct pt_regs * regs) +asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id) { register unsigned char st; @@ -125,7 +124,7 @@ asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id, static int dma_wait=0; #endif if(!doing_pdma) { - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); return IRQ_HANDLED; } @@ -189,7 +188,7 @@ asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id, dma_wait=0; #endif - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); return IRQ_HANDLED; } -- GitLab From 8774cb815f2492a95b90a927f93a2de555753b32 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 7 Oct 2006 14:17:31 +0100 Subject: [PATCH 0764/1619] [PATCH] minimal alpha pt_regs fixes Signed-off-by: Al Viro Acked-by: Jeff Garzik Signed-off-by: Linus Torvalds --- arch/alpha/kernel/irq.c | 5 ++++- arch/alpha/kernel/proto.h | 2 +- arch/alpha/kernel/smp.c | 6 +++++- arch/alpha/kernel/time.c | 6 +++--- include/asm-alpha/irq_regs.h | 1 + 5 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 include/asm-alpha/irq_regs.h diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 729c475d226..dba4e70926f 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -129,6 +129,7 @@ unlock: void handle_irq(int irq, struct pt_regs * regs) { + struct pt_regs *old_regs; /* * We ack quickly, we don't want the irq controller * thinking we're snobs just because some other CPU has @@ -149,6 +150,7 @@ handle_irq(int irq, struct pt_regs * regs) return; } + old_regs = set_irq_regs(regs); irq_enter(); /* * __do_IRQ() must be called with IPL_MAX. Note that we do not @@ -157,6 +159,7 @@ handle_irq(int irq, struct pt_regs * regs) * at IPL 0. */ local_irq_disable(); - __do_IRQ(irq, regs); + __do_IRQ(irq); irq_exit(); + set_irq_regs(old_regs); } diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 21f71287b6f..408bda25b0b 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -133,7 +133,7 @@ extern void smp_percpu_timer_interrupt(struct pt_regs *); /* extern void reset_for_srm(void); */ /* time.c */ -extern irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs); +extern irqreturn_t timer_interrupt(int irq, void *dev); extern void common_init_rtc(void); extern unsigned long est_cycle_freq; diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 4dc273e537f..596780e2c7d 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -515,12 +515,15 @@ smp_cpus_done(unsigned int max_cpus) void smp_percpu_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs; int cpu = smp_processor_id(); unsigned long user = user_mode(regs); struct cpuinfo_alpha *data = &cpu_data[cpu]; + old_regs = set_irq_regs(regs); + /* Record kernel PC. */ - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if (!--data->prof_counter) { /* We need to make like a normal interrupt -- otherwise @@ -534,6 +537,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs) irq_exit(); } + set_irq_regs(old_regs); } int __init diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 581ddcc22fc..cf066652398 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -104,7 +104,7 @@ unsigned long long sched_clock(void) * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs) +irqreturn_t timer_interrupt(int irq, void *dev) { unsigned long delta; __u32 now; @@ -112,7 +112,7 @@ irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs) #ifndef CONFIG_SMP /* Not SMP, do kernel PC profiling here. */ - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #endif write_seqlock(&xtime_lock); @@ -132,7 +132,7 @@ irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs) while (nticks > 0) { do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif nticks--; } diff --git a/include/asm-alpha/irq_regs.h b/include/asm-alpha/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-alpha/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 9c8e7f5cc965d30006c917ab19221e06fcc5a4f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 7 Oct 2006 16:29:18 +0100 Subject: [PATCH 0765/1619] [PATCH] m32r pt_regs fixes ... and now with irq_regs.h not forgotten... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/irq.c | 5 ++++- arch/m32r/kernel/smp.c | 13 ++++++++----- arch/m32r/kernel/time.c | 10 +++++----- drivers/net/smc91x.c | 2 +- drivers/pcmcia/m32r_pcc.c | 2 +- drivers/serial/m32r_sio.c | 2 +- include/asm-m32r/irq_regs.h | 1 + 7 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 include/asm-m32r/irq_regs.h diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c index 3841861df6a..f8d8650383e 100644 --- a/arch/m32r/kernel/irq.c +++ b/arch/m32r/kernel/irq.c @@ -77,13 +77,16 @@ skip: */ asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) { + struct pt_regs *old_regs; + old_regs = set_irq_regs(regs); irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW /* FIXME M32R */ #endif - __do_IRQ(irq, regs); + __do_IRQ(irq); irq_exit(); + set_irq_regs(old_regs); return 1; } diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index 8b1f6eb7687..722e21f556d 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -101,7 +101,7 @@ void smp_call_function_interrupt(void); void smp_send_timer(void); void smp_ipi_timer_interrupt(struct pt_regs *); -void smp_local_timer_interrupt(struct pt_regs *); +void smp_local_timer_interrupt(void); void send_IPI_allbutself(int, int); static void send_IPI_mask(cpumask_t, int, int); @@ -734,9 +734,12 @@ void smp_send_timer(void) *==========================================================================*/ void smp_ipi_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs; + old_regs = set_irq_regs(regs); irq_enter(); - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); irq_exit(); + set_irq_regs(old_regs); } /*==========================================================================* @@ -762,9 +765,9 @@ void smp_ipi_timer_interrupt(struct pt_regs *regs) * ---------- --- -------------------------------------------------------- * 2003-06-24 hy use per_cpu structure. *==========================================================================*/ -void smp_local_timer_interrupt(struct pt_regs *regs) +void smp_local_timer_interrupt(void) { - int user = user_mode(regs); + int user = user_mode(get_irq_regs()); int cpu_id = smp_processor_id(); /* @@ -774,7 +777,7 @@ void smp_local_timer_interrupt(struct pt_regs *regs) * useful with a profiling multiplier != 1 */ - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if (--per_cpu(prof_counter, cpu_id) <= 0) { /* diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c index d8af155db98..a09038282c7 100644 --- a/arch/m32r/kernel/time.c +++ b/arch/m32r/kernel/time.c @@ -35,7 +35,7 @@ #ifdef CONFIG_SMP extern void send_IPI_allbutself(int, int); -extern void smp_local_timer_interrupt(struct pt_regs *); +extern void smp_local_timer_interrupt(void); #endif #define TICK_SIZE (tick_nsec / 1000) @@ -188,15 +188,15 @@ static long last_rtc_update = 0; * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t timer_interrupt(int irq, void *dev_id) { #ifndef CONFIG_SMP - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #endif do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif /* * If we have an externally synchronized Linux clock, then update @@ -221,7 +221,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) a hack, so don't look closely for now.. */ #ifdef CONFIG_SMP - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); smp_send_timer(); #endif diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 506807fa526..95b6478f55c 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1400,7 +1400,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) static void smc_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - smc_interrupt(dev->irq, dev, NULL); + smc_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 0964fd76bfe..bbf025874d0 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -395,7 +395,7 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) static void pcc_interrupt_wrapper(u_long data) { - pcc_interrupt(0, NULL, NULL); + pcc_interrupt(0, NULL); init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index c85ac1a7760..7656a35f5e2 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -590,7 +590,7 @@ static void m32r_sio_timeout(unsigned long data) sts = sio_in(up, SIOSTS); if (sts & 0x5) { spin_lock(&up->port.lock); - m32r_sio_handle_port(up, sts, NULL); + m32r_sio_handle_port(up, sts); spin_unlock(&up->port.lock); } diff --git a/include/asm-m32r/irq_regs.h b/include/asm-m32r/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-m32r/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 59d6ab86a6b1097d5e5eae5d820f8e2661009324 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 6 Oct 2006 17:36:20 +0100 Subject: [PATCH 0766/1619] [MIPS] Update Malta config. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 20 +++---- arch/mips/configs/malta_defconfig | 98 +++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 33 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8a49884bd5e..731b942a824 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1465,10 +1465,8 @@ config MIPS_MT_DISABLED the option of an MT-enabled processor this option will be the only option in this menu. -config MIPS_MT_SMTC - bool "SMTC: Use all TCs on all VPEs for SMP" - depends on CPU_MIPS32_R2 - #depends on CPU_MIPS64_R2 # once there is hardware ... +config MIPS_MT_SMP + bool "Use 1 TC on each available VPE for SMP" depends on SYS_SUPPORTS_MULTITHREADING select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_SRS @@ -1476,11 +1474,13 @@ config MIPS_MT_SMTC select SMP select SYS_SUPPORTS_SMP help - This is a kernel model which is known a SMTC or lately has been - marketesed into SMVP. + This is a kernel model which is also known a VSMP or lately + has been marketesed into SMVP. -config MIPS_MT_SMP - bool "Use 1 TC on each available VPE for SMP" +config MIPS_MT_SMTC + bool "SMTC: Use all TCs on all VPEs for SMP" + depends on CPU_MIPS32_R2 + #depends on CPU_MIPS64_R2 # once there is hardware ... depends on SYS_SUPPORTS_MULTITHREADING select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_SRS @@ -1488,8 +1488,8 @@ config MIPS_MT_SMP select SMP select SYS_SUPPORTS_SMP help - This is a kernel model which is also known a VSMP or lately - has been marketesed into SMVP. + This is a kernel model which is known a SMTC or lately has been + marketesed into SMVP. config MIPS_VPE_LOADER bool "VPE loader support." diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index aeefe2873e3..101e80347dc 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:13 2006 +# Linux kernel version: 2.6.19-rc1 +# Fri Oct 6 17:34:55 2006 # CONFIG_MIPS=y @@ -25,8 +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_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 @@ -67,6 +65,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_DMA_NONCOHERENT=y @@ -134,19 +133,19 @@ CONFIG_MIPS_CPU_SCACHE=y CONFIG_CPU_HAS_PREFETCH=y # CONFIG_MIPS_MT_DISABLED is not set # CONFIG_MIPS_MT_SMTC is not set -# CONFIG_MIPS_MT_SMP is not set -CONFIG_MIPS_VPE_LOADER=y +CONFIG_MIPS_MT_SMP=y +# CONFIG_MIPS_VPE_LOADER is not set CONFIG_MIPS_MT=y CONFIG_SYS_SUPPORTS_MULTITHREADING=y CONFIG_MIPS_MT_FPAFF=y -CONFIG_MIPS_VPE_LOADER_TOM=y -CONFIG_MIPS_VPE_APSP_API=y -CONFIG_MIPS_APSP_KSPD=y # CONFIG_64BIT_PHYS_ADDR is not set CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_MIPSR2_IRQ_VI=y +CONFIG_CPU_MIPSR2_SRS=y CONFIG_CPU_HAS_SYNC=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_IRQ_PER_CPU=y CONFIG_CPU_SUPPORTS_HIGHMEM=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_SELECT_MEMORY_MODEL=y @@ -158,6 +157,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set +CONFIG_SMP=y +CONFIG_SYS_SUPPORTS_SMP=y +CONFIG_NR_CPUS=2 # CONFIG_HZ_48 is not set CONFIG_HZ_100=y # CONFIG_HZ_128 is not set @@ -170,6 +172,7 @@ CONFIG_HZ=100 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -178,7 +181,7 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 # @@ -188,15 +191,20 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +# CONFIG_CPUSETS is not set CONFIG_RELAY=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_HOTPLUG=y @@ -204,12 +212,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -223,10 +231,12 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set @@ -249,6 +259,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_HW_HAS_PCI=y CONFIG_PCI=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set CONFIG_MMU=y # @@ -282,6 +293,7 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_XFRM=y CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set CONFIG_NET_KEY=y CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -313,10 +325,12 @@ CONFIG_INET_XFRM_TUNNEL=m CONFIG_INET_TUNNEL=m CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # # IP: Virtual Server Configuration @@ -358,11 +372,16 @@ CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m CONFIG_INET6_XFRM_MODE_TRANSPORT=m CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set CONFIG_NETWORK_SECMARK=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -377,6 +396,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m CONFIG_NETFILTER_XTABLES=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m CONFIG_NETFILTER_XT_TARGET_NOTRACK=m @@ -387,6 +407,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m CONFIG_NETFILTER_XT_MATCH_DCCP=m +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set CONFIG_NETFILTER_XT_MATCH_ESP=m CONFIG_NETFILTER_XT_MATCH_HELPER=m CONFIG_NETFILTER_XT_MATCH_LENGTH=m @@ -429,7 +450,6 @@ CONFIG_IP_NF_MATCH_IPRANGE=m CONFIG_IP_NF_MATCH_TOS=m CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_OWNER=m @@ -457,7 +477,6 @@ CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_RAW=m @@ -536,13 +555,12 @@ CONFIG_LLC=m # CONFIG_LLC2 is not set # CONFIG_IPX is not set CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=y +CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y CONFIG_IPDDP_DECAP=y # CONFIG_X25 is not set # CONFIG_LAPB is not set -CONFIG_NET_DIVERT=y # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -604,6 +622,7 @@ CONFIG_IEEE80211_CRYPT_CCMP=m CONFIG_IEEE80211_SOFTMAC=m # CONFIG_IEEE80211_SOFTMAC_DEBUG is not set CONFIG_WIRELESS_EXT=y +CONFIG_FIB_RULES=y # # Device Drivers @@ -652,6 +671,7 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD_BUFFERS=8 @@ -662,6 +682,7 @@ CONFIG_ATA_OVER_ETH=m # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -699,6 +720,7 @@ CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_IT821X is not set @@ -721,6 +743,7 @@ CONFIG_IDEDMA_AUTO=y # CONFIG_RAID_ATTRS=m CONFIG_SCSI=m +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -742,12 +765,13 @@ CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y # -# SCSI Transport Attributes +# SCSI Transports # CONFIG_SCSI_SPI_ATTRS=m CONFIG_SCSI_FC_ATTRS=m CONFIG_SCSI_ISCSI_ATTRS=m CONFIG_SCSI_SAS_ATTRS=m +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers @@ -765,27 +789,34 @@ CONFIG_AIC7XXX_DEBUG_MASK=0 CONFIG_AIC7XXX_REG_PRETTY_PRINT=y # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set # CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set -# CONFIG_SCSI_SATA is not set # CONFIG_SCSI_HPTIOP is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + # # Multi-device support (RAID and LVM) # @@ -800,6 +831,7 @@ CONFIG_MD_RAID5_RESHAPE=y CONFIG_MD_MULTIPATH=m CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m @@ -854,6 +886,7 @@ CONFIG_LXT_PHY=m CONFIG_CICADA_PHY=m CONFIG_VITESSE_PHY=m CONFIG_SMSC_PHY=m +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) @@ -873,6 +906,7 @@ CONFIG_MII=y # CONFIG_HP100 is not set CONFIG_NET_PCI=y CONFIG_PCNET32=y +# CONFIG_PCNET32_NAPI is not set # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set @@ -909,6 +943,7 @@ CONFIG_PCNET32=y # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -956,6 +991,7 @@ CONFIG_PCNET32=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -1070,12 +1106,12 @@ CONFIG_RTC=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -1093,6 +1129,7 @@ CONFIG_VIDEO_V4L2=y # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -1191,6 +1228,7 @@ CONFIG_XFS_QUOTA=y CONFIG_XFS_SECURITY=y CONFIG_XFS_POSIX_ACL=y # CONFIG_XFS_RT is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set CONFIG_MINIX_FS=m CONFIG_ROMFS_FS=m @@ -1230,8 +1268,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set @@ -1279,7 +1319,6 @@ CONFIG_SUNRPC=y # 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 @@ -1335,6 +1374,11 @@ CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=m +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + # # Profiling support # @@ -1345,10 +1389,11 @@ CONFIG_NLS_UTF8=m # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 +CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_FS is not set CONFIG_CROSSCOMPILE=y CONFIG_CMDLINE="" @@ -1363,6 +1408,10 @@ CONFIG_CMDLINE="" # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_MD4=m @@ -1372,9 +1421,12 @@ CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m -- GitLab From 5c90d528b21cb9506713f92730f33246b80ecc25 Mon Sep 17 00:00:00 2001 From: Scott Ashcroft Date: Fri, 6 Oct 2006 16:54:54 +0100 Subject: [PATCH 0767/1619] [MIPS] Cobalt: Time runs too quickly A kernel built with HZ==250 runs about 4 four times too quickly on a Cobalt RaQ2. Signed-off-by: Scott Ashcroft Signed-off-by: Ralf Baechle --- arch/mips/cobalt/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 0b347cffc76..bf9dc72b972 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -50,8 +50,8 @@ const char *get_system_type(void) void __init plat_timer_setup(struct irqaction *irq) { - /* Load timer value for 1KHz (TCLK is 50MHz) */ - GALILEO_OUTL(50*1000*1000 / 1000, GT_TC0_OFS); + /* Load timer value for HZ (TCLK is 50MHz) */ + GALILEO_OUTL(50*1000*1000 / HZ, GT_TC0_OFS); /* Enable timer */ GALILEO_OUTL(GALILEO_ENTC0 | GALILEO_SELTC0, GT_TC_CONTROL_OFS); -- GitLab From 31aa36658a123263a9a69896e348b9600e050679 Mon Sep 17 00:00:00 2001 From: Karl-Johan Karlsson Date: Sun, 8 Oct 2006 01:15:02 +0200 Subject: [PATCH 0768/1619] [MIPS] Show actual CPU information in /proc/cpuinfo Currently, /proc/cpuinfo contains several copies of the information for whatever processor we happen to be scheduled on. This patch makes it contain the proper information for each CPU, which is particularly useful on mixed R12k/R10k IP27 machines. Signed-off-by: Karl-Johan Karlsson Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index d8beef10790..46ee5a68ab1 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -89,9 +89,9 @@ static const char *cpu_name[] = { static int show_cpuinfo(struct seq_file *m, void *v) { - unsigned int version = current_cpu_data.processor_id; - unsigned int fp_vers = current_cpu_data.fpu_id; unsigned long n = (unsigned long) v - 1; + unsigned int version = cpu_data[n].processor_id; + unsigned int fp_vers = cpu_data[n].fpu_id; char fmt [64]; #ifdef CONFIG_SMP @@ -108,8 +108,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", cpu_has_fpu ? " FPU V%d.%d" : ""); - seq_printf(m, fmt, cpu_name[current_cpu_data.cputype <= CPU_LAST ? - current_cpu_data.cputype : CPU_UNKNOWN], + seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ? + cpu_data[n].cputype : CPU_UNKNOWN], (version >> 4) & 0x0f, version & 0x0f, (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", @@ -118,7 +118,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); seq_printf(m, "microsecond timers\t: %s\n", cpu_has_counter ? "yes" : "no"); - seq_printf(m, "tlb_entries\t\t: %d\n", current_cpu_data.tlbsize); + seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize); seq_printf(m, "extra interrupt vector\t: %s\n", cpu_has_divec ? "yes" : "no"); seq_printf(m, "hardware watchpoint\t: %s\n", -- GitLab From 937a801576f954bd030d7c4a5a94571710d87c0b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 7 Oct 2006 19:44:33 +0100 Subject: [PATCH 0769/1619] [MIPS] Complete fixes after removal of pt_regs argument to int handlers. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/dma.c | 2 +- arch/mips/au1000/common/irq.c | 52 ++++----- arch/mips/au1000/common/time.c | 13 ++- arch/mips/au1000/common/usbdev.c | 9 +- arch/mips/au1000/pb1200/irqmap.c | 5 +- arch/mips/basler/excite/excite_dbg_io.c | 2 +- arch/mips/basler/excite/excite_iodev.c | 14 +-- arch/mips/basler/excite/excite_irq.c | 18 +-- arch/mips/cobalt/irq.c | 51 ++++----- arch/mips/ddb5xxx/ddb5477/irq.c | 19 ++-- arch/mips/dec/int-handler.S | 4 +- arch/mips/emma2rh/common/irq.c | 12 +- arch/mips/emma2rh/markeins/irq.c | 14 +-- arch/mips/gt64120/common/time.c | 5 +- arch/mips/gt64120/ev64120/irq.c | 14 +-- arch/mips/gt64120/momenco_ocelot/irq.c | 22 ++-- arch/mips/gt64120/wrppmc/irq.c | 10 +- arch/mips/jazz/irq.c | 30 ++--- arch/mips/jmr3927/rbhma3100/irq.c | 106 +++++++++--------- arch/mips/kernel/asm-offsets.c | 3 +- arch/mips/kernel/entry.S | 1 - arch/mips/kernel/genex.S | 15 ++- arch/mips/kernel/irq-msc01.c | 4 +- arch/mips/kernel/irq-mv6434x.c | 6 +- arch/mips/kernel/irq.c | 6 +- arch/mips/kernel/rtlx.c | 6 +- arch/mips/kernel/smp-mt.c | 16 +-- arch/mips/kernel/smtc.c | 26 ++--- arch/mips/kernel/time.c | 11 +- arch/mips/lasat/interrupt.c | 6 +- arch/mips/mips-boards/atlas/atlas_int.c | 12 +- arch/mips/mips-boards/generic/time.c | 22 ++-- arch/mips/mips-boards/malta/malta_int.c | 26 +++-- arch/mips/mips-boards/sead/sead_int.c | 4 +- arch/mips/mips-boards/sim/sim_int.c | 11 +- arch/mips/mips-boards/sim/sim_time.c | 14 +-- arch/mips/momentum/jaguar_atx/irq.c | 20 ++-- arch/mips/momentum/ocelot_3/irq.c | 22 ++-- arch/mips/momentum/ocelot_c/cpci-irq.c | 4 +- arch/mips/momentum/ocelot_c/irq.c | 22 ++-- arch/mips/momentum/ocelot_c/uart-irq.c | 4 +- arch/mips/momentum/ocelot_g/gt-irq.c | 4 +- arch/mips/momentum/ocelot_g/irq.c | 24 ++-- arch/mips/oprofile/op_impl.h | 4 +- arch/mips/oprofile/op_model_mipsxx.c | 7 +- arch/mips/pci/pci-ip32.c | 2 +- arch/mips/philips/pnx8550/common/int.c | 32 +++--- arch/mips/pmc-sierra/yosemite/irq.c | 54 ++------- arch/mips/pmc-sierra/yosemite/smp.c | 2 +- arch/mips/qemu/q-irq.c | 6 +- arch/mips/sgi-ip22/ip22-berr.c | 4 +- arch/mips/sgi-ip22/ip22-eisa.c | 5 +- arch/mips/sgi-ip22/ip22-int.c | 32 +++--- arch/mips/sgi-ip22/ip22-time.c | 6 +- arch/mips/sgi-ip27/ip27-irq.c | 26 ++--- arch/mips/sgi-ip27/ip27-timer.c | 4 +- arch/mips/sgi-ip32/crime.c | 6 +- arch/mips/sgi-ip32/ip32-irq.c | 48 ++++---- arch/mips/sibyte/bcm1480/irq.c | 27 +++-- arch/mips/sibyte/bcm1480/smp.c | 2 +- arch/mips/sibyte/bcm1480/time.c | 8 +- arch/mips/sibyte/sb1250/irq.c | 28 +++-- arch/mips/sibyte/sb1250/smp.c | 2 +- arch/mips/sibyte/sb1250/time.c | 6 +- arch/mips/sni/irq.c | 34 +++--- arch/mips/tx4927/common/tx4927_irq.c | 14 +-- .../toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 6 +- arch/mips/tx4938/common/irq.c | 46 ++------ arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c | 3 +- arch/mips/vr41xx/common/icu.c | 2 +- arch/mips/vr41xx/common/irq.c | 32 +++--- include/asm-mips/irq.h | 8 +- include/asm-mips/irq_regs.h | 22 +++- include/asm-mips/jmr3927/irq.h | 4 - include/asm-mips/mach-au1x00/au1000_dma.h | 3 +- include/asm-mips/marvell.h | 2 +- include/asm-mips/msc01_ic.h | 2 +- include/asm-mips/thread_info.h | 1 + include/asm-mips/time.h | 4 +- 79 files changed, 560 insertions(+), 625 deletions(-) diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c index fb7c47c1585..c3019b9c91b 100644 --- a/arch/mips/au1000/common/dma.c +++ b/arch/mips/au1000/common/dma.c @@ -160,7 +160,7 @@ void dump_au1000_dma_channel(unsigned int dmanr) * Requests the DMA done IRQ if irqhandler != NULL. */ int request_au1000_dma(int dev_id, const char *dev_str, - irqreturn_t (*irqhandler)(int, void *, struct pt_regs *), + irqreturn_t (*irqhandler)(int, void *), unsigned long irqflags, void *irq_dev_id) { diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index 316722ee8cf..b32597e05a6 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -67,7 +67,7 @@ extern void set_debug_traps(void); extern irq_cpustat_t irq_stat [NR_CPUS]; -extern void mips_timer_interrupt(struct pt_regs *regs); +extern void mips_timer_interrupt(void); static void setup_local_irq(unsigned int irq, int type, int int_req); static unsigned int startup_irq(unsigned int irq); @@ -81,10 +81,6 @@ inline void local_disable_irq(unsigned int irq_nr); void (*board_init_irq)(void); -#ifdef CONFIG_PM -extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs); -#endif - static DEFINE_SPINLOCK(irq_lock); @@ -292,7 +288,7 @@ static struct irq_chip level_irq_type = { }; #ifdef CONFIG_PM -void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *)) +void startup_match20_interrupt(irqreturn_t (*handler)(int, void *)) { struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT]; @@ -501,14 +497,15 @@ void __init arch_init_irq(void) * intcX_reqX_irqdispatch(). */ -void intc0_req0_irqdispatch(struct pt_regs *regs) +static void intc0_req0_irqdispatch(void) { int irq = 0; static unsigned long intc0_req0 = 0; intc0_req0 |= au_readl(IC0_REQ0INT); - if (!intc0_req0) return; + if (!intc0_req0) + return; #ifdef AU1000_USB_DEV_REQ_INT /* * Because of the tight timing of SETUP token to reply @@ -517,28 +514,29 @@ void intc0_req0_irqdispatch(struct pt_regs *regs) */ if ((intc0_req0 & (1< 0) { do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif time_elapsed -= MATCH20_INC; last_match20 += MATCH20_INC; @@ -158,7 +159,7 @@ irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs) jiffie_drift -= 999; do_timer(1); /* increment jiffies by one */ #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif } diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c index 63bcb3a95dc..70dc82e536c 100644 --- a/arch/mips/au1000/common/usbdev.c +++ b/arch/mips/au1000/common/usbdev.c @@ -1031,8 +1031,7 @@ process_ep_receive (struct usb_dev* dev, endpoint_t *ep) /* This ISR handles the receive complete and suspend events */ -static void -req_sus_intr (int irq, void *dev_id, struct pt_regs *regs) +static void req_sus_intr (int irq, void *dev_id) { struct usb_dev *dev = (struct usb_dev *) dev_id; u32 status; @@ -1050,8 +1049,7 @@ req_sus_intr (int irq, void *dev_id, struct pt_regs *regs) /* This ISR handles the DMA done events on EP0 */ -static void -dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs) +static void dma_done_ep0_intr(int irq, void *dev_id) { struct usb_dev *dev = (struct usb_dev *) dev_id; usbdev_pkt_t* pkt; @@ -1094,8 +1092,7 @@ dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs) } /* This ISR handles the DMA done events on endpoints 2,3,4,5 */ -static void -dma_done_ep_intr(int irq, void *dev_id, struct pt_regs *regs) +static void dma_done_ep_intr(int irq, void *dev_id) { struct usb_dev *dev = (struct usb_dev *) dev_id; int i; diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c index f66779f0d4c..91983ba407c 100644 --- a/arch/mips/au1000/pb1200/irqmap.c +++ b/arch/mips/au1000/pb1200/irqmap.c @@ -65,7 +65,7 @@ int __initdata au1xxx_nr_irqs = ARRAY_SIZE(au1xxx_irq_map); */ static volatile int pb1200_cascade_en=0; -irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t pb1200_cascade_handler( int irq, void *dev_id) { unsigned short bisr = bcsr->int_status; int extirq_nr = 0; @@ -76,8 +76,9 @@ irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs) { extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr); /* Ack and dispatch IRQ */ - do_IRQ(extirq_nr,regs); + do_IRQ(extirq_nr); } + return IRQ_RETVAL(1); } diff --git a/arch/mips/basler/excite/excite_dbg_io.c b/arch/mips/basler/excite/excite_dbg_io.c index c04505afa47..d289e3a868c 100644 --- a/arch/mips/basler/excite/excite_dbg_io.c +++ b/arch/mips/basler/excite/excite_dbg_io.c @@ -112,7 +112,7 @@ int putDebugChar(int data) } /* KGDB interrupt handler */ -asmlinkage void excite_kgdb_inthdl(struct pt_regs *regs) +asmlinkage void excite_kgdb_inthdl(void) { if (unlikely( ((titan_readl(UAIIR) & 0x7) == 4) diff --git a/arch/mips/basler/excite/excite_iodev.c b/arch/mips/basler/excite/excite_iodev.c index 10bbb8cfb96..6af0b21ebc3 100644 --- a/arch/mips/basler/excite/excite_iodev.c +++ b/arch/mips/basler/excite/excite_iodev.c @@ -38,7 +38,7 @@ static int iodev_open(struct inode *, struct file *); static int iodev_release(struct inode *, struct file *); static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *); static unsigned int iodev_poll(struct file *, struct poll_table_struct *); -static irqreturn_t iodev_irqhdl(int, void *, struct pt_regs *); +static irqreturn_t iodev_irqhdl(int, void *); @@ -108,16 +108,12 @@ static int __exit iodev_remove(struct device *dev) return misc_deregister(&miscdev); } - - static int iodev_open(struct inode *i, struct file *f) { return request_irq(iodev_irq, iodev_irqhdl, IRQF_DISABLED, iodev_name, &miscdev); } - - static int iodev_release(struct inode *i, struct file *f) { free_irq(iodev_irq, &miscdev); @@ -148,17 +144,13 @@ static unsigned int iodev_poll(struct file *f, struct poll_table_struct *p) return POLLOUT | POLLWRNORM; } - - - -static irqreturn_t iodev_irqhdl(int irq, void *ctxt, struct pt_regs *regs) +static irqreturn_t iodev_irqhdl(int irq, void *ctxt) { wake_up(&wq); + return IRQ_HANDLED; } - - static int __init iodev_init_module(void) { return driver_register(&iodev_driver); diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c index 511ad8730f5..2e2061a286c 100644 --- a/arch/mips/basler/excite/excite_irq.c +++ b/arch/mips/basler/excite/excite_irq.c @@ -56,7 +56,7 @@ void __init arch_init_irq(void) #endif } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { const u32 interrupts = read_c0_cause() >> 8, @@ -67,7 +67,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) /* process timer interrupt */ if (pending & (1 << TIMER_IRQ)) { - do_IRQ(TIMER_IRQ, regs); + do_IRQ(TIMER_IRQ); return; } @@ -80,7 +80,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) #else if (pending & (1 << USB_IRQ)) { #endif - do_IRQ(USB_IRQ, regs); + do_IRQ(USB_IRQ); return; } @@ -91,9 +91,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) if ((pending & (1 << TITAN_IRQ)) && msgint) { ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10)); #if defined(CONFIG_KGDB) - excite_kgdb_inthdl(regs); + excite_kgdb_inthdl(); #endif - do_IRQ(TITAN_IRQ, regs); + do_IRQ(TITAN_IRQ); return; } @@ -102,7 +102,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) msgintmask = ocd_readl(INTP0Mask0 + (FPGA0_MSGINT / 0x20 * 0x10)); msgint = msgintflags & msgintmask & (0x1 << (FPGA0_MSGINT % 0x20)); if ((pending & (1 << FPGA0_IRQ)) && msgint) { - do_IRQ(FPGA0_IRQ, regs); + do_IRQ(FPGA0_IRQ); return; } @@ -111,7 +111,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) msgintmask = ocd_readl(INTP0Mask0 + (FPGA1_MSGINT / 0x20 * 0x10)); msgint = msgintflags & msgintmask & (0x1 << (FPGA1_MSGINT % 0x20)); if ((pending & (1 << FPGA1_IRQ)) && msgint) { - do_IRQ(FPGA1_IRQ, regs); + do_IRQ(FPGA1_IRQ); return; } @@ -120,10 +120,10 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) msgintmask = ocd_readl(INTP0Mask0 + (PHY_MSGINT / 0x20 * 0x10)); msgint = msgintflags & msgintmask & (0x1 << (PHY_MSGINT % 0x20)); if ((pending & (1 << PHY_IRQ)) && msgint) { - do_IRQ(PHY_IRQ, regs); + do_IRQ(PHY_IRQ); return; } /* Process spurious interrupts */ - spurious_interrupt(regs); + spurious_interrupt(); } diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 0b75f4fb719..1117fab1973 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -42,7 +42,7 @@ * 15 - IDE1 */ -static inline void galileo_irq(struct pt_regs *regs) +static inline void galileo_irq(void) { unsigned int mask, pending, devfn; @@ -52,7 +52,7 @@ static inline void galileo_irq(struct pt_regs *regs) if (pending & GALILEO_INTR_T0EXP) { GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS); - do_IRQ(COBALT_GALILEO_IRQ, regs); + do_IRQ(COBALT_GALILEO_IRQ); } else if (pending & GALILEO_INTR_RETRY_CTR) { @@ -68,44 +68,31 @@ static inline void galileo_irq(struct pt_regs *regs) } } -static inline void via_pic_irq(struct pt_regs *regs) +static inline void via_pic_irq(void) { int irq; irq = i8259_irq(); if (irq >= 0) - do_IRQ(irq, regs); + do_IRQ(irq); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { - unsigned pending; - - pending = read_c0_status() & read_c0_cause(); - - if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */ - - galileo_irq(regs); - - else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */ - - via_pic_irq(regs); - - else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */ - - do_IRQ(COBALT_CPU_IRQ + 3, regs); - - else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */ - - do_IRQ(COBALT_CPU_IRQ + 4, regs); - - else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */ - - do_IRQ(COBALT_CPU_IRQ + 5, regs); - - else if (pending & CAUSEF_IP7) /* IRQ 23 */ - - do_IRQ(COBALT_CPU_IRQ + 7, regs); + unsigned pending = read_c0_status() & read_c0_cause(); + + if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */ + galileo_irq(); + else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */ + via_pic_irq(); + else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */ + do_IRQ(COBALT_CPU_IRQ + 3); + else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */ + do_IRQ(COBALT_CPU_IRQ + 4); + else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */ + do_IRQ(COBALT_CPU_IRQ + 5); + else if (pending & CAUSEF_IP7) /* IRQ 23 */ + do_IRQ(COBALT_CPU_IRQ + 7); } static struct irqaction irq_via = { diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c index 513fc6722d8..a8bd2e66705 100644 --- a/arch/mips/ddb5xxx/ddb5477/irq.c +++ b/arch/mips/ddb5xxx/ddb5477/irq.c @@ -153,8 +153,7 @@ u8 i8259_interrupt_ack(void) * the first level int-handler will jump here if it is a vrc5477 irq */ #define NUM_5477_IRQS 32 -static void -vrc5477_irq_dispatch(struct pt_regs *regs) +static void vrc5477_irq_dispatch(void) { u32 intStatus; u32 bitmask; @@ -178,7 +177,7 @@ vrc5477_irq_dispatch(struct pt_regs *regs) /* check for i8259 interrupts */ if (intStatus & (1 << VRC5477_I8259_CASCADE)) { int i8259_irq = i8259_interrupt_ack(); - do_IRQ(I8259_IRQ_BASE + i8259_irq, regs); + do_IRQ(I8259_IRQ_BASE + i8259_irq); return; } } @@ -186,7 +185,7 @@ vrc5477_irq_dispatch(struct pt_regs *regs) for (i=0, bitmask=1; i<= NUM_5477_IRQS; bitmask <<=1, i++) { /* do we need to "and" with the int mask? */ if (intStatus & bitmask) { - do_IRQ(VRC5477_IRQ_BASE + i, regs); + do_IRQ(VRC5477_IRQ_BASE + i); return; } } @@ -194,18 +193,18 @@ vrc5477_irq_dispatch(struct pt_regs *regs) #define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6) -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); if (pending & STATUSF_IP7) - do_IRQ(CPU_IRQ_BASE + 7, regs); + do_IRQ(CPU_IRQ_BASE + 7); else if (pending & VR5477INTS) - vrc5477_irq_dispatch(regs); + vrc5477_irq_dispatch(); else if (pending & STATUSF_IP0) - do_IRQ(CPU_IRQ_BASE, regs); + do_IRQ(CPU_IRQ_BASE); else if (pending & STATUSF_IP1) - do_IRQ(CPU_IRQ_BASE + 1, regs); + do_IRQ(CPU_IRQ_BASE + 1); else - spurious_interrupt(regs); + spurious_interrupt(); } diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 455a65b91cb..55d60d5e0e8 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -264,8 +264,10 @@ srlv t3,t1,t2 handle_it: + LONG_L s0, TI_REGS($28) + LONG_S sp, TI_REGS($28) jal do_IRQ - move a1,sp + LONG_S s0, TI_REGS($28) j ret_from_irq nop diff --git a/arch/mips/emma2rh/common/irq.c b/arch/mips/emma2rh/common/irq.c index 3af57693c84..c191b3e9d9d 100644 --- a/arch/mips/emma2rh/common/irq.c +++ b/arch/mips/emma2rh/common/irq.c @@ -39,7 +39,7 @@ /* * the first level int-handler will jump here if it is a emma2rh irq */ -asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) +void emma2rh_irq_dispatch(void) { u32 intStatus; u32 bitmask; @@ -56,7 +56,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) & emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { if (swIntStatus & bitmask) { - do_IRQ(EMMA2RH_SW_IRQ_BASE + i, regs); + do_IRQ(EMMA2RH_SW_IRQ_BASE + i); return; } } @@ -65,7 +65,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { if (intStatus & bitmask) { - do_IRQ(EMMA2RH_IRQ_BASE + i, regs); + do_IRQ(EMMA2RH_IRQ_BASE + i); return; } } @@ -81,7 +81,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) & emma2rh_in32(EMMA2RH_GPIO_INT_MASK); for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) { if (gpioIntStatus & bitmask) { - do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i, regs); + do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i); return; } } @@ -90,7 +90,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) for (i = 32, bitmask = 1; i < 64; i++, bitmask <<= 1) { if (intStatus & bitmask) { - do_IRQ(EMMA2RH_IRQ_BASE + i, regs); + do_IRQ(EMMA2RH_IRQ_BASE + i); return; } } @@ -100,7 +100,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs) for (i = 64, bitmask = 1; i < 96; i++, bitmask <<= 1) { if (intStatus & bitmask) { - do_IRQ(EMMA2RH_IRQ_BASE + i, regs); + do_IRQ(EMMA2RH_IRQ_BASE + i); return; } } diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c index 2a736be42c8..c93369cb411 100644 --- a/arch/mips/emma2rh/markeins/irq.c +++ b/arch/mips/emma2rh/markeins/irq.c @@ -57,7 +57,7 @@ extern void emma2rh_sw_irq_init(u32 base); extern void emma2rh_gpio_irq_init(u32 base); extern void emma2rh_irq_init(u32 base); -extern asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs); +extern void emma2rh_irq_dispatch(void); static struct irqaction irq_cascade = { .handler = no_action, @@ -114,20 +114,20 @@ void __init arch_init_irq(void) setup_irq(CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP7) - do_IRQ(CPU_IRQ_BASE + 7, regs); + do_IRQ(CPU_IRQ_BASE + 7); else if (pending & STATUSF_IP2) - emma2rh_irq_dispatch(regs); + emma2rh_irq_dispatch(); else if (pending & STATUSF_IP1) - do_IRQ(CPU_IRQ_BASE + 1, regs); + do_IRQ(CPU_IRQ_BASE + 1); else if (pending & STATUSF_IP0) - do_IRQ(CPU_IRQ_BASE + 0, regs); + do_IRQ(CPU_IRQ_BASE + 0); else - spurious_interrupt(regs); + spurious_interrupt(); } diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c index 7feca49350d..b203169f19c 100644 --- a/arch/mips/gt64120/common/time.c +++ b/arch/mips/gt64120/common/time.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,7 @@ * differently than other MIPS interrupts. */ -static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs) +static void gt64120_irq(int irq, void *dev_id) { unsigned int irq_src, int_high_src, irq_src_mask, int_high_src_mask; int handled = 0; @@ -36,7 +37,7 @@ static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs) irq_src &= ~0x00000800; do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif } diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c index 5d939ac58f3..ed4d82b9a24 100644 --- a/arch/mips/gt64120/ev64120/irq.c +++ b/arch/mips/gt64120/ev64120/irq.c @@ -46,22 +46,22 @@ #include #include -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP4) /* int2 hardware line (timer) */ - do_IRQ(4, regs); + do_IRQ(4); else if (pending & STATUSF_IP2) /* int0 hardware line */ - do_IRQ(GT_INTA, regs); + do_IRQ(GT_INTA); else if (pending & STATUSF_IP5) /* int3 hardware line */ - do_IRQ(GT_INTD, regs); + do_IRQ(GT_INTD); else if (pending & STATUSF_IP6) /* int4 hardware line */ - do_IRQ(6, regs); + do_IRQ(6); else if (pending & STATUSF_IP7) /* compare int */ - do_IRQ(7, regs); + do_IRQ(7); else - spurious_interrupt(regs); + spurious_interrupt(); } static void disable_ev64120_irq(unsigned int irq_nr) diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c index 885f67f32ea..d9294401ccb 100644 --- a/arch/mips/gt64120/momenco_ocelot/irq.c +++ b/arch/mips/gt64120/momenco_ocelot/irq.c @@ -48,22 +48,22 @@ #include #include -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP2) /* int0 hardware line */ - do_IRQ(2, regs); + do_IRQ(2); else if (pending & STATUSF_IP3) /* int1 hardware line */ - do_IRQ(3, regs); + do_IRQ(3); else if (pending & STATUSF_IP4) /* int2 hardware line */ - do_IRQ(4, regs); + do_IRQ(4); else if (pending & STATUSF_IP5) /* int3 hardware line */ - do_IRQ(5, regs); + do_IRQ(5); else if (pending & STATUSF_IP6) /* int4 hardware line */ - do_IRQ(6, regs); + do_IRQ(6); else if (pending & STATUSF_IP7) /* cpu timer */ - do_IRQ(7, regs); + do_IRQ(7); else { /* * Now look at the extended interrupts @@ -71,13 +71,13 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16; if (pending & STATUSF_IP8) /* int6 hardware line */ - do_IRQ(8, regs); + do_IRQ(8); else if (pending & STATUSF_IP9) /* int7 hardware line */ - do_IRQ(9, regs); + do_IRQ(9); else if (pending & STATUSF_IP10) /* int8 hardware line */ - do_IRQ(10, regs); + do_IRQ(10); else if (pending & STATUSF_IP11) /* int9 hardware line */ - do_IRQ(11, regs); + do_IRQ(11); } } diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c index 8d75a43ce87..eedfc24e1ea 100644 --- a/arch/mips/gt64120/wrppmc/irq.c +++ b/arch/mips/gt64120/wrppmc/irq.c @@ -30,18 +30,18 @@ #include #include -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP7) - do_IRQ(WRPPMC_MIPS_TIMER_IRQ, regs); /* CPU Compare/Count internal timer */ + do_IRQ(WRPPMC_MIPS_TIMER_IRQ); /* CPU Compare/Count internal timer */ else if (pending & STATUSF_IP6) - do_IRQ(WRPPMC_UART16550_IRQ, regs); /* UART 16550 port */ + do_IRQ(WRPPMC_UART16550_IRQ); /* UART 16550 port */ else if (pending & STATUSF_IP3) - do_IRQ(WRPPMC_PCI_INTA_IRQ, regs); /* PCI INT_A */ + do_IRQ(WRPPMC_PCI_INTA_IRQ); /* PCI INT_A */ else - spurious_interrupt(regs); + spurious_interrupt(); } /** diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index eef05093deb..d5bd6b3a093 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -94,26 +94,26 @@ void __init arch_init_irq(void) change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); } -static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask) +static void loc_call(unsigned int irq, unsigned int mask) { r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask); - do_IRQ(irq, regs); + do_IRQ(irq); r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask); } -static void ll_local_dev(struct pt_regs *regs) +static void ll_local_dev(void) { switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) { case 0: panic("Unimplemented loc_no_irq handler"); break; case 4: - loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL); + loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_PARALLEL); break; case 8: - loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY); + loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_FLOPPY); break; case 12: panic("Unimplemented loc_sound handler"); @@ -122,27 +122,27 @@ static void ll_local_dev(struct pt_regs *regs) panic("Unimplemented loc_video handler"); break; case 20: - loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET); + loc_call(JAZZ_ETHERNET_IRQ, JAZZ_IE_ETHERNET); break; case 24: - loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI); + loc_call(JAZZ_SCSI_IRQ, JAZZ_IE_SCSI); break; case 28: - loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD); + loc_call(JAZZ_KEYBOARD_IRQ, JAZZ_IE_KEYBOARD); break; case 32: - loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE); + loc_call(JAZZ_MOUSE_IRQ, JAZZ_IE_MOUSE); break; case 36: - loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1); + loc_call(JAZZ_SERIAL1_IRQ, JAZZ_IE_SERIAL1); break; case 40: - loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2); + loc_call(JAZZ_SERIAL2_IRQ, JAZZ_IE_SERIAL2); break; } } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; @@ -150,13 +150,13 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) write_c0_compare(0); else if (pending & IE_IRQ4) { r4030_read_reg32(JAZZ_TIMER_REGISTER); - do_IRQ(JAZZ_TIMER_IRQ, regs); + do_IRQ(JAZZ_TIMER_IRQ); } else if (pending & IE_IRQ3) panic("Unimplemented ISA NMI handler"); else if (pending & IE_IRQ2) - do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs); + do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK)); else if (pending & IE_IRQ1) { - ll_local_dev(regs); + ll_local_dev(); } else if (unlikely(pending & IE_IRQ0)) panic("Unimplemented local_dma handler"); else if (pending & IE_SW1) { diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c index 72217448146..39a0243bed9 100644 --- a/arch/mips/jmr3927/rbhma3100/irq.c +++ b/arch/mips/jmr3927/rbhma3100/irq.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -239,45 +240,80 @@ struct tb_irq_space jmr3927_ioc_irqspace = { .space_id = 0, can_share : 1 }; + struct tb_irq_space jmr3927_irc_irqspace = { - .next = NULL, - .start_irqno = JMR3927_IRQ_IRC, - nr_irqs : JMR3927_NR_IRQ_IRC, - .mask_func = mask_irq_irc, - .unmask_func = unmask_irq_irc, - .name = "on-chip", - .space_id = 0, - can_share : 0 + .next = NULL, + .start_irqno = JMR3927_IRQ_IRC, + .nr_irqs = JMR3927_NR_IRQ_IRC, + .mask_func = mask_irq_irc, + .unmask_func = unmask_irq_irc, + .name = "on-chip", + .space_id = 0, + .can_share = 0 }; -void jmr3927_spurious(struct pt_regs *regs) + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND +static int tx_branch_likely_bug_count = 0; +static int have_tx_branch_likely_bug = 0; + +static void tx_branch_likely_bug_fixup(void) +{ + struct pt_regs *regs = get_irq_regs(); + + /* TX39/49-BUG: Under this condition, the insn in delay slot + of the branch likely insn is executed (not nullified) even + the branch condition is false. */ + if (!have_tx_branch_likely_bug) + return; + if ((regs->cp0_epc & 0xfff) == 0xffc && + KSEGX(regs->cp0_epc) != KSEG0 && + KSEGX(regs->cp0_epc) != KSEG1) { + unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); + /* beql,bnel,blezl,bgtzl */ + /* bltzl,bgezl,blezall,bgezall */ + /* bczfl, bcztl */ + if ((insn & 0xf0000000) == 0x50000000 || + (insn & 0xfc0e0000) == 0x04020000 || + (insn & 0xf3fe0000) == 0x41020000) { + regs->cp0_epc -= 4; + tx_branch_likely_bug_count++; + printk(KERN_INFO + "fix branch-likery bug in %s (insn %08x)\n", + current->comm, insn); + } + } +} +#endif + +static void jmr3927_spurious(void) { #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND - tx_branch_likely_bug_fixup(regs); + tx_branch_likely_bug_fixup(); #endif printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", regs->cp0_cause, regs->cp0_epc, regs->regs[31]); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { int irq; #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND - tx_branch_likely_bug_fixup(regs); + tx_branch_likely_bug_fixup(); #endif if ((regs->cp0_cause & CAUSEF_IP7) == 0) { #if 0 - jmr3927_spurious(regs); + jmr3927_spurious(); #endif return; } irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; - do_IRQ(irq + JMR3927_IRQ_IRC, regs); + do_IRQ(irq + JMR3927_IRQ_IRC); } -static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id) { unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR); int i; @@ -285,7 +321,7 @@ static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs * for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) { if (istat & (1 << i)) { irq = JMR3927_IRQ_IOC + i; - do_IRQ(irq, regs); + do_IRQ(irq); } } return IRQ_HANDLED; @@ -295,7 +331,7 @@ static struct irqaction ioc_action = { jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, }; -static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id) { unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); int i; @@ -303,7 +339,7 @@ static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { if (istat & (1 << i)) { irq = JMR3927_IRQ_ISAC + i; - do_IRQ(irq, regs); + do_IRQ(irq); } } return IRQ_HANDLED; @@ -314,7 +350,7 @@ static struct irqaction isac_action = { }; -static irqreturn_t jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id) { printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); @@ -324,7 +360,7 @@ static struct irqaction isaerr_action = { jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL, }; -static irqreturn_t jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) { printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", @@ -439,33 +475,3 @@ void jmr3927_irq_init(u32 irq_base) jmr3927_irq_base = irq_base; } - -#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND -static int tx_branch_likely_bug_count = 0; -static int have_tx_branch_likely_bug = 0; -void tx_branch_likely_bug_fixup(struct pt_regs *regs) -{ - /* TX39/49-BUG: Under this condition, the insn in delay slot - of the branch likely insn is executed (not nullified) even - the branch condition is false. */ - if (!have_tx_branch_likely_bug) - return; - if ((regs->cp0_epc & 0xfff) == 0xffc && - KSEGX(regs->cp0_epc) != KSEG0 && - KSEGX(regs->cp0_epc) != KSEG1) { - unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); - /* beql,bnel,blezl,bgtzl */ - /* bltzl,bgezl,blezall,bgezall */ - /* bczfl, bcztl */ - if ((insn & 0xf0000000) == 0x50000000 || - (insn & 0xfc0e0000) == 0x04020000 || - (insn & 0xf3fe0000) == 0x41020000) { - regs->cp0_epc -= 4; - tx_branch_likely_bug_count++; - printk(KERN_INFO - "fix branch-likery bug in %s (insn %08x)\n", - current->comm, insn); - } - } -} -#endif diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index ec28077d5ee..e9ce5b3721a 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -93,11 +93,12 @@ void output_thread_info_defines(void) offset("#define TI_TASK ", struct thread_info, task); offset("#define TI_EXEC_DOMAIN ", struct thread_info, exec_domain); offset("#define TI_FLAGS ", struct thread_info, flags); + offset("#define TI_TP_VALUE ", struct thread_info, tp_value); offset("#define TI_CPU ", struct thread_info, cpu); offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count); offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit); offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block); - offset("#define TI_TP_VALUE ", struct thread_info, tp_value); + offset("#define TI_REGS ", struct thread_info, regs); constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER); constant("#define _THREAD_SIZE ", THREAD_SIZE); constant("#define _THREAD_MASK ", THREAD_MASK); diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 766655f3525..e93e43e1f42 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -79,7 +79,6 @@ FEXPORT(syscall_exit) FEXPORT(restore_all) # restore full frame #ifdef CONFIG_MIPS_MT_SMTC /* Detect and execute deferred IPI "interrupts" */ - move a0,sp jal deferred_smtc_ipi /* Re-arm any temporarily masked interrupts not explicitly "acked" */ mfc0 v0, CP0_TCSTATUS diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index af6ef2fd830..50ed7729772 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -131,9 +131,11 @@ NESTED(handle_int, PT_SIZE, sp) CLI TRACE_IRQS_OFF - PTR_LA ra, ret_from_irq - move a0, sp - j plat_irq_dispatch + LONG_L s0, TI_REGS($28) + LONG_S sp, TI_REGS($28) + jal plat_irq_dispatch + LONG_S s0, TI_REGS($28) + j ret_from_irq END(handle_int) __INIT @@ -219,9 +221,12 @@ NESTED(except_vec_vi_handler, 0, sp) #endif /* CONFIG_MIPS_MT_SMTC */ CLI TRACE_IRQS_OFF - move a0, sp + + LONG_L s0, TI_REGS($28) + LONG_S sp, TI_REGS($28) + jalr v0 + LONG_S s0, TI_REGS($28) PTR_LA ra, ret_from_irq - jr v0 END(except_vec_vi_handler) /* diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 63dfeb41796..71e8e45f368 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -115,14 +115,14 @@ static void end_msc_irq(unsigned int irq) /* * Interrupt handler for interrupts coming from SOC-it. */ -void ll_msc_irq(struct pt_regs *regs) +void ll_msc_irq(void) { unsigned int irq; /* read the interrupt vector register */ MSCIC_READ(MSC01_IC_VEC, irq); if (irq < 64) - do_IRQ(irq + irq_base, regs); + do_IRQ(irq + irq_base); else { /* Ignore spurious interrupt */ } diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c index b117e64da64..39c94fd8d8b 100644 --- a/arch/mips/kernel/irq-mv6434x.c +++ b/arch/mips/kernel/irq-mv6434x.c @@ -113,7 +113,7 @@ static void end_mv64340_irq(unsigned int irq) * Interrupt handler for interrupts coming from the Marvell chip. * It could be built in ethernet ports etc... */ -void ll_mv64340_irq(struct pt_regs *regs) +void ll_mv64340_irq(void) { unsigned int irq_src_low, irq_src_high; unsigned int irq_mask_low, irq_mask_high; @@ -129,9 +129,9 @@ void ll_mv64340_irq(struct pt_regs *regs) irq_src_high &= irq_mask_high; if (irq_src_low) - do_IRQ(ls1bit32(irq_src_low) + irq_base, regs); + do_IRQ(ls1bit32(irq_src_low) + irq_base); else - do_IRQ(ls1bit32(irq_src_high) + irq_base + 32, regs); + do_IRQ(ls1bit32(irq_src_high) + irq_base + 32); } #define shutdown_mv64340_irq disable_mv64340_irq diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index a00b0e7ab9b..dd24434392b 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -53,9 +53,8 @@ unsigned long irq_hwmask[NR_IRQS]; * SMP cross-CPU interrupts have their own specific * handlers). */ -asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs) +asmlinkage unsigned int do_IRQ(unsigned int irq) { - struct pt_regs *old_regs = set_irq_regs(regs); irq_enter(); __DO_IRQ_SMTC_HOOK(); @@ -63,7 +62,6 @@ asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs) irq_exit(); - set_irq_regs(old_regs); return 1; } @@ -112,7 +110,7 @@ skip: return 0; } -asmlinkage void spurious_interrupt(struct pt_regs *regs) +asmlinkage void spurious_interrupt(void) { atomic_inc(&irq_err_count); } diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index cdab1b2cd13..8c8c8324f77 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -61,16 +61,16 @@ static int sp_stopping = 0; extern void *vpe_get_shared(int index); -static void rtlx_dispatch(struct pt_regs *regs) +static void rtlx_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); + do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ); } /* Interrupt handler may be called before rtlx_init has otherwise had a chance to run. */ -static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rtlx_interrupt(int irq, void *dev_id) { int i; diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 766253c44f3..3b5f3b63262 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -106,22 +106,22 @@ void __init sanitize_tlb_entries(void) clear_c0_mvpcontrol(MVPCONTROL_VPC); } -static void ipi_resched_dispatch (struct pt_regs *regs) +static void ipi_resched_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ, regs); + do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ); } -static void ipi_call_dispatch (struct pt_regs *regs) +static void ipi_call_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ, regs); + do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ); } -irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) { return IRQ_HANDLED; } -irqreturn_t ipi_call_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) { smp_call_function_interrupt(); @@ -250,8 +250,8 @@ void __init plat_prepare_cpus(unsigned int max_cpus) { /* set up ipi interrupts */ if (cpu_has_vint) { - set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); - set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); + set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); + set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); } cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ; diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 604bcc5cb7c..cc1f7474f7d 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -82,7 +82,7 @@ struct smtc_ipi_q freeIPIq; /* Forward declarations */ -void ipi_decode(struct pt_regs *, struct smtc_ipi *); +void ipi_decode(struct smtc_ipi *); void post_direct_ipi(int cpu, struct smtc_ipi *pipi); void setup_cross_vpe_interrupts(void); void init_smtc_stats(void); @@ -820,19 +820,19 @@ void post_direct_ipi(int cpu, struct smtc_ipi *pipi) write_tc_c0_tcrestart(__smtc_ipi_vector); } -void ipi_resched_interrupt(struct pt_regs *regs) +static void ipi_resched_interrupt(void) { /* Return from interrupt should be enough to cause scheduler check */ } -void ipi_call_interrupt(struct pt_regs *regs) +static void ipi_call_interrupt(void) { /* Invoke generic function invocation code in smp.c */ smp_call_function_interrupt(); } -void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi) +void ipi_decode(struct smtc_ipi *pipi) { void *arg_copy = pipi->arg; int type_copy = pipi->type; @@ -846,15 +846,15 @@ void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi) #ifdef SMTC_IDLE_HOOK_DEBUG clock_hang_reported[dest_copy] = 0; #endif /* SMTC_IDLE_HOOK_DEBUG */ - local_timer_interrupt(0, NULL, regs); + local_timer_interrupt(0, NULL); break; case LINUX_SMP_IPI: switch ((int)arg_copy) { case SMP_RESCHEDULE_YOURSELF: - ipi_resched_interrupt(regs); + ipi_resched_interrupt(); break; case SMP_CALL_FUNCTION: - ipi_call_interrupt(regs); + ipi_call_interrupt(); break; default: printk("Impossible SMTC IPI Argument 0x%x\n", @@ -868,7 +868,7 @@ void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi) } } -void deferred_smtc_ipi(struct pt_regs *regs) +void deferred_smtc_ipi(void) { struct smtc_ipi *pipi; unsigned long flags; @@ -883,7 +883,7 @@ void deferred_smtc_ipi(struct pt_regs *regs) while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) { /* ipi_decode() should be called with interrupts off */ local_irq_save(flags); - ipi_decode(regs, pipi); + ipi_decode(pipi); local_irq_restore(flags); } } @@ -917,7 +917,7 @@ void smtc_timer_broadcast(int vpe) static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ; -static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs) +static irqreturn_t ipi_interrupt(int irq, void *dev_idm) { int my_vpe = cpu_data[smp_processor_id()].vpe_id; int my_tc = cpu_data[smp_processor_id()].tc_id; @@ -978,7 +978,7 @@ static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs) * with interrupts off */ local_irq_save(flags); - ipi_decode(regs, pipi); + ipi_decode(pipi); local_irq_restore(flags); } } @@ -987,9 +987,9 @@ static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs) return IRQ_HANDLED; } -static void ipi_irq_dispatch(struct pt_regs *regs) +static void ipi_irq_dispatch(void) { - do_IRQ(cpu_ipi_irq, regs); + do_IRQ(cpu_ipi_irq); } static struct irqaction irq_ipi; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index d349eb9e4ff..debe86c2f69 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -324,8 +324,7 @@ static long last_rtc_update; */ void local_timer_interrupt(int irq, void *dev_id) { - if (current->pid) - profile_tick(CPU_PROFILING); + profile_tick(CPU_PROFILING); update_process_times(user_mode(get_irq_regs())); } @@ -434,9 +433,8 @@ 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) +asmlinkage void ll_timer_interrupt(int irq) { - struct pt_regs *old_regs = set_irq_regs(regs); int r2 = cpu_has_mips_r2; irq_enter(); @@ -458,12 +456,10 @@ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) out: irq_exit(); - set_irq_regs(old_regs); } -asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) +asmlinkage void ll_local_timer_interrupt(int irq) { - struct pt_regs *old_regs = set_irq_regs(regs); irq_enter(); if (smp_processor_id() != 0) kstat_this_cpu.irqs[irq]++; @@ -472,7 +468,6 @@ asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) local_timer_interrupt(irq, NULL); irq_exit(); - set_irq_regs(old_regs); } /* diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c index 456be8fc961..a144a002dcc 100644 --- a/arch/mips/lasat/interrupt.c +++ b/arch/mips/lasat/interrupt.c @@ -108,14 +108,14 @@ static unsigned long get_int_status_200(void) return int_status; } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned long int_status; unsigned int cause = read_c0_cause(); int irq; if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */ - ll_timer_interrupt(7, regs); + ll_timer_interrupt(7); return; } @@ -125,7 +125,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) if (int_status) { irq = ls1bit32(int_status); - do_IRQ(irq, regs); + do_IRQ(irq); } } diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index a020a3cb4f4..be624b8c3b0 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -101,7 +101,7 @@ static inline int ls1bit32(unsigned int x) return b; } -static inline void atlas_hw0_irqdispatch(struct pt_regs *regs) +static inline void atlas_hw0_irqdispatch(void) { unsigned long int_status; int irq; @@ -116,7 +116,7 @@ static inline void atlas_hw0_irqdispatch(struct pt_regs *regs) DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); - do_IRQ(irq, regs); + do_IRQ(irq); } static inline int clz(unsigned long x) @@ -188,7 +188,7 @@ static inline unsigned int irq_ffs(unsigned int pending) * then we just return, if multiple IRQs are pending then we will just take * another exception, big deal. */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; int irq; @@ -196,11 +196,11 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) irq = irq_ffs(pending); if (irq == MIPSCPU_INT_ATLAS) - atlas_hw0_irqdispatch(regs); + atlas_hw0_irqdispatch(); else if (irq >= 0) - do_IRQ(MIPSCPU_INT_BASE + irq, regs); + do_IRQ(MIPSCPU_INT_BASE + irq); else - spurious_interrupt(regs); + spurious_interrupt(); } static inline void init_atlas_irqs (int base) diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 8d15861fce6..d379000162f 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -82,19 +82,19 @@ static inline void scroll_display_message(void) } } -static void mips_timer_dispatch (struct pt_regs *regs) +static void mips_timer_dispatch(void) { - do_IRQ (mips_cpu_timer_irq, regs); + do_IRQ(mips_cpu_timer_irq); } /* * Redeclare until I get around mopping the timer code insanity on MIPS. */ -extern int null_perf_irq(struct pt_regs *regs); +extern int null_perf_irq(void); -extern int (*perf_irq)(struct pt_regs *regs); +extern int (*perf_irq)(void); -irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t mips_timer_interrupt(int irq, void *dev_id) { int cpu = smp_processor_id(); @@ -119,7 +119,7 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * perf counter overflow, or both. */ if (read_c0_cause() & (1 << 26)) - perf_irq(regs); + perf_irq(); if (read_c0_cause() & (1 << 30)) { /* If timer interrupt, make it de-assert */ @@ -139,13 +139,13 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * the tick on VPE 0 to run the full timer_interrupt(). */ if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, NULL, regs); + timer_interrupt(irq, NULL); smtc_timer_broadcast(cpu_data[cpu].vpe_id); scroll_display_message(); } else { write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); - local_timer_interrupt(irq, dev_id, regs); + local_timer_interrupt(irq, dev_id); smtc_timer_broadcast(cpu_data[cpu].vpe_id); } } @@ -159,12 +159,12 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * timer int. */ 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); scroll_display_message(); } else { @@ -180,7 +180,7 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* * Other CPUs should do profiling and process accounting */ - local_timer_interrupt(irq, dev_id, regs); + local_timer_interrupt(irq, dev_id); } out: #endif /* CONFIG_MIPS_MT_SMTC */ diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index 7cc0ba4f553..ed221dc7f6a 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -114,7 +114,7 @@ static inline int get_int(void) return irq; } -static void malta_hw0_irqdispatch(struct pt_regs *regs) +static void malta_hw0_irqdispatch(void) { int irq; @@ -123,17 +123,21 @@ static void malta_hw0_irqdispatch(struct pt_regs *regs) return; /* interrupt has already been cleared */ } - do_IRQ(MALTA_INT_BASE+irq, regs); + do_IRQ(MALTA_INT_BASE + irq); } -void corehi_irqdispatch(struct pt_regs *regs) +static void corehi_irqdispatch(void) { + unsigned int intedge, intsteer, pcicmd, pcibadaddr; + unsigned int pcimstat, intisr, inten, intpol; unsigned int intrcause,datalo,datahi; - unsigned int pcimstat, intisr, inten, intpol, intedge, intsteer, pcicmd, pcibadaddr; + struct pt_regs *regs; printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n"); - printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n" -, regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr); + printk("epc : %08lx\nStatus: %08lx\n" + "Cause : %08lx\nbadVaddr : %08lx\n", + regs->cp0_epc, regs->cp0_status, + regs->cp0_cause, regs->cp0_badvaddr); /* Read all the registers and then print them as there is a problem with interspersed printk's upsetting the Bonito controller. @@ -146,7 +150,7 @@ void corehi_irqdispatch(struct pt_regs *regs) case MIPS_REVISION_CORID_CORE_FPGA3: case MIPS_REVISION_CORID_CORE_24K: case MIPS_REVISION_CORID_CORE_EMUL_MSC: - ll_msc_irq(regs); + ll_msc_irq(); break; case MIPS_REVISION_CORID_QED_RM5261: case MIPS_REVISION_CORID_CORE_LV: @@ -255,7 +259,7 @@ static inline unsigned int irq_ffs(unsigned int pending) * another exception, big deal. */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; int irq; @@ -263,11 +267,11 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) irq = irq_ffs(pending); if (irq == MIPSCPU_INT_I8259A) - malta_hw0_irqdispatch(regs); + malta_hw0_irqdispatch(); else if (irq > 0) - do_IRQ(MIPSCPU_INT_BASE + irq, regs); + do_IRQ(MIPSCPU_INT_BASE + irq); else - spurious_interrupt(regs); + spurious_interrupt(); } static struct irqaction i8259irq = { diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c index 9168d934c66..f445fcddfdf 100644 --- a/arch/mips/mips-boards/sead/sead_int.c +++ b/arch/mips/mips-boards/sead/sead_int.c @@ -98,7 +98,7 @@ static inline unsigned int irq_ffs(unsigned int pending) * then we just return, if multiple IRQs are pending then we will just take * another exception, big deal. */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; int irq; @@ -106,7 +106,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) irq = irq_ffs(pending); if (irq >= 0) - do_IRQ(MIPSCPU_INT_BASE + irq, regs); + do_IRQ(MIPSCPU_INT_BASE + irq); else spurious_interrupt(regs); } diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c index 2c15c8efec4..2ce449dce6f 100644 --- a/arch/mips/mips-boards/sim/sim_int.c +++ b/arch/mips/mips-boards/sim/sim_int.c @@ -71,12 +71,7 @@ static inline unsigned int irq_ffs(unsigned int pending) #endif } -static inline void sim_hw0_irqdispatch(struct pt_regs *regs) -{ - do_IRQ(2, regs); -} - -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; int irq; @@ -84,9 +79,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) irq = irq_ffs(pending); if (irq > 0) - do_IRQ(MIPSCPU_INT_BASE + irq, regs); + do_IRQ(MIPSCPU_INT_BASE + irq); else - spurious_interrupt(regs); + spurious_interrupt(); } void __init arch_init_irq(void) diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c index 230929ecd57..acd83a37955 100644 --- a/arch/mips/mips-boards/sim/sim_time.c +++ b/arch/mips/mips-boards/sim/sim_time.c @@ -33,7 +33,7 @@ unsigned long cpu_khz; -irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t sim_timer_interrupt(int irq, void *dev_id) { #ifdef CONFIG_SMP int cpu = smp_processor_id(); @@ -44,7 +44,7 @@ irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ #ifndef CONFIG_MIPS_MT_SMTC if (cpu == 0) { - timer_interrupt(irq, dev_id, regs); + timer_interrupt(irq, dev_id); } else { /* Everyone else needs to reset the timer int here as @@ -84,7 +84,7 @@ irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) irq_enable_hazard(); evpe(vpflags); - if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id, regs); + if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id); else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); smtc_timer_broadcast(cpu_data[cpu].vpe_id); @@ -93,10 +93,10 @@ irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* * every CPU should do profiling and process accounting */ - local_timer_interrupt (irq, dev_id, regs); + local_timer_interrupt (irq, dev_id); return IRQ_HANDLED; #else - return timer_interrupt (irq, dev_id, regs); + return timer_interrupt (irq, dev_id); #endif } @@ -177,9 +177,9 @@ void __init sim_time_init(void) static int mips_cpu_timer_irq; -static void mips_timer_dispatch (struct pt_regs *regs) +static void mips_timer_dispatch(void) { - do_IRQ (mips_cpu_timer_irq, regs); + do_IRQ(mips_cpu_timer_irq); } diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c index f9067469a65..2efb25aa1ae 100644 --- a/arch/mips/momentum/jaguar_atx/irq.c +++ b/arch/mips/momentum/jaguar_atx/irq.c @@ -40,33 +40,33 @@ #include #include -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); if (pending & STATUSF_IP0) - do_IRQ(0, regs); + do_IRQ(0); else if (pending & STATUSF_IP1) - do_IRQ(1, regs); + do_IRQ(1); else if (pending & STATUSF_IP2) - do_IRQ(2, regs); + do_IRQ(2); else if (pending & STATUSF_IP3) - do_IRQ(3, regs); + do_IRQ(3); else if (pending & STATUSF_IP4) - do_IRQ(4, regs); + do_IRQ(4); else if (pending & STATUSF_IP5) - do_IRQ(5, regs); + do_IRQ(5); else if (pending & STATUSF_IP6) - do_IRQ(6, regs); + do_IRQ(6); else if (pending & STATUSF_IP7) - ll_timer_interrupt(7, regs); + ll_timer_interrupt(7); else { /* * Now look at the extended interrupts */ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16; if (pending & STATUSF_IP8) - ll_mv64340_irq(regs); + ll_mv64340_irq(); } } diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c index 793782a9c19..cea0e5deb80 100644 --- a/arch/mips/momentum/ocelot_3/irq.c +++ b/arch/mips/momentum/ocelot_3/irq.c @@ -75,26 +75,26 @@ void __init arch_init_irq(void) } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); if (pending & STATUSF_IP0) - do_IRQ(0, regs); + do_IRQ(0); else if (pending & STATUSF_IP1) - do_IRQ(1, regs); + do_IRQ(1); else if (pending & STATUSF_IP2) - do_IRQ(2, regs); + do_IRQ(2); else if (pending & STATUSF_IP3) - do_IRQ(3, regs); + do_IRQ(3); else if (pending & STATUSF_IP4) - do_IRQ(4, regs); + do_IRQ(4); else if (pending & STATUSF_IP5) - do_IRQ(5, regs); + do_IRQ(5); else if (pending & STATUSF_IP6) - do_IRQ(6, regs); + do_IRQ(6); else if (pending & STATUSF_IP7) - do_IRQ(7, regs); + do_IRQ(7); else { /* * Now look at the extended interrupts @@ -102,8 +102,8 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16; if (pending & STATUSF_IP8) - ll_mv64340_irq(regs); + ll_mv64340_irq(); else - spurious_interrupt(regs); + spurious_interrupt(); } } diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c index a5dc230520d..2fb14bb08e6 100644 --- a/arch/mips/momentum/ocelot_c/cpci-irq.c +++ b/arch/mips/momentum/ocelot_c/cpci-irq.c @@ -112,7 +112,7 @@ static void end_cpci_irq(unsigned int irq) * Interrupt handler for interrupts coming from the FPGA chip. * It could be built in ethernet ports etc... */ -void ll_cpci_irq(struct pt_regs *regs) +void ll_cpci_irq(void) { unsigned int irq_src, irq_mask; @@ -123,7 +123,7 @@ void ll_cpci_irq(struct pt_regs *regs) /* mask for just the interrupts we want */ irq_src &= ~irq_mask; - do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE, regs); + do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE); } #define shutdown_cpci_irq disable_cpci_irq diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c index 9d44ae1e156..4be7b26e30e 100644 --- a/arch/mips/momentum/ocelot_c/irq.c +++ b/arch/mips/momentum/ocelot_c/irq.c @@ -59,31 +59,31 @@ static struct irqaction cascade_mv64340 = { no_action, IRQF_DISABLED, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL }; -extern void ll_uart_irq(struct pt_regs *regs); -extern void ll_cpci_irq(struct pt_regs *regs); +extern void ll_uart_irq(void); +extern void ll_cpci_irq(void); -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); if (pending & STATUSF_IP0) - do_IRQ(0, regs); + do_IRQ(0); else if (pending & STATUSF_IP1) - do_IRQ(1, regs); + do_IRQ(1); else if (pending & STATUSF_IP2) - do_IRQ(2, regs); + do_IRQ(2); else if (pending & STATUSF_IP3) - ll_uart_irq(regs); + ll_uart_irq(); else if (pending & STATUSF_IP4) - do_IRQ(4, regs); + do_IRQ(4); else if (pending & STATUSF_IP5) - ll_cpci_irq(regs); + ll_cpci_irq(); else if (pending & STATUSF_IP6) ll_mv64340_irq(regs); else if (pending & STATUSF_IP7) - do_IRQ(7, regs); + do_IRQ(7); else - spurious_interrupt(regs); + spurious_interrupt(); } void __init arch_init_irq(void) diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c index 9f33d8f1d82..f8efe2370ff 100644 --- a/arch/mips/momentum/ocelot_c/uart-irq.c +++ b/arch/mips/momentum/ocelot_c/uart-irq.c @@ -105,7 +105,7 @@ static void end_uart_irq(unsigned int irq) /* * Interrupt handler for interrupts coming from the FPGA chip. */ -void ll_uart_irq(struct pt_regs *regs) +void ll_uart_irq(void) { unsigned int irq_src, irq_mask; @@ -116,7 +116,7 @@ void ll_uart_irq(struct pt_regs *regs) /* mask for just the interrupts we want */ irq_src &= ~irq_mask; - do_IRQ(ls1bit8(irq_src) + 74, regs); + do_IRQ(ls1bit8(irq_src) + 74); } #define shutdown_uart_irq disable_uart_irq diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c index 6cd87cf0195..b8cffa80548 100644 --- a/arch/mips/momentum/ocelot_g/gt-irq.c +++ b/arch/mips/momentum/ocelot_g/gt-irq.c @@ -108,7 +108,7 @@ int disable_galileo_irq(int int_cause, int bit_num) * we keep this particular structure in the function. */ -static irqreturn_t gt64240_p0int_irq(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t gt64240_p0int_irq(int irq, void *dev) { uint32_t irq_src, irq_src_mask; int handled; @@ -135,7 +135,7 @@ static irqreturn_t gt64240_p0int_irq(int irq, void *dev, struct pt_regs *regs) /* handle the timer call */ do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif } diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c index 7a4a419804f..da46524e87c 100644 --- a/arch/mips/momentum/ocelot_g/irq.c +++ b/arch/mips/momentum/ocelot_g/irq.c @@ -48,22 +48,22 @@ #include #include -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); if (pending & STATUSF_IP2) - do_IRQ(2, regs); + do_IRQ(2); else if (pending & STATUSF_IP3) - do_IRQ(3, regs); + do_IRQ(3); else if (pending & STATUSF_IP4) - do_IRQ(4, regs); + do_IRQ(4); else if (pending & STATUSF_IP5) - do_IRQ(5, regs); + do_IRQ(5); else if (pending & STATUSF_IP6) - do_IRQ(6, regs); + do_IRQ(6); else if (pending & STATUSF_IP7) - do_IRQ(7, regs); + do_IRQ(7); else { /* * Now look at the extended interrupts @@ -71,15 +71,15 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16; if (pending & STATUSF_IP8) - do_IRQ(8, regs); + do_IRQ(8); else if (pending & STATUSF_IP9) - do_IRQ(9, regs); + do_IRQ(9); else if (pending & STATUSF_IP10) - do_IRQ(10, regs); + do_IRQ(10); else if (pending & STATUSF_IP11) - do_IRQ(11, regs); + do_IRQ(11); else - spurious_interrupt(regs); + spurious_interrupt(); } } diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h index 5cfce7d87a4..354e5449640 100644 --- a/arch/mips/oprofile/op_impl.h +++ b/arch/mips/oprofile/op_impl.h @@ -12,8 +12,8 @@ struct pt_regs; -extern int null_perf_irq(struct pt_regs *regs); -extern int (*perf_irq)(struct pt_regs *regs); +extern int null_perf_irq(void); +extern int (*perf_irq)(void); /* Per-counter configuration as set via oprofilefs. */ struct op_counter_config { diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index a175d673540..dd0aec9c3ce 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -3,12 +3,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004, 2005 by Ralf Baechle + * Copyright (C) 2004, 05, 06 by Ralf Baechle * Copyright (C) 2005 by MIPS Technologies, Inc. */ #include #include #include +#include #include "op_impl.h" @@ -170,7 +171,7 @@ static void mipsxx_cpu_stop(void *args) } } -static int mipsxx_perfcount_handler(struct pt_regs *regs) +static int mipsxx_perfcount_handler(void) { unsigned int counters = op_model_mipsxx_ops.num_counters; unsigned int control; @@ -184,7 +185,7 @@ static int mipsxx_perfcount_handler(struct pt_regs *regs) counter = r_c0_perfcntr ## n(); \ if ((control & M_PERFCTL_INTERRUPT_ENABLE) && \ (counter & M_COUNTER_OVERFLOW)) { \ - oprofile_add_sample(regs, n); \ + oprofile_add_sample(get_irq_regs(), n); \ w_c0_perfcntr ## n(reg.counter[n]); \ handled = 1; \ } diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c index 17c7932cf0a..618ea7dbc47 100644 --- a/arch/mips/pci/pci-ip32.c +++ b/arch/mips/pci/pci-ip32.c @@ -22,7 +22,7 @@ * registered on the bridge error irq. It's conceivable that some of these * conditions warrant a panic. Anybody care to say which ones? */ -static irqreturn_t macepci_error(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t macepci_error(int irq, void *dev) { char s; unsigned int flags = mace->pci.error; diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c index 3c93512be1e..710611615ca 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/philips/pnx8550/common/int.c @@ -23,6 +23,7 @@ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * */ +#include #include #include #include @@ -52,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOTINT] = { 1 // 70 }; -static void hw0_irqdispatch(int irq, struct pt_regs *regs) +static void hw0_irqdispatch(int irq) { /* find out which interrupt */ irq = PNX8550_GIC_VECTOR_0 >> 3; @@ -61,42 +62,39 @@ static void hw0_irqdispatch(int irq, struct pt_regs *regs) printk("hw0_irqdispatch: irq 0, spurious interrupt?\n"); return; } - do_IRQ(PNX8550_INT_GIC_MIN + irq, regs); + do_IRQ(PNX8550_INT_GIC_MIN + irq); } -static void timer_irqdispatch(int irq, struct pt_regs *regs) +static void timer_irqdispatch(int irq) { irq = (0x01c0 & read_c0_config7()) >> 6; - if (irq == 0) { + if (unlikely(irq == 0)) { printk("timer_irqdispatch: irq 0, spurious interrupt?\n"); return; } - if (irq & 0x1) { - do_IRQ(PNX8550_INT_TIMER1, regs); - } - if (irq & 0x2) { - do_IRQ(PNX8550_INT_TIMER2, regs); - } - if (irq & 0x4) { - do_IRQ(PNX8550_INT_TIMER3, regs); - } + if (irq & 0x1) + do_IRQ(PNX8550_INT_TIMER1); + if (irq & 0x2) + do_IRQ(PNX8550_INT_TIMER2); + if (irq & 0x4) + do_IRQ(PNX8550_INT_TIMER3); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP2) - hw0_irqdispatch(2, regs); + hw0_irqdispatch(2); else if (pending & STATUSF_IP7) { if (read_c0_config7() & 0x01c0) - timer_irqdispatch(7, regs); + timer_irqdispatch(7); } - spurious_interrupt(regs); + spurious_interrupt(); } static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c index b91d0aa3b7e..adb048527e7 100644 --- a/arch/mips/pmc-sierra/yosemite/irq.c +++ b/arch/mips/pmc-sierra/yosemite/irq.c @@ -56,15 +56,13 @@ #define HYPERTRANSPORT_INTC 0x7a /* INTC# */ #define HYPERTRANSPORT_INTD 0x7b /* INTD# */ -extern void jaguar_mailbox_irq(struct pt_regs *); - /* * Handle hypertransport & SMP interrupts. The interrupt lines are scarce. * For interprocessor interrupts, the best thing to do is to use the INTMSG * register. We use the same external interrupt line, i.e. INTB3 and monitor * another status bit */ -asmlinkage void ll_ht_smp_irq_handler(int irq, struct pt_regs *regs) +static void ll_ht_smp_irq_handler(int irq) { u32 status = OCD_READ(RM9000x2_OCD_INTP0STATUS4); @@ -107,50 +105,35 @@ asmlinkage void ll_ht_smp_irq_handler(int irq, struct pt_regs *regs) } #endif /* CONFIG_HT_LEVEL_TRIGGER */ - do_IRQ(irq, regs); -} - -asmlinkage void do_extended_irq(struct pt_regs *regs) -{ - unsigned int intcontrol = read_c0_intcontrol(); - unsigned int cause = read_c0_cause(); - unsigned int status = read_c0_status(); - unsigned int pending_sr, pending_ic; - - pending_sr = status & cause & 0xff00; - pending_ic = (cause >> 8) & intcontrol & 0xff00; - - if (pending_ic & (1 << 13)) - do_IRQ(13, regs); - + do_IRQ(irq); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int cause = read_c0_cause(); unsigned int status = read_c0_status(); unsigned int pending = cause & status; if (pending & STATUSF_IP7) { - do_IRQ(7, regs); + do_IRQ(7); } else if (pending & STATUSF_IP2) { #ifdef CONFIG_HYPERTRANSPORT - ll_ht_smp_irq_handler(2, regs); + ll_ht_smp_irq_handler(2); #else - do_IRQ(2, regs); + do_IRQ(2); #endif } else if (pending & STATUSF_IP3) { - do_IRQ(3, regs); + do_IRQ(3); } else if (pending & STATUSF_IP4) { - do_IRQ(4, regs); + do_IRQ(4); } else if (pending & STATUSF_IP5) { #ifdef CONFIG_SMP - titan_mailbox_irq(regs); + titan_mailbox_irq(); #else - do_IRQ(5, regs); + do_IRQ(5); #endif } else if (pending & STATUSF_IP6) { - do_IRQ(4, regs); + do_IRQ(4); } } @@ -178,18 +161,3 @@ void __init arch_init_irq(void) register_gdb_console(); #endif } - -#ifdef CONFIG_KGDB -/* - * The 16550 DUART has two ports, but is allocated one IRQ - * for the serial console. Hence, a generic framework for - * serial IRQ routing in place. Currently, just calls the - * do_IRQ fuction. But, going in the future, need to check - * DUART registers for channel A and B, then decide the - * appropriate action - */ -asmlinkage void yosemite_kgdb_irq(int irq, struct pt_regs *regs) -{ - do_IRQ(irq, regs); -} -#endif diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c index c197311e15d..65fa3a23ea5 100644 --- a/arch/mips/pmc-sierra/yosemite/smp.c +++ b/arch/mips/pmc-sierra/yosemite/smp.c @@ -110,7 +110,7 @@ void prom_smp_finish(void) { } -asmlinkage void titan_mailbox_irq(struct pt_regs *regs) +asmlinkage void titan_mailbox_irq(void) { int cpu = smp_processor_id(); unsigned long status; diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c index 3352374c4c7..f5ea2fe10f1 100644 --- a/arch/mips/qemu/q-irq.c +++ b/arch/mips/qemu/q-irq.c @@ -9,19 +9,19 @@ extern asmlinkage void qemu_handle_int(void); -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & 0x8000) { - ll_timer_interrupt(Q_COUNT_COMPARE_IRQ, regs); + ll_timer_interrupt(Q_COUNT_COMPARE_IRQ); return; } if (pending & 0x0400) { int irq = i8259_irq(); if (likely(irq >= 0)) - do_IRQ(irq, regs); + do_IRQ(irq); return; } diff --git a/arch/mips/sgi-ip22/ip22-berr.c b/arch/mips/sgi-ip22/ip22-berr.c index a28dc780007..de6a0cc32fe 100644 --- a/arch/mips/sgi-ip22/ip22-berr.c +++ b/arch/mips/sgi-ip22/ip22-berr.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -85,9 +86,10 @@ static void print_buserr(void) * and then clear the interrupt when this happens. */ -void ip22_be_interrupt(int irq, struct pt_regs *regs) +void ip22_be_interrupt(int irq) { const int field = 2 * sizeof(unsigned long); + const struct pt_regs *regs = get_irq_regs(); save_and_clear_buserr(); print_buserr(); diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c index ee0514a2992..0d18ed47c47 100644 --- a/arch/mips/sgi-ip22/ip22-eisa.c +++ b/arch/mips/sgi-ip22/ip22-eisa.c @@ -70,7 +70,7 @@ static char __init *decode_eisa_sig(unsigned long addr) return sig_str; } -static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ip22_eisa_intr(int irq, void *dev_id) { u8 eisa_irq; u8 dma1, dma2; @@ -80,7 +80,7 @@ static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs) dma2 = inb(EISA_DMA2_STATUS); if (eisa_irq < EISA_MAX_IRQ) { - do_IRQ(eisa_irq, regs); + do_IRQ(eisa_irq); return IRQ_HANDLED; } @@ -89,6 +89,7 @@ static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs) outb(0x20, EISA_INT2_CTRL); outb(0x20, EISA_INT1_CTRL); + return IRQ_NONE; } diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index f66026e5d64..af518898eaa 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -222,7 +222,7 @@ static struct irq_chip ip22_local3_irq_type = { .end = end_local3_irq, }; -static void indy_local0_irqdispatch(struct pt_regs *regs) +static void indy_local0_irqdispatch(void) { u8 mask = sgint->istat0 & sgint->imask0; u8 mask2; @@ -236,11 +236,10 @@ static void indy_local0_irqdispatch(struct pt_regs *regs) /* if irq == 0, then the interrupt has already been cleared */ if (irq) - do_IRQ(irq, regs); - return; + do_IRQ(irq); } -static void indy_local1_irqdispatch(struct pt_regs *regs) +static void indy_local1_irqdispatch(void) { u8 mask = sgint->istat1 & sgint->imask1; u8 mask2; @@ -254,19 +253,18 @@ static void indy_local1_irqdispatch(struct pt_regs *regs) /* if irq == 0, then the interrupt has already been cleared */ if (irq) - do_IRQ(irq, regs); - return; + do_IRQ(irq); } -extern void ip22_be_interrupt(int irq, struct pt_regs *regs); +extern void ip22_be_interrupt(int irq); -static void indy_buserror_irq(struct pt_regs *regs) +static void indy_buserror_irq(void) { int irq = SGI_BUSERR_IRQ; irq_enter(); kstat_this_cpu.irqs[irq]++; - ip22_be_interrupt(irq, regs); + ip22_be_interrupt(irq); irq_exit(); } @@ -305,8 +303,8 @@ static struct irqaction map1_cascade = { #define SGI_INTERRUPTS SGINT_LOCAL3 #endif -extern void indy_r4k_timer_interrupt(struct pt_regs *regs); -extern void indy_8254timer_irq(struct pt_regs *regs); +extern void indy_r4k_timer_interrupt(void); +extern void indy_8254timer_irq(void); /* * IRQs on the INDY look basically (barring software IRQs which we don't use @@ -336,7 +334,7 @@ extern void indy_8254timer_irq(struct pt_regs *regs); * another exception, big deal. */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause(); @@ -344,15 +342,15 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) * First we check for r4k counter/timer IRQ. */ if (pending & CAUSEF_IP7) - indy_r4k_timer_interrupt(regs); + indy_r4k_timer_interrupt(); else if (pending & CAUSEF_IP2) - indy_local0_irqdispatch(regs); + indy_local0_irqdispatch(); else if (pending & CAUSEF_IP3) - indy_local1_irqdispatch(regs); + indy_local1_irqdispatch(); else if (pending & CAUSEF_IP6) - indy_buserror_irq(regs); + indy_buserror_irq(); else if (pending & (CAUSEF_IP4 | CAUSEF_IP5)) - indy_8254timer_irq(regs); + indy_8254timer_irq(); } extern void mips_cpu_irq_init(unsigned int irq_base); diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 3462b0d98de..20555473409 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -175,7 +175,7 @@ static __init void indy_time_init(void) } /* Generic SGI handler for (spurious) 8254 interrupts */ -void indy_8254timer_irq(struct pt_regs *regs) +void indy_8254timer_irq(void) { int irq = SGI_8254_0_IRQ; ULONG cnt; @@ -189,16 +189,14 @@ void indy_8254timer_irq(struct pt_regs *regs) irq_exit(); } -void indy_r4k_timer_interrupt(struct pt_regs *regs) +void indy_r4k_timer_interrupt(void) { - 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); irq_exit(); - set_irq_regs(old_regs); } void __init plat_timer_setup(struct irqaction *irq) diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 24a85372284..f41587a206e 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -129,7 +129,7 @@ static int ms1bit(unsigned long x) * Kanoj 05.13.00 */ -static void ip27_do_irq_mask0(struct pt_regs *regs) +static void ip27_do_irq_mask0(void) { int irq, swlevel; hubreg_t pend0, mask0; @@ -164,13 +164,13 @@ static void ip27_do_irq_mask0(struct pt_regs *regs) struct slice_data *si = cpu_data[cpu].data; irq = si->level_to_irq[swlevel]; - do_IRQ(irq, regs); + do_IRQ(irq); } LOCAL_HUB_L(PI_INT_PEND0); } -static void ip27_do_irq_mask1(struct pt_regs *regs) +static void ip27_do_irq_mask1(void) { int irq, swlevel; hubreg_t pend1, mask1; @@ -190,17 +190,17 @@ static void ip27_do_irq_mask1(struct pt_regs *regs) /* "map" swlevel to irq */ irq = si->level_to_irq[swlevel]; LOCAL_HUB_CLR_INTR(swlevel); - do_IRQ(irq, regs); + do_IRQ(irq); LOCAL_HUB_L(PI_INT_PEND1); } -static void ip27_prof_timer(struct pt_regs *regs) +static void ip27_prof_timer(void) { panic("CPU %d got a profiling interrupt", smp_processor_id()); } -static void ip27_hub_error(struct pt_regs *regs) +static void ip27_hub_error(void) { panic("CPU %d got a hub error interrupt", smp_processor_id()); } @@ -418,22 +418,22 @@ int __devinit request_bridge_irq(struct bridge_controller *bc) return irq; } -extern void ip27_rt_timer_interrupt(struct pt_regs *regs); +extern void ip27_rt_timer_interrupt(void); -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned long pending = read_c0_cause() & read_c0_status(); if (pending & CAUSEF_IP4) - ip27_rt_timer_interrupt(regs); + ip27_rt_timer_interrupt(); else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */ - ip27_do_irq_mask0(regs); + ip27_do_irq_mask0(); else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */ - ip27_do_irq_mask1(regs); + ip27_do_irq_mask1(); else if (pending & CAUSEF_IP5) - ip27_prof_timer(regs); + ip27_prof_timer(); else if (pending & CAUSEF_IP6) - ip27_hub_error(regs); + ip27_hub_error(); } void __init arch_init_irq(void) diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 257ce118e38..4e870fc4469 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -89,7 +89,7 @@ static int set_rtc_mmss(unsigned long nowtime) static unsigned int rt_timer_irq; -void ip27_rt_timer_interrupt(struct pt_regs *regs) +void ip27_rt_timer_interrupt(void) { int cpu = smp_processor_id(); int cpuA = cputoslice(cpu) == 0; @@ -111,7 +111,7 @@ again: if (cpu == 0) do_timer(1); - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); /* * If we have an externally synchronized Linux clock, then update diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c index 41b5eca1148..f1f2c45a6c8 100644 --- a/arch/mips/sgi-ip32/crime.c +++ b/arch/mips/sgi-ip32/crime.c @@ -40,8 +40,7 @@ void __init crime_init(void) id, rev, field, (unsigned long) CRIME_BASE); } -irqreturn_t -crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) { unsigned long stat, addr; int fatal = 0; @@ -92,8 +91,7 @@ crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -irqreturn_t -crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id) { unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK; unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK; diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index c64a820373d..c9acadd0846 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -120,10 +120,8 @@ static void inline flush_mace_bus(void) static DEFINE_SPINLOCK(ip32_irq_lock); /* Some initial interrupts to set up */ -extern irqreturn_t crime_memerr_intr (int irq, void *dev_id, - struct pt_regs *regs); -extern irqreturn_t crime_cpuerr_intr (int irq, void *dev_id, - struct pt_regs *regs); +extern irqreturn_t crime_memerr_intr(int irq, void *dev_id); +extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); struct irqaction memerr_irq = { crime_memerr_intr, IRQF_DISABLED, CPU_MASK_NONE, "CRIME memory error", NULL, NULL }; @@ -479,7 +477,7 @@ static struct irq_chip ip32_mace_interrupt = { .end = end_mace_irq, }; -static void ip32_unknown_interrupt(struct pt_regs *regs) +static void ip32_unknown_interrupt(void) { printk ("Unknown interrupt occurred!\n"); printk ("cp0_status: %08x\n", read_c0_status()); @@ -492,7 +490,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs) printk ("MACE PCI control register: %08x\n", mace->pci.control); printk("Register dump:\n"); - show_regs(regs); + show_regs(get_irq_regs()); printk("Please mail this report to linux-mips@linux-mips.org\n"); printk("Spinning..."); @@ -501,7 +499,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs) /* CRIME 1.1 appears to deliver all interrupts to this one pin. */ /* change this to loop over all edge-triggered irqs, exception masked out ones */ -static void ip32_irq0(struct pt_regs *regs) +static void ip32_irq0(void) { uint64_t crime_int; int irq = 0; @@ -516,50 +514,50 @@ static void ip32_irq0(struct pt_regs *regs) } irq++; DBG("*irq %u*\n", irq); - do_IRQ(irq, regs); + do_IRQ(irq); } -static void ip32_irq1(struct pt_regs *regs) +static void ip32_irq1(void) { - ip32_unknown_interrupt(regs); + ip32_unknown_interrupt(); } -static void ip32_irq2(struct pt_regs *regs) +static void ip32_irq2(void) { - ip32_unknown_interrupt(regs); + ip32_unknown_interrupt(); } -static void ip32_irq3(struct pt_regs *regs) +static void ip32_irq3(void) { - ip32_unknown_interrupt(regs); + ip32_unknown_interrupt(); } -static void ip32_irq4(struct pt_regs *regs) +static void ip32_irq4(void) { - ip32_unknown_interrupt(regs); + ip32_unknown_interrupt(); } -static void ip32_irq5(struct pt_regs *regs) +static void ip32_irq5(void) { - ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs); + ll_timer_interrupt(IP32_R4K_TIMER_IRQ); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause(); if (likely(pending & IE_IRQ0)) - ip32_irq0(regs); + ip32_irq0(); else if (unlikely(pending & IE_IRQ1)) - ip32_irq1(regs); + ip32_irq1(); else if (unlikely(pending & IE_IRQ2)) - ip32_irq2(regs); + ip32_irq2(); else if (unlikely(pending & IE_IRQ3)) - ip32_irq3(regs); + ip32_irq3(); else if (unlikely(pending & IE_IRQ4)) - ip32_irq4(regs); + ip32_irq4(); else if (likely(pending & IE_IRQ5)) - ip32_irq5(regs); + ip32_irq5(); } void __init arch_init_irq(void) diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index a46b75b23ec..0c00f676b8b 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -284,8 +285,7 @@ void __init init_bcm1480_irqs(void) } -static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id) { return IRQ_NONE; } @@ -453,7 +453,7 @@ void __init arch_init_irq(void) #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -void bcm1480_kgdb_interrupt(struct pt_regs *regs) +static void bcm1480_kgdb_interrupt(void) { /* * Clear break-change status (allow some time for the remote @@ -464,16 +464,15 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs) mdelay(500); duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | M_DUART_RX_EN | M_DUART_TX_EN); - set_async_breakpoint(®s->cp0_epc); + set_async_breakpoint(&get_irq_regs()->cp0_epc); } #endif /* CONFIG_KGDB */ -extern void bcm1480_timer_interrupt(struct pt_regs *regs); -extern void bcm1480_mailbox_interrupt(struct pt_regs *regs); -extern void bcm1480_kgdb_interrupt(struct pt_regs *regs); +extern void bcm1480_timer_interrupt(void); +extern void bcm1480_mailbox_interrupt(void); -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending; @@ -486,21 +485,21 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) #ifdef CONFIG_SIBYTE_BCM1480_PROF if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ - sbprof_cpu_intr(exception_epc(regs)); + sbprof_cpu_intr(); else #endif if (pending & CAUSEF_IP4) - bcm1480_timer_interrupt(regs); + bcm1480_timer_interrupt(); #ifdef CONFIG_SMP else if (pending & CAUSEF_IP3) - bcm1480_mailbox_interrupt(regs); + bcm1480_mailbox_interrupt(); #endif #ifdef CONFIG_KGDB else if (pending & CAUSEF_IP6) - bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */ + bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ #endif else if (pending & CAUSEF_IP2) { @@ -521,9 +520,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) if (mask_h) { if (mask_h ^ 1) - do_IRQ(fls64(mask_h) - 1, regs); + do_IRQ(fls64(mask_h) - 1); else - do_IRQ(63 + fls64(mask_l), regs); + do_IRQ(63 + fls64(mask_l)); } } } diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 584a4b33faa..6eac36d1b8c 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -88,7 +88,7 @@ void core_send_ipi(int cpu, unsigned int action) __raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]); } -void bcm1480_mailbox_interrupt(struct pt_regs *regs) +void bcm1480_mailbox_interrupt(void) { int cpu = smp_processor_id(); unsigned int action; diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 7e088f6c4a8..f228f711dc3 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -100,10 +100,10 @@ void bcm1480_time_init(void) #include -void bcm1480_timer_interrupt(struct pt_regs *regs) +void bcm1480_timer_interrupt(void) { int cpu = smp_processor_id(); - int irq = K_BCM1480_INT_TIMER_0+cpu; + int irq = K_BCM1480_INT_TIMER_0 + cpu; /* Reset the timer */ __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, @@ -113,13 +113,13 @@ void bcm1480_timer_interrupt(struct pt_regs *regs) /* * CPU 0 handles the global timer interrupt job */ - ll_timer_interrupt(irq, regs); + ll_timer_interrupt(irq); } else { /* * other CPUs should just do profiling and process accounting */ - ll_local_timer_interrupt(irq, regs); + ll_local_timer_interrupt(irq); } } diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index f9bd9f07451..f6d2e19592e 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -254,8 +254,7 @@ void __init init_sb1250_irqs(void) } -static irqreturn_t sb1250_dummy_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t sb1250_dummy_handler(int irq, void *dev_id) { return IRQ_NONE; } @@ -403,7 +402,7 @@ void __init arch_init_irq(void) #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -static void sb1250_kgdb_interrupt(struct pt_regs *regs) +static void sb1250_kgdb_interrupt(void) { /* * Clear break-change status (allow some time for the remote @@ -414,16 +413,15 @@ static void sb1250_kgdb_interrupt(struct pt_regs *regs) mdelay(500); duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | M_DUART_RX_EN | M_DUART_TX_EN); - set_async_breakpoint(®s->cp0_epc); + set_async_breakpoint(&get_irq_regs()->cp0_epc); } #endif /* CONFIG_KGDB */ -extern void sb1250_timer_interrupt(struct pt_regs *regs); -extern void sb1250_mailbox_interrupt(struct pt_regs *regs); -extern void sb1250_kgdb_interrupt(struct pt_regs *regs); +extern void sb1250_timer_interrupt(void); +extern void sb1250_mailbox_interrupt(void); -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending; @@ -446,21 +444,21 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) #ifdef CONFIG_SIBYTE_SB1250_PROF if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ - sbprof_cpu_intr(exception_epc(regs)); + sbprof_cpu_intr(); else #endif if (pending & CAUSEF_IP4) - sb1250_timer_interrupt(regs); + sb1250_timer_interrupt(); #ifdef CONFIG_SMP else if (pending & CAUSEF_IP3) - sb1250_mailbox_interrupt(regs); + sb1250_mailbox_interrupt(); #endif #ifdef CONFIG_KGDB else if (pending & CAUSEF_IP6) /* KGDB (uart 1) */ - sb1250_kgdb_interrupt(regs); + sb1250_kgdb_interrupt(); #endif else if (pending & CAUSEF_IP2) { @@ -475,9 +473,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(), R_IMR_INTERRUPT_STATUS_BASE))); if (mask) - do_IRQ(fls64(mask) - 1, regs); + do_IRQ(fls64(mask) - 1); else - spurious_interrupt(regs); + spurious_interrupt(); } else - spurious_interrupt(regs); + spurious_interrupt(); } diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index f859db02d3c..c38e1f34460 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c @@ -76,7 +76,7 @@ void core_send_ipi(int cpu, unsigned int action) __raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]); } -void sb1250_mailbox_interrupt(struct pt_regs *regs) +void sb1250_mailbox_interrupt(void) { int cpu = smp_processor_id(); unsigned int action; diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 4b669dc86ef..0d17aec03dd 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -125,7 +125,7 @@ void sb1250_time_init(void) */ } -void sb1250_timer_interrupt(struct pt_regs *regs) +void sb1250_timer_interrupt(void) { int cpu = smp_processor_id(); int irq = K_INT_TIMER_0 + cpu; @@ -138,13 +138,13 @@ void sb1250_timer_interrupt(struct pt_regs *regs) /* * CPU 0 handles the global timer interrupt job */ - ll_timer_interrupt(irq, regs); + ll_timer_interrupt(irq); } else { /* * other CPUs should just do profiling and process accounting */ - ll_local_timer_interrupt(irq, regs); + ll_local_timer_interrupt(irq); } } diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c index cda165f42b6..48fb74a7aae 100644 --- a/arch/mips/sni/irq.c +++ b/arch/mips/sni/irq.c @@ -69,20 +69,20 @@ static struct irq_chip pciasic_irq_type = { * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug * button interrupts. Later ... */ -static void pciasic_hwint0(struct pt_regs *regs) +static void pciasic_hwint0(void) { panic("Received int0 but no handler yet ..."); } /* This interrupt was used for the com1 console on the first prototypes. */ -static void pciasic_hwint2(struct pt_regs *regs) +static void pciasic_hwint2(void) { /* I think this shouldn't happen on production machines. */ panic("hwint2 and no handler yet"); } /* hwint5 is the r4k count / compare interrupt */ -static void pciasic_hwint5(struct pt_regs *regs) +static void pciasic_hwint5(void) { panic("hwint5 and no handler yet"); } @@ -103,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x) * * The EISA_INT bit in CSITPEND is high active, all others are low active. */ -static void pciasic_hwint1(struct pt_regs *regs) +static void pciasic_hwint1(void) { u8 pend = *(volatile char *)PCIMT_CSITPEND; unsigned long flags; @@ -119,13 +119,13 @@ static void pciasic_hwint1(struct pt_regs *regs) if (unlikely(irq < 0)) return; - do_IRQ(irq, regs); + do_IRQ(irq); } if (!(pend & IT_SCSI)) { flags = read_c0_status(); clear_c0_status(ST0_IM); - do_IRQ(PCIMT_IRQ_SCSI, regs); + do_IRQ(PCIMT_IRQ_SCSI); write_c0_status(flags); } } @@ -133,7 +133,7 @@ static void pciasic_hwint1(struct pt_regs *regs) /* * hwint 3 should deal with the PCI A - D interrupts, */ -static void pciasic_hwint3(struct pt_regs *regs) +static void pciasic_hwint3(void) { u8 pend = *(volatile char *)PCIMT_CSITPEND; int irq; @@ -141,21 +141,21 @@ static void pciasic_hwint3(struct pt_regs *regs) pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); clear_c0_status(IE_IRQ3); irq = PCIMT_IRQ_INT2 + ls1bit8(pend); - do_IRQ(irq, regs); + do_IRQ(irq); set_c0_status(IE_IRQ3); } /* * hwint 4 is used for only the onboard PCnet 32. */ -static void pciasic_hwint4(struct pt_regs *regs) +static void pciasic_hwint4(void) { clear_c0_status(IE_IRQ4); - do_IRQ(PCIMT_IRQ_ETHERNET, regs); + do_IRQ(PCIMT_IRQ_ETHERNET); set_c0_status(IE_IRQ4); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); static unsigned char led_cache; @@ -163,17 +163,17 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) *(volatile unsigned char *) PCIMT_CSLED = ++led_cache; if (pending & 0x0800) - pciasic_hwint1(regs); + pciasic_hwint1(); else if (pending & 0x4000) - pciasic_hwint4(regs); + pciasic_hwint4(); else if (pending & 0x2000) - pciasic_hwint3(regs); + pciasic_hwint3(); else if (pending & 0x1000) - pciasic_hwint2(regs); + pciasic_hwint2(); else if (pending & 0x8000) - pciasic_hwint5(regs); + pciasic_hwint5(); else if (pending & 0x0400) - pciasic_hwint0(regs); + pciasic_hwint0(); } void __init init_pciasic(void) diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c index cd176f6a06c..8266a88a3f8 100644 --- a/arch/mips/tx4927/common/tx4927_irq.c +++ b/arch/mips/tx4927/common/tx4927_irq.c @@ -576,24 +576,24 @@ static int tx4927_irq_nested(void) return (sw_irq); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP7) /* cpu timer */ - do_IRQ(TX4927_IRQ_CPU_TIMER, regs); + do_IRQ(TX4927_IRQ_CPU_TIMER); else if (pending & STATUSF_IP2) { /* tx4927 pic */ unsigned int irq = tx4927_irq_nested(); if (unlikely(irq == 0)) { - spurious_interrupt(regs); + spurious_interrupt(); return; } - do_IRQ(irq, regs); + do_IRQ(irq); } else if (pending & STATUSF_IP0) /* user line 0 */ - do_IRQ(TX4927_IRQ_USER0, regs); + do_IRQ(TX4927_IRQ_USER0); else if (pending & STATUSF_IP1) /* user line 1 */ - do_IRQ(TX4927_IRQ_USER1, regs); + do_IRQ(TX4927_IRQ_USER1); else - spurious_interrupt(regs); + spurious_interrupt(); } diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index f0d70c47600..bea19098ac2 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -160,8 +161,7 @@ int tx4927_pci66 = 0; /* 0:auto */ char *toshiba_name = ""; #ifdef CONFIG_PCI -static void tx4927_pcierr_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static void tx4927_pcierr_interrupt(int irq, void *dev_id) { #ifdef CONFIG_BLK_DEV_IDEPCI /* ignore MasterAbort for ide probing... */ @@ -185,7 +185,7 @@ static void tx4927_pcierr_interrupt(int irq, void *dev_id, (unsigned long) tx4927_ccfgptr->ccfg, (unsigned long) (tx4927_ccfgptr->tear >> 32), (unsigned long) tx4927_ccfgptr->tear); - show_regs(regs); + show_regs(get_irq_regs()); } void __init toshiba_rbtx4927_pci_irq_init(void) diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c index cbfb34221b5..b6024749b8f 100644 --- a/arch/mips/tx4938/common/irq.c +++ b/arch/mips/tx4938/common/irq.c @@ -104,8 +104,6 @@ tx4938_irq_cp0_init(void) irq_desc[i].depth = 1; irq_desc[i].chip = &tx4938_irq_cp0_type; } - - return; } static unsigned int @@ -113,7 +111,7 @@ tx4938_irq_cp0_startup(unsigned int irq) { tx4938_irq_cp0_enable(irq); - return (0); + return 0; } static void @@ -144,16 +142,12 @@ tx4938_irq_cp0_disable(unsigned int irq) clear_c0_status(tx4938_irq_cp0_mask(irq)); spin_unlock_irqrestore(&tx4938_cp0_lock, flags); - - return; } static void tx4938_irq_cp0_mask_and_ack(unsigned int irq) { tx4938_irq_cp0_disable(irq); - - return; } static void @@ -162,8 +156,6 @@ tx4938_irq_cp0_end(unsigned int irq) if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { tx4938_irq_cp0_enable(irq); } - - return; } /**********************************************************************************/ @@ -227,7 +219,7 @@ tx4938_irq_pic_addr(int irq) } } - return (0); + return 0; } u32 @@ -278,7 +270,7 @@ tx4938_irq_pic_mask(int irq) return (0x00000007); } } - return (0x00000000); + return 0x00000000; } static void @@ -292,8 +284,6 @@ tx4938_irq_pic_modify(unsigned pic_reg, unsigned clr_bits, unsigned set_bits) TX4938_WR(pic_reg, val); mmiowb(); TX4938_RD(pic_reg); - - return; } static void __init @@ -317,8 +307,6 @@ tx4938_irq_pic_init(void) TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */ spin_unlock_irqrestore(&tx4938_pic_lock, flags); - - return; } static unsigned int @@ -326,15 +314,13 @@ tx4938_irq_pic_startup(unsigned int irq) { tx4938_irq_pic_enable(irq); - return (0); + return 0; } static void tx4938_irq_pic_shutdown(unsigned int irq) { tx4938_irq_pic_disable(irq); - - return; } static void @@ -348,8 +334,6 @@ tx4938_irq_pic_enable(unsigned int irq) tx4938_irq_pic_mask(irq)); spin_unlock_irqrestore(&tx4938_pic_lock, flags); - - return; } static void @@ -363,16 +347,12 @@ tx4938_irq_pic_disable(unsigned int irq) tx4938_irq_pic_mask(irq), 0); spin_unlock_irqrestore(&tx4938_pic_lock, flags); - - return; } static void tx4938_irq_pic_mask_and_ack(unsigned int irq) { tx4938_irq_pic_disable(irq); - - return; } static void @@ -381,8 +361,6 @@ tx4938_irq_pic_end(unsigned int irq) if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { tx4938_irq_pic_enable(irq); } - - return; } /**********************************************************************************/ @@ -394,8 +372,6 @@ tx4938_irq_init(void) { tx4938_irq_cp0_init(); tx4938_irq_pic_init(); - - return; } int @@ -417,23 +393,23 @@ tx4938_irq_nested(void) } wbflush(); - return (sw_irq); + return sw_irq; } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); if (pending & STATUSF_IP7) - do_IRQ(TX4938_IRQ_CPU_TIMER, regs); + do_IRQ(TX4938_IRQ_CPU_TIMER); else if (pending & STATUSF_IP2) { int irq = tx4938_irq_nested(); if (irq) - do_IRQ(irq, regs); + do_IRQ(irq); else - spurious_interrupt(regs); + spurious_interrupt(); } else if (pending & STATUSF_IP1) - do_IRQ(TX4938_IRQ_USER1, regs); + do_IRQ(TX4938_IRQ_USER1); else if (pending & STATUSF_IP0) - do_IRQ(TX4938_IRQ_USER0, regs); + do_IRQ(TX4938_IRQ_USER0); } diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c index fae3136f462..b926e6a75c2 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c @@ -35,7 +35,8 @@ void __init txx9_spi_init(unsigned long base, int (*cs_func)(int chipid, int on) } static DECLARE_WAIT_QUEUE_HEAD(txx9_spi_wait); -static void txx9_spi_interrupt(int irq, void *dev_id, struct pt_regs *regs) + +static void txx9_spi_interrupt(int irq, void *dev_id) { /* disable rx intr */ tx4938_spiptr->cr0 &= ~TXx9_SPCR0_RBSIE; diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index 7a5c31d5837..c215c0d39fa 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -635,7 +635,7 @@ int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) EXPORT_SYMBOL(vr41xx_set_intassign); -static int icu_get_irq(unsigned int irq, struct pt_regs *regs) +static int icu_get_irq(unsigned int irq) { uint16_t pend1, pend2; uint16_t mask1, mask2; diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c index 4733c534446..397ba94cd7e 100644 --- a/arch/mips/vr41xx/common/irq.c +++ b/arch/mips/vr41xx/common/irq.c @@ -25,7 +25,7 @@ #include typedef struct irq_cascade { - int (*get_irq)(unsigned int, struct pt_regs *); + int (*get_irq)(unsigned int); } irq_cascade_t; static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned; @@ -36,7 +36,7 @@ static struct irqaction cascade_irqaction = { .name = "cascade", }; -int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *)) +int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int)) { int retval = 0; @@ -59,7 +59,7 @@ int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *) EXPORT_SYMBOL_GPL(cascade_irq); -static void irq_dispatch(unsigned int irq, struct pt_regs *regs) +static void irq_dispatch(unsigned int irq) { irq_cascade_t *cascade; struct irq_desc *desc; @@ -74,39 +74,39 @@ static void irq_dispatch(unsigned int irq, struct pt_regs *regs) unsigned int source_irq = irq; desc = irq_desc + source_irq; desc->chip->ack(source_irq); - irq = cascade->get_irq(irq, regs); + irq = cascade->get_irq(irq); if (irq < 0) atomic_inc(&irq_err_count); else - irq_dispatch(irq, regs); + irq_dispatch(irq); desc->chip->end(source_irq); } else - do_IRQ(irq, regs); + do_IRQ(irq); } -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; if (pending & CAUSEF_IP7) - do_IRQ(7, regs); + do_IRQ(7); else if (pending & 0x7800) { if (pending & CAUSEF_IP3) - irq_dispatch(3, regs); + irq_dispatch(3); else if (pending & CAUSEF_IP4) - irq_dispatch(4, regs); + irq_dispatch(4); else if (pending & CAUSEF_IP5) - irq_dispatch(5, regs); + irq_dispatch(5); else if (pending & CAUSEF_IP6) - irq_dispatch(6, regs); + irq_dispatch(6); } else if (pending & CAUSEF_IP2) - irq_dispatch(2, regs); + irq_dispatch(2); else if (pending & CAUSEF_IP0) - do_IRQ(0, regs); + do_IRQ(0); else if (pending & CAUSEF_IP1) - do_IRQ(1, regs); + do_IRQ(1); else - spurious_interrupt(regs); + spurious_interrupt(); } void __init arch_init_irq(void) diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index d35c61776a0..1a9804c6536 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -26,7 +26,7 @@ static inline int irq_canonicalize(int irq) struct pt_regs; -extern asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs); +extern asmlinkage unsigned int do_IRQ(unsigned int irq); #ifdef CONFIG_MIPS_MT_SMTC /* @@ -55,18 +55,18 @@ do { \ * Ideally there should be away to get this into kernel/irq/handle.c to * avoid the overhead of a call for just a tiny function ... */ -#define do_IRQ(irq, regs) \ +#define do_IRQ(irq) \ do { \ irq_enter(); \ __DO_IRQ_SMTC_HOOK(); \ - __do_IRQ((irq), (regs)); \ + __do_IRQ((irq)); \ irq_exit(); \ } while (0) #endif extern void arch_init_irq(void); -extern void spurious_interrupt(struct pt_regs *regs); +extern void spurious_interrupt(void); #ifdef CONFIG_MIPS_MT_SMTC struct irqaction; diff --git a/include/asm-mips/irq_regs.h b/include/asm-mips/irq_regs.h index 3dd9c0b7027..33bd2a06de5 100644 --- a/include/asm-mips/irq_regs.h +++ b/include/asm-mips/irq_regs.h @@ -1 +1,21 @@ -#include +/* + * 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. + * + * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) + */ +#ifndef __ASM_IRQ_REGS_H +#define __ASM_IRQ_REGS_H + +#define ARCH_HAS_OWN_IRQ_REGS + +#include + +static inline struct pt_regs *get_irq_regs(void) +{ + return current_thread_info()->regs; +} + +#endif /* __ASM_IRQ_REGS_H */ diff --git a/include/asm-mips/jmr3927/irq.h b/include/asm-mips/jmr3927/irq.h index fe551f33a74..e3e7ed38da6 100644 --- a/include/asm-mips/jmr3927/irq.h +++ b/include/asm-mips/jmr3927/irq.h @@ -45,10 +45,6 @@ extern int toshibaboards_setup_irq(int irq, struct irqaction * new); -#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND -extern void tx_branch_likely_bug_fixup(struct pt_regs *regs); -#endif - extern int (*toshibaboards_gen_iack)(void); #endif /* !__ASSEMBLY__ */ diff --git a/include/asm-mips/mach-au1x00/au1000_dma.h b/include/asm-mips/mach-au1x00/au1000_dma.h index 810f2fa3344..0493cb0d617 100644 --- a/include/asm-mips/mach-au1x00/au1000_dma.h +++ b/include/asm-mips/mach-au1x00/au1000_dma.h @@ -123,8 +123,7 @@ struct dma_chan { extern struct dma_chan au1000_dma_table[]; extern int request_au1000_dma(int dev_id, const char *dev_str, - irqreturn_t (*irqhandler)(int, void *, - struct pt_regs *), + irqreturn_t (*irqhandler)(int, void *), unsigned long irqflags, void *irq_dev_id); extern void free_au1000_dma(unsigned int dmanr); diff --git a/include/asm-mips/marvell.h b/include/asm-mips/marvell.h index 6bb2125bb05..df94955b098 100644 --- a/include/asm-mips/marvell.h +++ b/include/asm-mips/marvell.h @@ -53,6 +53,6 @@ struct mv_pci_controller { unsigned long config_vreg; }; -extern void ll_mv64340_irq(struct pt_regs *regs); +extern void ll_mv64340_irq(void); #endif /* __ASM_MIPS_MARVELL_H */ diff --git a/include/asm-mips/msc01_ic.h b/include/asm-mips/msc01_ic.h index 64f17208d60..aa7ad9a7176 100644 --- a/include/asm-mips/msc01_ic.h +++ b/include/asm-mips/msc01_ic.h @@ -145,7 +145,7 @@ typedef struct msc_irqmap { #define MSC01_IRQ_EDGE 1 extern void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq); -extern void ll_msc_irq(struct pt_regs *regs); +extern void ll_msc_irq(void); #endif /* __ASM_MIPS_BOARDS_MSC01_IC_H */ diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h index ae8ada5b42a..e475c45ea26 100644 --- a/include/asm-mips/thread_info.h +++ b/include/asm-mips/thread_info.h @@ -34,6 +34,7 @@ struct thread_info { 0-0xFFFFFFFF for kernel-thread */ struct restart_block restart_block; + struct pt_regs *regs; }; /* diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 30f21df3925..28512ba2266 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -72,13 +72,13 @@ extern irqreturn_t timer_interrupt(int irq, void *dev_id); /* * the corresponding low-level timer interrupt routine. */ -extern asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs); +extern asmlinkage void ll_timer_interrupt(int irq); /* * profiling and process accouting is done separately in local_timer_interrupt */ extern void local_timer_interrupt(int irq, void *dev_id); -extern asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs); +extern asmlinkage void ll_local_timer_interrupt(int irq); /* * board specific routines required by time_init(). -- GitLab From f1d08f71974dcf68ce4510a2dfaeb798b05df2c0 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sat, 7 Oct 2006 13:41:51 +0900 Subject: [PATCH 0770/1619] [MIPS] Fix DECserial build error by IRQ hander change Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- drivers/tc/zs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 7c0fe1dc96a..792becdfe6f 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -389,7 +389,7 @@ static void receive_chars(struct dec_serial *info) if (ch == 0) continue; if (time_before(jiffies, break_pressed + HZ * 5)) { - handle_sysrq(ch, regs, NULL); + handle_sysrq(ch, NULL); break_pressed = 0; continue; } -- GitLab From b7a7179dcae6cecfaaa8384f8c088fb7823c6c90 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 6 Oct 2006 19:49:52 +0200 Subject: [PATCH 0771/1619] ieee1394: nodemgr: fix startup of knodemgrd Revert a thinko in commit d2f119fe319528da8c76a1107459d6f478cbf28c: When knodemgrd starts, it needs to sleep until host->generation was incremented above its initial value of 0. My wrong logic caused it to start sending requests when the bus wasn't completely ready. Seen as "AT dma reset ctx=0, aborting transmission" messages in 2.6.19-rc1. Signed-off-by: Stefan Richter --- drivers/ieee1394/nodemgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 3e7974c5744..8e7b83f8448 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1614,7 +1614,7 @@ static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; struct hpsb_host *host = hi->host; - unsigned int g, generation = get_hpsb_generation(host) - 1; + unsigned int g, generation = 0; int i, reset_cycles = 0; /* Setup our device-model entries */ -- GitLab From ca4aa09635516258f158a7bc1594a794e4c34864 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Oct 2006 14:33:24 -0400 Subject: [PATCH 0772/1619] [PATCH] NFS: Fix typo in nfs_get_client() NFS_CS_INITING > NFS_CS_READY, so instead of waiting for the structure to get initialised, we currently immediately jump out of the loop without ever sleeping. Signed-off-by: Trond Myklebust Signed-off-by: Linus Torvalds --- fs/nfs/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 6e4e48c5092..d2533e21425 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -330,7 +330,7 @@ found_client: for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current) || - clp->cl_cons_state > NFS_CS_READY) + clp->cl_cons_state != NFS_CS_INITING) break; schedule(); } -- GitLab From 7da5d406792eedb5341a8c20296470b2e67743e7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Oct 2006 07:41:19 -0600 Subject: [PATCH 0773/1619] [PATCH] i386/x86_64: FIX pci_enable_irq to set dev->irq to the irq number In commit ace80ab796ae30d2c9ee8a84ab6f608a61f8b87b I removed the weird logic that used the vector number as the irq number when MSI was defined. However pci_enable_irq was using a different test in the io_apic_assign_irqs path and I missed it :( This patch removes the wrong code so no one hits this problem. This code is only active when a specific set of boot command line parameters is specified which likely explains why no one has notices this earlier. Signed-off-by: Eric W. Biederman Signed-off-by: Linus Torvalds --- arch/i386/pci/irq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 47f02af74be..dbc4aae9195 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -1141,10 +1141,6 @@ static int pirq_enable_irq(struct pci_dev *dev) } dev = temp_dev; if (irq >= 0) { -#ifdef CONFIG_PCI_MSI - if (!platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); -#endif printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", pci_name(dev), 'A' + pin, irq); dev->irq = irq; -- GitLab From b940d22d58c41b2ae491dca9232850f6f38f3653 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Oct 2006 07:43:46 -0600 Subject: [PATCH 0774/1619] [PATCH] i386/x86_64: Remove global IO_APIC_VECTOR Which vector an irq is assigned to now varies dynamically and is not needed outside of io_apic.c. So remove the possibility of accessing the information outside of io_apic.c and remove the silly macro that makes looking for users of irq_vector difficult. The fact this compiles ensures there aren't any more pieces of the old CONFIG_PCI_MSI weirdness that I failed to remove. Signed-off-by: Eric W. Biederman Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 12 ++++++------ arch/x86_64/kernel/io_apic.c | 8 ++++---- include/asm-i386/hw_irq.h | 3 --- include/asm-x86_64/hw_irq.h | 2 -- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index b7287fb499f..cd082c36ca0 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1184,8 +1184,8 @@ static int __assign_irq_vector(int irq) BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); - if (IO_APIC_VECTOR(irq) > 0) - return IO_APIC_VECTOR(irq); + if (irq_vector[irq] > 0) + return irq_vector[irq]; current_vector += 8; if (current_vector == SYSCALL_VECTOR) @@ -1199,7 +1199,7 @@ static int __assign_irq_vector(int irq) } vector = current_vector; - IO_APIC_VECTOR(irq) = vector; + irq_vector[irq] = vector; return vector; } @@ -1967,7 +1967,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq) * operation to prevent an edge-triggered interrupt escaping meanwhile. * The idea is from Manfred Spraul. --macro */ - i = IO_APIC_VECTOR(irq); + i = irq_vector[irq]; v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); @@ -1984,7 +1984,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq) static int ioapic_retrigger_irq(unsigned int irq) { - send_IPI_self(IO_APIC_VECTOR(irq)); + send_IPI_self(irq_vector[irq]); return 1; } @@ -2020,7 +2020,7 @@ static inline void init_IO_APIC_traps(void) */ for (irq = 0; irq < NR_IRQS ; irq++) { int tmp = irq; - if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { + if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { /* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 91728d9d347..9c3b9b19d69 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -587,8 +587,8 @@ static int __assign_irq_vector(int irq, cpumask_t mask) BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); - if (IO_APIC_VECTOR(irq) > 0) - old_vector = IO_APIC_VECTOR(irq); + if (irq_vector[irq] > 0) + old_vector = irq_vector[irq]; if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) { return old_vector; } @@ -620,7 +620,7 @@ next: } per_cpu(vector_irq, cpu)[vector] = irq; vector |= cpu << 8; - IO_APIC_VECTOR(irq) = vector; + irq_vector[irq] = vector; return vector; } return -ENOSPC; @@ -1289,7 +1289,7 @@ static inline void init_IO_APIC_traps(void) */ for (irq = 0; irq < NR_IRQS ; irq++) { int tmp = irq; - if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { + if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { /* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 8806c7e002a..0bedbdf5e90 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -26,9 +26,6 @@ * Interrupt entry/exit code at both C and assembly level */ -extern u8 irq_vector[NR_IRQ_VECTORS]; -#define IO_APIC_VECTOR(irq) (irq_vector[irq]) - extern void (*interrupt[NR_IRQS])(void); #ifdef CONFIG_SMP diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 53d0d9fd10d..792dd52fcd7 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -74,10 +74,8 @@ #ifndef __ASSEMBLY__ -extern unsigned int irq_vector[NR_IRQ_VECTORS]; typedef int vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); -#define IO_APIC_VECTOR(irq) (irq_vector[irq]) /* * Various low-level irq details needed by irq.c, process.c, -- GitLab From c7111c1318ee8890f385813f232fdb32643e2653 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Oct 2006 07:47:55 -0600 Subject: [PATCH 0775/1619] [PATCH] x86_64 irq: Allocate a vector across all cpus for genapic_flat. The problem we can't take advantage of lowest priority delivery mode if the vectors are allocated for only one cpu at a time. Nor can we work around hardware that assumes lowest priority delivery mode is always used with several cpus. So this patch introduces the concept of a vector_allocation_domain. A set of cpus that will receive an irq on the same vector. Currently the code for implementing this is placed in the genapic structure so we can vary this depending on how we are using the io_apics. This allows us to restore the previous behaviour of genapic_flat without removing the benefits of having separate vector allocation for large machines. This should also fix the problem report where a hyperthreaded cpu was receving the irq on the wrong hyperthread when in logical delivery mode because the previous behaviour is restored. This patch properly records our allocation of the first 16 irqs to the first 16 available vectors on all cpus. This should be fine but it may run into problems with multiple interrupts at the same interrupt level. Except for some badly maintained comments in the code and the behaviour of the interrupt allocator I have no real understanding of that problem. Signed-off-by: Eric W. Biederman Acked-by: Muli Ben-Yehuda Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/genapic_cluster.c | 8 ++ arch/x86_64/kernel/genapic_flat.c | 24 +++++ arch/x86_64/kernel/io_apic.c | 131 +++++++++++++++++---------- include/asm-x86_64/genapic.h | 1 + include/asm-x86_64/mach_apic.h | 1 + 5 files changed, 117 insertions(+), 48 deletions(-) diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c index cdb90e671b8..73d76308b95 100644 --- a/arch/x86_64/kernel/genapic_cluster.c +++ b/arch/x86_64/kernel/genapic_cluster.c @@ -63,6 +63,13 @@ static cpumask_t cluster_target_cpus(void) return cpumask_of_cpu(0); } +static cpumask_t cluster_vector_allocation_domain(int cpu) +{ + cpumask_t domain = CPU_MASK_NONE; + cpu_set(cpu, domain); + return domain; +} + static void cluster_send_IPI_mask(cpumask_t mask, int vector) { send_IPI_mask_sequence(mask, vector); @@ -119,6 +126,7 @@ struct genapic apic_cluster = { .int_delivery_mode = dest_Fixed, .int_dest_mode = (APIC_DEST_PHYSICAL != 0), .target_cpus = cluster_target_cpus, + .vector_allocation_domain = cluster_vector_allocation_domain, .apic_id_registered = cluster_apic_id_registered, .init_apic_ldr = cluster_init_apic_ldr, .send_IPI_all = cluster_send_IPI_all, diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index 50ad153eaac..0dfc223c183 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c @@ -22,6 +22,20 @@ static cpumask_t flat_target_cpus(void) return cpu_online_map; } +static cpumask_t flat_vector_allocation_domain(int cpu) +{ + /* Careful. Some cpus do not strictly honor the set of cpus + * specified in the interrupt destination when using lowest + * priority interrupt delivery mode. + * + * In particular there was a hyperthreading cpu observed to + * deliver interrupts to the wrong hyperthread when only one + * hyperthread was specified in the interrupt desitination. + */ + cpumask_t domain = { { [0] = APIC_ALL_CPUS, } }; + return domain; +} + /* * Set up the logical destination ID. * @@ -121,6 +135,7 @@ struct genapic apic_flat = { .int_delivery_mode = dest_LowestPrio, .int_dest_mode = (APIC_DEST_LOGICAL != 0), .target_cpus = flat_target_cpus, + .vector_allocation_domain = flat_vector_allocation_domain, .apic_id_registered = flat_apic_id_registered, .init_apic_ldr = flat_init_apic_ldr, .send_IPI_all = flat_send_IPI_all, @@ -141,6 +156,14 @@ static cpumask_t physflat_target_cpus(void) return cpumask_of_cpu(0); } +static cpumask_t physflat_vector_allocation_domain(int cpu) +{ + cpumask_t domain = CPU_MASK_NONE; + cpu_set(cpu, domain); + return domain; +} + + static void physflat_send_IPI_mask(cpumask_t cpumask, int vector) { send_IPI_mask_sequence(cpumask, vector); @@ -179,6 +202,7 @@ struct genapic apic_physflat = { .int_delivery_mode = dest_Fixed, .int_dest_mode = (APIC_DEST_PHYSICAL != 0), .target_cpus = physflat_target_cpus, + .vector_allocation_domain = physflat_vector_allocation_domain, .apic_id_registered = flat_apic_id_registered, .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/ .send_IPI_all = physflat_send_IPI_all, diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 9c3b9b19d69..771bcf77daf 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -47,7 +47,7 @@ #include #include -static int assign_irq_vector(int irq, cpumask_t mask); +static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result); #define __apicdebuginit __init @@ -174,12 +174,10 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) cpus_and(mask, tmp, CPU_MASK_ALL); - vector = assign_irq_vector(irq, mask); + vector = assign_irq_vector(irq, mask, &tmp); if (vector < 0) return; - cpus_clear(tmp); - cpu_set(vector >> 8, tmp); dest = cpu_mask_to_apicid(tmp); /* @@ -188,7 +186,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) dest = SET_APIC_LOGICAL_ID(dest); spin_lock_irqsave(&ioapic_lock, flags); - __target_IO_APIC_irq(irq, dest, vector & 0xff); + __target_IO_APIC_irq(irq, dest, vector); set_native_irq_info(irq, mask); spin_unlock_irqrestore(&ioapic_lock, flags); } @@ -563,9 +561,45 @@ static inline int IO_APIC_irq_trigger(int irq) } /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ -unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 }; +static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { + [0] = FIRST_EXTERNAL_VECTOR + 0, + [1] = FIRST_EXTERNAL_VECTOR + 1, + [2] = FIRST_EXTERNAL_VECTOR + 2, + [3] = FIRST_EXTERNAL_VECTOR + 3, + [4] = FIRST_EXTERNAL_VECTOR + 4, + [5] = FIRST_EXTERNAL_VECTOR + 5, + [6] = FIRST_EXTERNAL_VECTOR + 6, + [7] = FIRST_EXTERNAL_VECTOR + 7, + [8] = FIRST_EXTERNAL_VECTOR + 8, + [9] = FIRST_EXTERNAL_VECTOR + 9, + [10] = FIRST_EXTERNAL_VECTOR + 10, + [11] = FIRST_EXTERNAL_VECTOR + 11, + [12] = FIRST_EXTERNAL_VECTOR + 12, + [13] = FIRST_EXTERNAL_VECTOR + 13, + [14] = FIRST_EXTERNAL_VECTOR + 14, + [15] = FIRST_EXTERNAL_VECTOR + 15, +}; + +static cpumask_t irq_domain[NR_IRQ_VECTORS] __read_mostly = { + [0] = CPU_MASK_ALL, + [1] = CPU_MASK_ALL, + [2] = CPU_MASK_ALL, + [3] = CPU_MASK_ALL, + [4] = CPU_MASK_ALL, + [5] = CPU_MASK_ALL, + [6] = CPU_MASK_ALL, + [7] = CPU_MASK_ALL, + [8] = CPU_MASK_ALL, + [9] = CPU_MASK_ALL, + [10] = CPU_MASK_ALL, + [11] = CPU_MASK_ALL, + [12] = CPU_MASK_ALL, + [13] = CPU_MASK_ALL, + [14] = CPU_MASK_ALL, + [15] = CPU_MASK_ALL, +}; -static int __assign_irq_vector(int irq, cpumask_t mask) +static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) { /* * NOTE! The local APIC isn't very good at handling @@ -589,14 +623,22 @@ static int __assign_irq_vector(int irq, cpumask_t mask) if (irq_vector[irq] > 0) old_vector = irq_vector[irq]; - if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) { - return old_vector; + if (old_vector > 0) { + cpus_and(*result, irq_domain[irq], mask); + if (!cpus_empty(*result)) + return old_vector; } for_each_cpu_mask(cpu, mask) { + cpumask_t domain; + int first, new_cpu; int vector, offset; - vector = pos[cpu].vector; - offset = pos[cpu].offset; + + domain = vector_allocation_domain(cpu); + first = first_cpu(domain); + + vector = pos[first].vector; + offset = pos[first].offset; next: vector += 8; if (vector >= FIRST_SYSTEM_VECTOR) { @@ -604,35 +646,40 @@ next: offset = (offset + 1) % 8; vector = FIRST_DEVICE_VECTOR + offset; } - if (unlikely(pos[cpu].vector == vector)) + if (unlikely(pos[first].vector == vector)) continue; if (vector == IA32_SYSCALL_VECTOR) goto next; - if (per_cpu(vector_irq, cpu)[vector] != -1) - goto next; + for_each_cpu_mask(new_cpu, domain) + if (per_cpu(vector_irq, cpu)[vector] != -1) + goto next; /* Found one! */ - pos[cpu].vector = vector; - pos[cpu].offset = offset; + for_each_cpu_mask(new_cpu, domain) { + pos[cpu].vector = vector; + pos[cpu].offset = offset; + } if (old_vector >= 0) { - int old_cpu = old_vector >> 8; - old_vector &= 0xff; - per_cpu(vector_irq, old_cpu)[old_vector] = -1; + int old_cpu; + for_each_cpu_mask(old_cpu, domain) + per_cpu(vector_irq, old_cpu)[old_vector] = -1; } - per_cpu(vector_irq, cpu)[vector] = irq; - vector |= cpu << 8; + for_each_cpu_mask(new_cpu, domain) + per_cpu(vector_irq, new_cpu)[vector] = irq; irq_vector[irq] = vector; + irq_domain[irq] = domain; + cpus_and(*result, domain, mask); return vector; } return -ENOSPC; } -static int assign_irq_vector(int irq, cpumask_t mask) +static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) { int vector; unsigned long flags; spin_lock_irqsave(&vector_lock, flags); - vector = __assign_irq_vector(irq, mask); + vector = __assign_irq_vector(irq, mask, result); spin_unlock_irqrestore(&vector_lock, flags); return vector; } @@ -704,14 +751,12 @@ static void __init setup_IO_APIC_irqs(void) if (IO_APIC_IRQ(irq)) { cpumask_t mask; - vector = assign_irq_vector(irq, TARGET_CPUS); + vector = assign_irq_vector(irq, TARGET_CPUS, &mask); if (vector < 0) continue; - cpus_clear(mask); - cpu_set(vector >> 8, mask); entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); - entry.vector = vector & 0xff; + entry.vector = vector; ioapic_register_intr(irq, vector, IOAPIC_AUTO); if (!apic && (irq < 16)) @@ -1430,12 +1475,13 @@ static inline void check_timer(void) { int apic1, pin1, apic2, pin2; int vector; + cpumask_t mask; /* * get/set the timer IRQ vector: */ disable_8259A_irq(0); - vector = assign_irq_vector(0, TARGET_CPUS); + vector = assign_irq_vector(0, TARGET_CPUS, &mask); /* * Subtle, code in do_timer_interrupt() expects an AEOI @@ -1667,6 +1713,7 @@ int create_irq(void) int new; int vector = 0; unsigned long flags; + cpumask_t mask; irq = -ENOSPC; spin_lock_irqsave(&vector_lock, flags); @@ -1675,7 +1722,7 @@ int create_irq(void) continue; if (irq_vector[new] != 0) continue; - vector = __assign_irq_vector(new, TARGET_CPUS); + vector = __assign_irq_vector(new, TARGET_CPUS, &mask); if (likely(vector > 0)) irq = new; break; @@ -1707,13 +1754,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms { int vector; unsigned dest; + cpumask_t tmp; - vector = assign_irq_vector(irq, TARGET_CPUS); + vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); if (vector >= 0) { - cpumask_t tmp; - - cpus_clear(tmp); - cpu_set(vector >> 8, tmp); dest = cpu_mask_to_apicid(tmp); msg->address_hi = MSI_ADDR_BASE_HI; @@ -1752,12 +1796,10 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) cpus_and(mask, tmp, CPU_MASK_ALL); - vector = assign_irq_vector(irq, mask); + vector = assign_irq_vector(irq, mask, &tmp); if (vector < 0) return; - cpus_clear(tmp); - cpu_set(vector >> 8, tmp); dest = cpu_mask_to_apicid(tmp); read_msi_msg(irq, &msg); @@ -1844,12 +1886,10 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) cpus_and(mask, tmp, CPU_MASK_ALL); - vector = assign_irq_vector(irq, mask); + vector = assign_irq_vector(irq, mask, &tmp); 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); @@ -1871,15 +1911,13 @@ static struct hw_interrupt_type ht_irq_chip = { int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) { int vector; + cpumask_t tmp; - vector = assign_irq_vector(irq, TARGET_CPUS); + vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); 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); @@ -1945,13 +1983,10 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p add_pin_to_irq(irq, ioapic, pin); - vector = assign_irq_vector(irq, TARGET_CPUS); + vector = assign_irq_vector(irq, TARGET_CPUS, &mask); if (vector < 0) return vector; - cpus_clear(mask); - cpu_set(vector >> 8, mask); - /* * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. * Note that we mask (disable) IRQs now -- these get enabled when the diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86_64/genapic.h index 81e71466534..a0e9a4b9348 100644 --- a/include/asm-x86_64/genapic.h +++ b/include/asm-x86_64/genapic.h @@ -18,6 +18,7 @@ struct genapic { u32 int_dest_mode; int (*apic_id_registered)(void); cpumask_t (*target_cpus)(void); + cpumask_t (*vector_allocation_domain)(int cpu); void (*init_apic_ldr)(void); /* ipi */ void (*send_IPI_mask)(cpumask_t mask, int vector); diff --git a/include/asm-x86_64/mach_apic.h b/include/asm-x86_64/mach_apic.h index d33422450c0..7b7115a0c1c 100644 --- a/include/asm-x86_64/mach_apic.h +++ b/include/asm-x86_64/mach_apic.h @@ -17,6 +17,7 @@ #define INT_DELIVERY_MODE (genapic->int_delivery_mode) #define INT_DEST_MODE (genapic->int_dest_mode) #define TARGET_CPUS (genapic->target_cpus()) +#define vector_allocation_domain (genapic->vector_allocation_domain) #define apic_id_registered (genapic->apic_id_registered) #define init_apic_ldr (genapic->init_apic_ldr) #define send_IPI_mask (genapic->send_IPI_mask) -- GitLab From 0d84438d98777b0f9425d39121c42f47a06878ca Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:30:44 +0100 Subject: [PATCH 0776/1619] [PATCH] sparc32 pt_regs fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/sparc/kernel/irq.c | 23 +++++++++++++++-------- arch/sparc/kernel/pcic.c | 4 ++-- arch/sparc/kernel/sun4c_irq.c | 2 +- arch/sparc/kernel/sun4d_irq.c | 12 ++++++++---- arch/sparc/kernel/sun4d_smp.c | 6 +++++- arch/sparc/kernel/sun4m_irq.c | 2 +- arch/sparc/kernel/sun4m_smp.c | 7 ++++++- arch/sparc/kernel/tick14.c | 2 +- arch/sparc/kernel/time.c | 7 ++++--- drivers/parport/parport_sunbpp.c | 2 +- include/asm-sparc/floppy.h | 2 +- include/asm-sparc/irq.h | 6 +++--- include/asm-sparc/irq_regs.h | 1 + 13 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 include/asm-sparc/irq_regs.h diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 72f0201051a..ae4dfc89ca5 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef CONFIG_SMP #define SMP_NOP2 "nop; nop;\n\t" @@ -133,8 +134,8 @@ static void irq_panic(void) prom_halt(); } -void (*sparc_init_timers)(irqreturn_t (*)(int, void *,struct pt_regs *)) = - (void (*)(irqreturn_t (*)(int, void *,struct pt_regs *))) irq_panic; +void (*sparc_init_timers)(irqreturn_t (*)(int, void *)) = + (void (*)(irqreturn_t (*)(int, void *))) irq_panic; /* * Dave Redman (djhr@tadpole.co.uk) @@ -319,12 +320,14 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) void handler_irq(int irq, struct pt_regs * regs) { + struct pt_regs *old_regs; struct irqaction * action; int cpu = smp_processor_id(); #ifdef CONFIG_SMP extern void smp4m_irq_rotate(int cpu); #endif + old_regs = set_irq_regs(regs); irq_enter(); disable_pil_irq(irq); #ifdef CONFIG_SMP @@ -338,27 +341,31 @@ void handler_irq(int irq, struct pt_regs * regs) do { if (!action || !action->handler) unexpected_irq(irq, NULL, regs); - action->handler(irq, action->dev_id, regs); + action->handler(irq, action->dev_id); action = action->next; } while (action); sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS; enable_pil_irq(irq); irq_exit(); + set_irq_regs(old_regs); } #ifdef CONFIG_BLK_DEV_FD -extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern void floppy_interrupt(int irq, void *dev_id) void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) { + struct pt_regs *old_regs; int cpu = smp_processor_id(); + old_regs = set_irq_regs(regs); disable_pil_irq(irq); irq_enter(); kstat_cpu(cpu).irqs[irq]++; - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); irq_exit(); enable_pil_irq(irq); + set_irq_regs(old_regs); // XXX Eek, it's totally changed with preempt_count() and such // if (softirq_pending(cpu)) // do_softirq(); @@ -369,7 +376,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) * thus no sharing possible. */ int request_fast_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *), unsigned long irqflags, const char *devname) { struct irqaction *action; @@ -468,7 +475,7 @@ out: } int request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *), unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction * action, **actionp; @@ -478,7 +485,7 @@ int request_irq(unsigned int irq, if (sparc_cpu_model == sun4d) { extern int sun4d_request_irq(unsigned int, - irqreturn_t (*)(int, void *, struct pt_regs *), + irqreturn_t (*)(int, void *), unsigned long, const char *, void *); return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); } diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index edb6cc665f5..b4e50ae323b 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -708,13 +708,13 @@ static void pcic_clear_clock_irq(void) pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT); } -static irqreturn_t pcic_timer_handler (int irq, void *h, struct pt_regs *regs) +static irqreturn_t pcic_timer_handler (int irq, void *h) { write_seqlock(&xtime_lock); /* Dummy, to show that we remember */ pcic_clear_clock_irq(); do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif write_sequnlock(&xtime_lock); return IRQ_HANDLED; diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 4be2c86ea54..2eaa0d085e1 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c @@ -154,7 +154,7 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) /* Errm.. not sure how to do this.. */ } -static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) +static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *)) { int irq; diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 74eed9775ac..836d1562787 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -38,6 +38,7 @@ #include #include #include +#include /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */ /* #define DISTRIBUTE_IRQS */ @@ -198,6 +199,7 @@ extern void unexpected_irq(int, void *, struct pt_regs *); void sun4d_handler_irq(int irq, struct pt_regs * regs) { + struct pt_regs *old_regs; struct irqaction * action; int cpu = smp_processor_id(); /* SBUS IRQ level (1 - 7) */ @@ -208,6 +210,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) cc_set_iclr(1 << irq); + old_regs = set_irq_regs(regs); irq_enter(); kstat_cpu(cpu).irqs[irq]++; if (!sbusl) { @@ -215,7 +218,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) if (!action) unexpected_irq(irq, NULL, regs); do { - action->handler(irq, action->dev_id, regs); + action->handler(irq, action->dev_id); action = action->next; } while (action); } else { @@ -242,7 +245,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) if (!action) unexpected_irq(irq, NULL, regs); do { - action->handler(irq, action->dev_id, regs); + action->handler(irq, action->dev_id); action = action->next; } while (action); release_sbi(SBI2DEVID(sbino), slot); @@ -250,6 +253,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) } } irq_exit(); + set_irq_regs(old_regs); } unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq) @@ -272,7 +276,7 @@ unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) } int sun4d_request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *), unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction *action, *tmp = NULL, **actionp; @@ -466,7 +470,7 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit) bw_set_prof_limit(cpu, limit); } -static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) +static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *)) { int irq; int cpu; diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 3ff4edd3281..c80ea61e8ba 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -369,10 +370,12 @@ void smp4d_message_pass(int target, int msg, unsigned long data, int wait) void smp4d_percpu_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs; int cpu = hard_smp4d_processor_id(); static int cpu_tick[NR_CPUS]; static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; + old_regs = set_irq_regs(regs); bw_get_prof_limit(cpu); bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */ @@ -384,7 +387,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) show_leds(cpu); } - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if(!--prof_counter(cpu)) { int user = user_mode(regs); @@ -395,6 +398,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) prof_counter(cpu) = prof_multiplier(cpu); } + set_irq_regs(old_regs); } extern unsigned int lvl14_resolution; diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 7cefa301efe..28bcf8e2c5b 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -228,7 +228,7 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit) sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; } -static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) +static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *)) { int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 7d4a649138f..e2d9c018bd5 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -353,11 +354,14 @@ void smp4m_cross_call_irq(void) void smp4m_percpu_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs; int cpu = smp_processor_id(); + old_regs = set_irq_regs(regs); + clear_profile_irq(cpu); - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if(!--prof_counter(cpu)) { int user = user_mode(regs); @@ -368,6 +372,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) prof_counter(cpu) = prof_multiplier(cpu); } + set_irq_regs(old_regs); } extern unsigned int lvl14_resolution; diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c index d3b4daac705..7107d2f0625 100644 --- a/arch/sparc/kernel/tick14.c +++ b/arch/sparc/kernel/tick14.c @@ -55,7 +55,7 @@ void install_obp_ticker(void) linux_lvl14[3] = obp_lvl14[3]; } -void claim_ticker14(irqreturn_t (*handler)(int, void *, struct pt_regs *), +void claim_ticker14(irqreturn_t (*handler)(int, void *), int irq_nr, unsigned int timeout ) { int cpu = smp_processor_id(); diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index e10dc831944..7dcd1a16c6e 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -42,6 +42,7 @@ #include #include #include +#include DEFINE_SPINLOCK(rtc_lock); enum sparc_clock_type sp_clock_typ; @@ -104,13 +105,13 @@ __volatile__ unsigned int *master_l10_limit; #define TICK_SIZE (tick_nsec / 1000) -irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t timer_interrupt(int irq, void *dev_id) { /* last time the cmos clock got updated */ static long last_rtc_update; #ifndef CONFIG_SMP - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #endif /* Protect counter clear so that do_gettimeoffset works */ @@ -128,7 +129,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index d758c90c86a..9793533276e 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -48,7 +48,7 @@ static irqreturn_t parport_sunbpp_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/include/asm-sparc/floppy.h b/include/asm-sparc/floppy.h index c53b332c850..9073c84218c 100644 --- a/include/asm-sparc/floppy.h +++ b/include/asm-sparc/floppy.h @@ -262,7 +262,7 @@ static __inline__ void sun_fd_enable_dma(void) } /* Our low-level entry point in arch/sparc/kernel/entry.S */ -irqreturn_t floppy_hardint(int irq, void *unused, struct pt_regs *regs); +irqreturn_t floppy_hardint(int irq, void *unused); static int sun_fd_request_irq(void) { diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h index 3141ddfea97..70867330f42 100644 --- a/include/asm-sparc/irq.h +++ b/include/asm-sparc/irq.h @@ -76,8 +76,8 @@ static inline void load_profile_irq(int cpu, int limit) BTFIXUP_CALL(load_profile_irq)(cpu, limit); } -extern void (*sparc_init_timers)(irqreturn_t (*lvl10_irq)(int, void *, struct pt_regs *)); -extern void claim_ticker14(irqreturn_t (*irq_handler)(int, void *, struct pt_regs *), +extern void (*sparc_init_timers)(irqreturn_t (*lvl10_irq)(int, void *)); +extern void claim_ticker14(irqreturn_t (*irq_handler)(int, void *), int irq, unsigned int timeout); @@ -91,7 +91,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int) #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) #endif -extern int request_fast_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, __const__ char *devname); +extern int request_fast_irq(unsigned int irq, irqreturn_t (*handler)(int, void *), unsigned long flags, __const__ char *devname); /* On the sun4m, just like the timers, we have both per-cpu and master * interrupt registers. diff --git a/include/asm-sparc/irq_regs.h b/include/asm-sparc/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-sparc/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 6d24c8dc2e656b02807aa0506405727d34c0376c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 08:23:28 -0400 Subject: [PATCH 0777/1619] [PATCH] sparc64 pt_regs fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/sparc64/kernel/ebus.c | 2 +- arch/sparc64/kernel/irq.c | 5 ++++- arch/sparc64/kernel/pci_psycho.c | 6 +++--- arch/sparc64/kernel/pci_sabre.c | 6 +++--- arch/sparc64/kernel/pci_schizo.c | 8 ++++---- arch/sparc64/kernel/power.c | 2 +- arch/sparc64/kernel/sbus.c | 6 +++--- arch/sparc64/kernel/smp.c | 6 +++++- include/asm-sparc64/floppy.h | 8 ++++---- include/asm-sparc64/irq_regs.h | 1 + 10 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 include/asm-sparc64/irq_regs.h diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 8a9b470e1b6..2df25c2b407 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -79,7 +79,7 @@ static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain) } } -static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ebus_dma_irq(int irq, void *dev_id) { struct ebus_dma_info *p = dev_id; unsigned long flags; diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 4e64724cb9a..ce05deb1bc9 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -547,9 +547,11 @@ void timer_irq(int irq, struct pt_regs *regs) void handler_irq(int irq, struct pt_regs *regs) { struct ino_bucket *bucket; + struct pt_regs *old_regs; clear_softint(1 << irq); + old_regs = set_irq_regs(regs); irq_enter(); /* Sliiiick... */ @@ -558,12 +560,13 @@ void handler_irq(int irq, struct pt_regs *regs) struct ino_bucket *next = __bucket(bucket->irq_chain); bucket->irq_chain = 0; - __do_IRQ(bucket->virt_irq, regs); + __do_IRQ(bucket->virt_irq); bucket = next; } irq_exit(); + set_irq_regs(old_regs); } struct sun5_timer { diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 1ec0aab68c0..fda5db223d9 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -533,7 +533,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p, #define PSYCHO_UEAFSR_RESV2 0x00000000007fffffUL /* Reserved */ #define PSYCHO_UE_AFAR 0x0038UL -static irqreturn_t psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t psycho_ue_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR; @@ -610,7 +610,7 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs) #define PSYCHO_CEAFSR_RESV2 0x00000000007fffffUL /* Reserved */ #define PSYCHO_CE_AFAR 0x0040UL -static irqreturn_t psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t psycho_ce_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR; @@ -735,7 +735,7 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm return ret; } -static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; struct pci_controller_info *p = pbm->parent; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 45891850b90..6ec569828c2 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -574,7 +574,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p, spin_unlock_irqrestore(&iommu->lock, flags); } -static irqreturn_t sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sabre_ue_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR; @@ -634,7 +634,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sabre_ce_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR; @@ -726,7 +726,7 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p) return ret; } -static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg, afar_reg; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 75ade83ecc6..66911b126ae 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -515,7 +515,7 @@ static void schizo_check_iommu_error(struct pci_controller_info *p, #define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL /* Safari */ #define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL /* Safari */ -static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t schizo_ue_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR; @@ -603,7 +603,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) #define SCHIZO_CEAFSR_MTAG 0x000000000000e000UL #define SCHIZO_CEAFSR_ECCSYND 0x00000000000001ffUL -static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t schizo_ce_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR; @@ -778,7 +778,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) return ret; } -static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; struct pci_controller_info *p = pbm->parent; @@ -933,7 +933,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg /* We only expect UNMAP errors here. The rest of the Safari errors * are marked fatal and thus cause a system reset. */ -static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id) { struct pci_controller_info *p = dev_id; u64 errlog; diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 0b9c70627ce..699b24b890d 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -35,7 +35,7 @@ static void __iomem *power_reg; static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); static int button_pressed; -static irqreturn_t power_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t power_handler(int irq, void *dev_id) { if (button_pressed == 0) { button_pressed = 1; diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index c49a5779574..01d6d869ea2 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -839,7 +839,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) #define SYSIO_UEAFSR_SIZE 0x00001c0000000000UL /* Bad transfer size 2^SIZE */ #define SYSIO_UEAFSR_MID 0x000003e000000000UL /* UPA MID causing the fault */ #define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */ -static irqreturn_t sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sysio_ue_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; struct sbus_iommu *iommu = sbus->iommu; @@ -911,7 +911,7 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs) #define SYSIO_CEAFSR_SIZE 0x00001c0000000000UL /* Bad transfer size 2^SIZE */ #define SYSIO_CEAFSR_MID 0x000003e000000000UL /* UPA MID causing the fault */ #define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */ -static irqreturn_t sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sysio_ce_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; struct sbus_iommu *iommu = sbus->iommu; @@ -988,7 +988,7 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs) #define SYSIO_SBAFSR_SIZE 0x00001c0000000000UL /* Size of transfer */ #define SYSIO_SBAFSR_MID 0x000003e000000000UL /* MID causing the error */ #define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */ -static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; struct sbus_iommu *iommu = sbus->iommu; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index f62bf3a2de1..cc09d826641 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -1187,6 +1188,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) unsigned long compare, tick, pstate; int cpu = smp_processor_id(); int user = user_mode(regs); + struct pt_regs *old_regs; /* * Check for level 14 softint. @@ -1203,8 +1205,9 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) clear_softint(tick_mask); } + old_regs = set_irq_regs(regs); do { - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if (!--prof_counter(cpu)) { irq_enter(); @@ -1236,6 +1239,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) : /* no outputs */ : "r" (pstate)); } while (time_after_eq(tick, compare)); + set_irq_regs(old_regs); } static void __init smp_setup_percpu_timer(void) diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index abf15003801..dbe033e494d 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -208,7 +208,7 @@ static void sun_fd_enable_dma(void) pdma_areasize = pdma_size; } -irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) +irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie) { if (likely(doing_pdma)) { void __iomem *stat = (void __iomem *) fdc_status; @@ -255,7 +255,7 @@ irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) } main_interrupt: - return floppy_interrupt(irq, dev_cookie, regs); + return floppy_interrupt(irq, dev_cookie); } static int sun_fd_request_irq(void) @@ -311,7 +311,7 @@ struct sun_pci_dma_op { static struct sun_pci_dma_op sun_pci_dma_current = { -1U, 0, 0, NULL}; static struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL}; -extern irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t floppy_interrupt(int irq, void *dev_id); static unsigned char sun_pci_fd_inb(unsigned long port) { @@ -446,7 +446,7 @@ static int sun_pci_fd_eject(int drive) void sun_pci_fd_dma_callback(struct ebus_dma_info *p, int event, void *cookie) { - floppy_interrupt(0, NULL, NULL); + floppy_interrupt(0, NULL); } /* diff --git a/include/asm-sparc64/irq_regs.h b/include/asm-sparc64/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-sparc64/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 7a39f52202a70ff6834e37053e2ee55c7d351621 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:32:15 +0100 Subject: [PATCH 0778/1619] [PATCH] sparc32 rwlock fix read_trylock() is broken on sparc32 (doesn't build and didn't work right, actually). Proposed fix: - make "writer holds lock" distinguishable from "reader tries to grab lock" - have __raw_read_trylock() try to acquire the mutex (in LSB of lock), terminating spin if we see that there's writer holding it. Then do the rest as we do in read_lock(). Thanks to Ingo for discussion... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/sparc/kernel/sparc_ksyms.c | 4 +++- arch/sparc/lib/locks.S | 20 ++++++++++++++++++++ include/asm-sparc/spinlock.h | 28 +++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 4d441a554d3..33dadd9f287 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -87,6 +87,7 @@ extern void ___set_bit(void); extern void ___clear_bit(void); extern void ___change_bit(void); extern void ___rw_read_enter(void); +extern void ___rw_read_try(void); extern void ___rw_read_exit(void); extern void ___rw_write_enter(void); @@ -104,8 +105,9 @@ extern unsigned _Urem(unsigned, unsigned); EXPORT_SYMBOL(sparc_cpu_model); EXPORT_SYMBOL(kernel_thread); #ifdef CONFIG_SMP -// XXX find what uses (or used) these. +// XXX find what uses (or used) these. AV: see asm/spinlock.h EXPORT_SYMBOL(___rw_read_enter); +EXPORT_SYMBOL(___rw_read_try); EXPORT_SYMBOL(___rw_read_exit); EXPORT_SYMBOL(___rw_write_enter); #endif diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S index 95fa4842496..b1df55cb221 100644 --- a/arch/sparc/lib/locks.S +++ b/arch/sparc/lib/locks.S @@ -25,6 +25,15 @@ ___rw_read_enter_spin_on_wlock: ldstub [%g1 + 3], %g2 b ___rw_read_enter_spin_on_wlock ldub [%g1 + 3], %g2 +___rw_read_try_spin_on_wlock: + andcc %g2, 0xff, %g0 + be,a ___rw_read_try + ldstub [%g1 + 3], %g2 + xnorcc %g2, 0x0, %o0 /* if g2 is ~0, set o0 to 0 and bugger off */ + bne,a ___rw_read_enter_spin_on_wlock + ld [%g1], %g2 + retl + mov %g4, %o7 ___rw_read_exit_spin_on_wlock: orcc %g2, 0x0, %g0 be,a ___rw_read_exit @@ -60,6 +69,17 @@ ___rw_read_exit: retl mov %g4, %o7 + .globl ___rw_read_try +___rw_read_try: + orcc %g2, 0x0, %g0 + bne ___rw_read_try_spin_on_wlock + ld [%g1], %g2 + add %g2, 1, %g2 + st %g2, [%g1] + set 1, %o1 + retl + mov %g4, %o7 + .globl ___rw_write_enter ___rw_write_enter: orcc %g2, 0x0, %g0 diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h index 557d08959d2..de2249b267c 100644 --- a/include/asm-sparc/spinlock.h +++ b/include/asm-sparc/spinlock.h @@ -129,6 +129,7 @@ static inline void __raw_write_lock(raw_rwlock_t *rw) : /* no outputs */ : "r" (lp) : "g2", "g4", "memory", "cc"); + *(volatile __u32 *)&lp->lock = ~0U; } static inline int __raw_write_trylock(raw_rwlock_t *rw) @@ -144,15 +145,40 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) val = rw->lock & ~0xff; if (val) ((volatile u8*)&rw->lock)[3] = 0; + else + *(volatile u32*)&rw->lock = ~0U; } return (val == 0); } +static inline int __read_trylock(raw_rwlock_t *rw) +{ + register raw_rwlock_t *lp asm("g1"); + register int res asm("o0"); + lp = rw; + __asm__ __volatile__( + "mov %%o7, %%g4\n\t" + "call ___rw_read_try\n\t" + " ldstub [%%g1 + 3], %%g2\n" + : "=r" (res) + : "r" (lp) + : "g2", "g4", "memory", "cc"); + return res; +} + +#define __raw_read_trylock(lock) \ +({ unsigned long flags; \ + int res; \ + local_irq_save(flags); \ + res = __read_trylock(lock); \ + local_irq_restore(flags); \ + res; \ +}) + #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0) #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) -#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) #define _raw_spin_relax(lock) cpu_relax() #define _raw_read_relax(lock) cpu_relax() -- GitLab From 8dab42a96781a1100a6b5cc6a66953fc51c30bc1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:33:33 +0100 Subject: [PATCH 0779/1619] [PATCH] m68k pt_regs fixes, part 2 Fallout from previous patch: - actually add include/asm-m68k/irq_regs.h - missed the prototype of sun3_sched_init() NB: git diff without argumentgs sucks when you've added some files... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m68k/sun3/config.c | 2 +- include/asm-m68k/irq_regs.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 include/asm-m68k/irq_regs.h diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index db930f9070e..43e4aa3f404 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -35,7 +35,7 @@ extern char _text, _end; char sun3_reserved_pmeg[SUN3_PMEGS_NUM]; extern unsigned long sun3_gettimeoffset(void); -extern void sun3_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +extern void sun3_sched_init(irqreturn_t (*handler)(int, void *)); extern void sun3_get_model (char* model); extern void idprom_init (void); extern int sun3_hwclk(int set, struct rtc_time *t); diff --git a/include/asm-m68k/irq_regs.h b/include/asm-m68k/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-m68k/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 7ca56053b29633ef08b14e5ca16c663363edac36 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:36:08 +0100 Subject: [PATCH 0780/1619] [PATCH] alpha pt_regs cleanups: device_interrupt callers of ->device_interrupt() do set_irq_regs() now; pt_regs argument removed, remaining uses of regs in instances of ->device_interrupt() are switched to get_irq_regs() and will be gone in the next patch. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/irq_alpha.c | 5 ++++- arch/alpha/kernel/irq_i8259.c | 4 ++-- arch/alpha/kernel/irq_impl.h | 6 +++--- arch/alpha/kernel/irq_pyxis.c | 6 +++--- arch/alpha/kernel/irq_srm.c | 4 ++-- arch/alpha/kernel/sys_alcor.c | 6 +++--- arch/alpha/kernel/sys_cabriolet.c | 16 ++++++++-------- arch/alpha/kernel/sys_dp264.c | 14 +++++++------- arch/alpha/kernel/sys_eb64p.c | 6 +++--- arch/alpha/kernel/sys_eiger.c | 16 ++++++++-------- arch/alpha/kernel/sys_jensen.c | 6 +++--- arch/alpha/kernel/sys_marvel.c | 4 ++-- arch/alpha/kernel/sys_miata.c | 4 ++-- arch/alpha/kernel/sys_mikasa.c | 6 +++--- arch/alpha/kernel/sys_noritake.c | 10 +++++----- arch/alpha/kernel/sys_rawhide.c | 4 ++-- arch/alpha/kernel/sys_rx164.c | 6 +++--- arch/alpha/kernel/sys_sable.c | 4 ++-- arch/alpha/kernel/sys_takara.c | 16 ++++++++-------- arch/alpha/kernel/sys_titan.c | 11 +++++++---- arch/alpha/kernel/sys_wildfire.c | 4 ++-- include/asm-alpha/machvec.h | 2 +- 22 files changed, 83 insertions(+), 77 deletions(-) diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index ddf5cf8dcb0..d14cc423aa4 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -39,6 +39,7 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, struct pt_regs *regs) { + struct pt_regs *old_regs; switch (type) { case 0: #ifdef CONFIG_SMP @@ -72,7 +73,9 @@ do_entInt(unsigned long type, unsigned long vector, alpha_mv.machine_check(vector, la_ptr, regs); return; case 3: - alpha_mv.device_interrupt(vector, regs); + old_regs = set_irq_regs(regs); + alpha_mv.device_interrupt(vector); + set_irq_regs(old_regs); return; case 4: perf_irq(la_ptr, regs); diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c index ebbadbc0c36..6c70f8b97b7 100644 --- a/arch/alpha/kernel/irq_i8259.c +++ b/arch/alpha/kernel/irq_i8259.c @@ -137,7 +137,7 @@ init_i8259a_irqs(void) #if defined(IACK_SC) void -isa_device_interrupt(unsigned long vector, struct pt_regs *regs) +isa_device_interrupt(unsigned long vector) { /* * Generate a PCI interrupt acknowledge cycle. The PIC will @@ -147,7 +147,7 @@ isa_device_interrupt(unsigned long vector, struct pt_regs *regs) */ int j = *(vuip) IACK_SC; j &= 0xff; - handle_irq(j, regs); + handle_irq(j, get_irq_regs()); } #endif diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h index f201d8ffc0d..5d84dbdcdb8 100644 --- a/arch/alpha/kernel/irq_impl.h +++ b/arch/alpha/kernel/irq_impl.h @@ -15,10 +15,10 @@ #define RTC_IRQ 8 -extern void isa_device_interrupt(unsigned long, struct pt_regs *); +extern void isa_device_interrupt(unsigned long); extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *); -extern void srm_device_interrupt(unsigned long, struct pt_regs *); -extern void pyxis_device_interrupt(unsigned long, struct pt_regs *); +extern void srm_device_interrupt(unsigned long); +extern void pyxis_device_interrupt(unsigned long); extern struct irqaction timer_irqaction; extern struct irqaction isa_cascade_irqaction; diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c index 3b581415bab..686dc22111b 100644 --- a/arch/alpha/kernel/irq_pyxis.c +++ b/arch/alpha/kernel/irq_pyxis.c @@ -81,7 +81,7 @@ static struct hw_interrupt_type pyxis_irq_type = { }; void -pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs) +pyxis_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; @@ -98,9 +98,9 @@ pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 7) - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); else - handle_irq(16+i, regs); + handle_irq(16+i, get_irq_regs()); } } diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c index 8e4d121f84c..2e9f6d421a8 100644 --- a/arch/alpha/kernel/irq_srm.c +++ b/arch/alpha/kernel/irq_srm.c @@ -72,8 +72,8 @@ init_srm_irqs(long max, unsigned long ignore_mask) } void -srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +srm_device_interrupt(unsigned long vector) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index d6926b7b1e9..2d412c87654 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c @@ -100,7 +100,7 @@ static struct hw_interrupt_type alcor_irq_type = { }; static void -alcor_device_interrupt(unsigned long vector, struct pt_regs *regs) +alcor_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; @@ -116,9 +116,9 @@ alcor_device_interrupt(unsigned long vector, struct pt_regs *regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 31) { - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); } else { - handle_irq(16 + i, regs); + handle_irq(16 + i, get_irq_regs()); } } } diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index 25a215067da..e75f0cea6fc 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -82,7 +82,7 @@ static struct hw_interrupt_type cabriolet_irq_type = { }; static void -cabriolet_device_interrupt(unsigned long v, struct pt_regs *r) +cabriolet_device_interrupt(unsigned long v) { unsigned long pld; unsigned int i; @@ -98,15 +98,15 @@ cabriolet_device_interrupt(unsigned long v, struct pt_regs *r) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 4) { - isa_device_interrupt(v, r); + isa_device_interrupt(v); } else { - handle_irq(16 + i, r); + handle_irq(16 + i, get_irq_regs()); } } } static void __init -common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r)) +common_init_irq(void (*srm_dev_int)(unsigned long v)) { init_i8259a_irqs(); @@ -154,18 +154,18 @@ cabriolet_init_irq(void) too invasive though. */ static void -pc164_srm_device_interrupt(unsigned long v, struct pt_regs *r) +pc164_srm_device_interrupt(unsigned long v) { __min_ipl = getipl(); - srm_device_interrupt(v, r); + srm_device_interrupt(v); __min_ipl = 0; } static void -pc164_device_interrupt(unsigned long v, struct pt_regs *r) +pc164_device_interrupt(unsigned long v) { __min_ipl = getipl(); - cabriolet_device_interrupt(v, r); + cabriolet_device_interrupt(v); __min_ipl = 0; } diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index dd6103b867e..57dce0098a1 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -217,7 +217,7 @@ static struct hw_interrupt_type clipper_irq_type = { }; static void -dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) +dp264_device_interrupt(unsigned long vector) { #if 1 printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n"); @@ -236,9 +236,9 @@ dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 55) - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); else - handle_irq(16 + i, 16 + i, regs); + handle_irq(16 + i, get_irq_regs()); #if 0 TSUNAMI_cchip->dir0.csr = 1UL << i; mb(); tmp = TSUNAMI_cchip->dir0.csr; @@ -248,7 +248,7 @@ dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) } static void -dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +dp264_srm_device_interrupt(unsigned long vector) { int irq; @@ -268,11 +268,11 @@ dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) if (irq >= 32) irq -= 16; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void -clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +clipper_srm_device_interrupt(unsigned long vector) { int irq; @@ -290,7 +290,7 @@ clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) * * Eg IRQ 24 is DRIR bit 8, etc, etc */ - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c index ed108b66ec0..90d27256d7d 100644 --- a/arch/alpha/kernel/sys_eb64p.c +++ b/arch/alpha/kernel/sys_eb64p.c @@ -80,7 +80,7 @@ static struct hw_interrupt_type eb64p_irq_type = { }; static void -eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs) +eb64p_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; @@ -97,9 +97,9 @@ eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs) pld &= pld - 1; /* clear least bit set */ if (i == 5) { - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); } else { - handle_irq(16 + i, regs); + handle_irq(16 + i, get_irq_regs()); } } } diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c index 64a785baf53..f38cded2df9 100644 --- a/arch/alpha/kernel/sys_eiger.c +++ b/arch/alpha/kernel/sys_eiger.c @@ -91,7 +91,7 @@ static struct hw_interrupt_type eiger_irq_type = { }; static void -eiger_device_interrupt(unsigned long vector, struct pt_regs * regs) +eiger_device_interrupt(unsigned long vector) { unsigned intstatus; @@ -118,20 +118,20 @@ eiger_device_interrupt(unsigned long vector, struct pt_regs * regs) * despatch an interrupt if it's set. */ - if (intstatus & 8) handle_irq(16+3, regs); - if (intstatus & 4) handle_irq(16+2, regs); - if (intstatus & 2) handle_irq(16+1, regs); - if (intstatus & 1) handle_irq(16+0, regs); + if (intstatus & 8) handle_irq(16+3, get_irq_regs()); + if (intstatus & 4) handle_irq(16+2, get_irq_regs()); + if (intstatus & 2) handle_irq(16+1, get_irq_regs()); + if (intstatus & 1) handle_irq(16+0, get_irq_regs()); } else { - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); } } static void -eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +eiger_srm_device_interrupt(unsigned long vector) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index 4ac2b328b8d..fc316369f4d 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c @@ -129,7 +129,7 @@ static struct hw_interrupt_type jensen_local_irq_type = { }; static void -jensen_device_interrupt(unsigned long vector, struct pt_regs * regs) +jensen_device_interrupt(unsigned long vector) { int irq; @@ -189,7 +189,7 @@ jensen_device_interrupt(unsigned long vector, struct pt_regs * regs) if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) || irq != last_irq) { printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n", - irq, count, cc-last_cc, regs->pc); + irq, count, cc-last_cc, get_irq_regs()->pc); count = 0; last_msg = cc; last_irq = irq; @@ -198,7 +198,7 @@ jensen_device_interrupt(unsigned long vector, struct pt_regs * regs) } #endif - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index 36d21595437..4ea5615be43 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c @@ -38,7 +38,7 @@ * Interrupt handling. */ static void -io7_device_interrupt(unsigned long vector, struct pt_regs * regs) +io7_device_interrupt(unsigned long vector) { unsigned int pid; unsigned int irq; @@ -64,7 +64,7 @@ io7_device_interrupt(unsigned long vector, struct pt_regs * regs) irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* not too many bits */ irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */ - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static volatile unsigned long * diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c index 61ac56f8eee..fbbd95212a9 100644 --- a/arch/alpha/kernel/sys_miata.c +++ b/arch/alpha/kernel/sys_miata.c @@ -33,7 +33,7 @@ static void -miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +miata_srm_device_interrupt(unsigned long vector) { int irq; @@ -56,7 +56,7 @@ miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) if (irq >= 16) irq = irq + 8; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index cc4c5811136..5429ba0e08f 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -79,7 +79,7 @@ static struct hw_interrupt_type mikasa_irq_type = { }; static void -mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs) +mikasa_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; @@ -97,9 +97,9 @@ mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i < 16) { - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); } else { - handle_irq(i, regs); + handle_irq(i, get_irq_regs()); } } } diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c index 2d3cff7e8c5..b9a843447b8 100644 --- a/arch/alpha/kernel/sys_noritake.c +++ b/arch/alpha/kernel/sys_noritake.c @@ -77,7 +77,7 @@ static struct hw_interrupt_type noritake_irq_type = { }; static void -noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) +noritake_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; @@ -96,15 +96,15 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i < 16) { - isa_device_interrupt(vector, regs); + isa_device_interrupt(vector); } else { - handle_irq(i, regs); + handle_irq(i, get_irq_regs()); } } } static void -noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +noritake_srm_device_interrupt(unsigned long vector) { int irq; @@ -122,7 +122,7 @@ noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) if (irq >= 16) irq = irq + 1; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c index 949607e3d6f..bef65162bfa 100644 --- a/arch/alpha/kernel/sys_rawhide.c +++ b/arch/alpha/kernel/sys_rawhide.c @@ -134,7 +134,7 @@ static struct hw_interrupt_type rawhide_irq_type = { }; static void -rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +rawhide_srm_device_interrupt(unsigned long vector) { int irq; @@ -158,7 +158,7 @@ rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) /* Adjust by which hose it is from. */ irq -= ((irq + 16) >> 2) & 0x38; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c index 6ae50605263..fa8eef8dd8c 100644 --- a/arch/alpha/kernel/sys_rx164.c +++ b/arch/alpha/kernel/sys_rx164.c @@ -83,7 +83,7 @@ static struct hw_interrupt_type rx164_irq_type = { }; static void -rx164_device_interrupt(unsigned long vector, struct pt_regs *regs) +rx164_device_interrupt(unsigned long vector) { unsigned long pld; volatile unsigned int *dirr; @@ -102,9 +102,9 @@ rx164_device_interrupt(unsigned long vector, struct pt_regs *regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 20) { - isa_no_iack_sc_device_interrupt(vector, regs); + isa_no_iack_sc_device_interrupt(vector, get_irq_regs()); } else { - handle_irq(16+i, regs); + handle_irq(16+i, get_irq_regs()); } } } diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c index a7a14647b50..791379101e7 100644 --- a/arch/alpha/kernel/sys_sable.c +++ b/arch/alpha/kernel/sys_sable.c @@ -512,7 +512,7 @@ static struct hw_interrupt_type sable_lynx_irq_type = { }; static void -sable_lynx_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +sable_lynx_srm_device_interrupt(unsigned long vector) { /* Note that the vector reported by the SRM PALcode corresponds to the interrupt mask bits, but we have to manage via the @@ -526,7 +526,7 @@ sable_lynx_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n", __FUNCTION__, vector, bit, irq); #endif - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c index 2c75cd1fd81..ce2d3b081dc 100644 --- a/arch/alpha/kernel/sys_takara.c +++ b/arch/alpha/kernel/sys_takara.c @@ -85,7 +85,7 @@ static struct hw_interrupt_type takara_irq_type = { }; static void -takara_device_interrupt(unsigned long vector, struct pt_regs *regs) +takara_device_interrupt(unsigned long vector) { unsigned intstatus; @@ -112,20 +112,20 @@ takara_device_interrupt(unsigned long vector, struct pt_regs *regs) * despatch an interrupt if it's set. */ - if (intstatus & 8) handle_irq(16+3, regs); - if (intstatus & 4) handle_irq(16+2, regs); - if (intstatus & 2) handle_irq(16+1, regs); - if (intstatus & 1) handle_irq(16+0, regs); + if (intstatus & 8) handle_irq(16+3, get_irq_regs()); + if (intstatus & 4) handle_irq(16+2, get_irq_regs()); + if (intstatus & 2) handle_irq(16+1, get_irq_regs()); + if (intstatus & 1) handle_irq(16+0, get_irq_regs()); } else { - isa_device_interrupt (vector, regs); + isa_device_interrupt (vector); } } static void -takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +takara_srm_device_interrupt(unsigned long vector) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } static void __init diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c index 302aab38d95..1473aa0e698 100644 --- a/arch/alpha/kernel/sys_titan.c +++ b/arch/alpha/kernel/sys_titan.c @@ -167,18 +167,18 @@ titan_set_irq_affinity(unsigned int irq, cpumask_t affinity) } static void -titan_device_interrupt(unsigned long vector, struct pt_regs * regs) +titan_device_interrupt(unsigned long vector) { printk("titan_device_interrupt: NOT IMPLEMENTED YET!! \n"); } static void -titan_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +titan_srm_device_interrupt(unsigned long vector) { int irq; irq = (vector - 0x800) >> 4; - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); } @@ -245,6 +245,7 @@ titan_legacy_init_irq(void) void titan_dispatch_irqs(u64 mask, struct pt_regs *regs) { + struct pt_regs *old_regs; unsigned long vector; /* @@ -252,6 +253,7 @@ titan_dispatch_irqs(u64 mask, struct pt_regs *regs) */ mask &= titan_cpu_irq_affinity[smp_processor_id()]; + old_regs = set_irq_regs(regs); /* * Dispatch all requested interrupts */ @@ -263,8 +265,9 @@ titan_dispatch_irqs(u64 mask, struct pt_regs *regs) vector = 0x900 + (vector << 4); /* convert to SRM vector */ /* dispatch it */ - alpha_mv.device_interrupt(vector, regs); + alpha_mv.device_interrupt(vector); } + set_irq_regs(old_regs); } diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c index 22c5798fe08..ddf5edd0cec 100644 --- a/arch/alpha/kernel/sys_wildfire.c +++ b/arch/alpha/kernel/sys_wildfire.c @@ -234,7 +234,7 @@ wildfire_init_irq(void) } static void -wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs) +wildfire_device_interrupt(unsigned long vector) { int irq; @@ -246,7 +246,7 @@ wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs) * bits 5-0: irq in PCA */ - handle_irq(irq, regs); + handle_irq(irq, get_irq_regs()); return; } diff --git a/include/asm-alpha/machvec.h b/include/asm-alpha/machvec.h index aced22f9175..7ae744240f8 100644 --- a/include/asm-alpha/machvec.h +++ b/include/asm-alpha/machvec.h @@ -79,7 +79,7 @@ struct alpha_machine_vector void (*update_irq_hw)(unsigned long, unsigned long, int); void (*ack_irq)(unsigned long); - void (*device_interrupt)(unsigned long vector, struct pt_regs *regs); + void (*device_interrupt)(unsigned long vector); void (*machine_check)(u64 vector, u64 la, struct pt_regs *regs); void (*smp_callin)(void); -- GitLab From 3dbb8c62897f96bbf5d4e4fe649e5d3791fc33c5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:37:32 +0100 Subject: [PATCH 0781/1619] [PATCH] alpha pt_regs cleanups: handle_irq() isa_no_iack_sc_device_interrupt() always gets get_irq_regs() as argument; kill that argument. All but two callers of handle_irq() pass get_irq_regs() as argument; convert the remaining two, kill set_irq_regs() inside handle_irq(). Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/irq.c | 5 +---- arch/alpha/kernel/irq_alpha.c | 6 ++++-- arch/alpha/kernel/irq_i8259.c | 6 +++--- arch/alpha/kernel/irq_impl.h | 4 ++-- arch/alpha/kernel/irq_pyxis.c | 2 +- arch/alpha/kernel/irq_srm.c | 2 +- arch/alpha/kernel/sys_alcor.c | 2 +- arch/alpha/kernel/sys_cabriolet.c | 2 +- arch/alpha/kernel/sys_dp264.c | 6 +++--- arch/alpha/kernel/sys_eb64p.c | 2 +- arch/alpha/kernel/sys_eiger.c | 10 +++++----- arch/alpha/kernel/sys_jensen.c | 2 +- arch/alpha/kernel/sys_marvel.c | 2 +- arch/alpha/kernel/sys_miata.c | 2 +- arch/alpha/kernel/sys_mikasa.c | 2 +- arch/alpha/kernel/sys_noritake.c | 4 ++-- arch/alpha/kernel/sys_rawhide.c | 2 +- arch/alpha/kernel/sys_rx164.c | 4 ++-- arch/alpha/kernel/sys_sable.c | 2 +- arch/alpha/kernel/sys_takara.c | 10 +++++----- arch/alpha/kernel/sys_titan.c | 2 +- arch/alpha/kernel/sys_wildfire.c | 2 +- 22 files changed, 40 insertions(+), 41 deletions(-) diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index dba4e70926f..facf82a5499 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -127,9 +127,8 @@ unlock: #define MAX_ILLEGAL_IRQS 16 void -handle_irq(int irq, struct pt_regs * regs) +handle_irq(int irq) { - struct pt_regs *old_regs; /* * We ack quickly, we don't want the irq controller * thinking we're snobs just because some other CPU has @@ -150,7 +149,6 @@ handle_irq(int irq, struct pt_regs * regs) return; } - old_regs = set_irq_regs(regs); irq_enter(); /* * __do_IRQ() must be called with IPL_MAX. Note that we do not @@ -161,5 +159,4 @@ handle_irq(int irq, struct pt_regs * regs) local_irq_disable(); __do_IRQ(irq); irq_exit(); - set_irq_regs(old_regs); } diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index d14cc423aa4..51d66b7f99e 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -52,6 +52,7 @@ do_entInt(unsigned long type, unsigned long vector, #endif break; case 1: + old_regs = set_irq_regs(regs); #ifdef CONFIG_SMP { long cpu; @@ -62,12 +63,13 @@ do_entInt(unsigned long type, unsigned long vector, if (cpu != boot_cpuid) { kstat_cpu(cpu).irqs[RTC_IRQ]++; } else { - handle_irq(RTC_IRQ, regs); + handle_irq(RTC_IRQ); } } #else - handle_irq(RTC_IRQ, regs); + handle_irq(RTC_IRQ); #endif + set_irq_regs(old_regs); return; case 2: alpha_mv.machine_check(vector, la_ptr, regs); diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c index 6c70f8b97b7..9405bee9894 100644 --- a/arch/alpha/kernel/irq_i8259.c +++ b/arch/alpha/kernel/irq_i8259.c @@ -147,13 +147,13 @@ isa_device_interrupt(unsigned long vector) */ int j = *(vuip) IACK_SC; j &= 0xff; - handle_irq(j, get_irq_regs()); + handle_irq(j); } #endif #if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC) void -isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs) +isa_no_iack_sc_device_interrupt(unsigned long vector) { unsigned long pic; @@ -176,7 +176,7 @@ isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs) while (pic) { int j = ffz(~pic); pic &= pic - 1; - handle_irq(j, regs); + handle_irq(j); } } #endif diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h index 5d84dbdcdb8..cc9a8a7aa27 100644 --- a/arch/alpha/kernel/irq_impl.h +++ b/arch/alpha/kernel/irq_impl.h @@ -16,7 +16,7 @@ #define RTC_IRQ 8 extern void isa_device_interrupt(unsigned long); -extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *); +extern void isa_no_iack_sc_device_interrupt(unsigned long); extern void srm_device_interrupt(unsigned long); extern void pyxis_device_interrupt(unsigned long); @@ -39,4 +39,4 @@ extern void i8259a_end_irq(unsigned int); extern struct hw_interrupt_type i8259a_irq_type; extern void init_i8259a_irqs(void); -extern void handle_irq(int irq, struct pt_regs * regs); +extern void handle_irq(int irq); diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c index 686dc22111b..d53edbccbfe 100644 --- a/arch/alpha/kernel/irq_pyxis.c +++ b/arch/alpha/kernel/irq_pyxis.c @@ -100,7 +100,7 @@ pyxis_device_interrupt(unsigned long vector) if (i == 7) isa_device_interrupt(vector); else - handle_irq(16+i, get_irq_regs()); + handle_irq(16+i); } } diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c index 2e9f6d421a8..32212014fbe 100644 --- a/arch/alpha/kernel/irq_srm.c +++ b/arch/alpha/kernel/irq_srm.c @@ -75,5 +75,5 @@ void srm_device_interrupt(unsigned long vector) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index 2d412c87654..49bedfbbd31 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c @@ -118,7 +118,7 @@ alcor_device_interrupt(unsigned long vector) if (i == 31) { isa_device_interrupt(vector); } else { - handle_irq(16 + i, get_irq_regs()); + handle_irq(16 + i); } } } diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index e75f0cea6fc..ace475c124f 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -100,7 +100,7 @@ cabriolet_device_interrupt(unsigned long v) if (i == 4) { isa_device_interrupt(v); } else { - handle_irq(16 + i, get_irq_regs()); + handle_irq(16 + i); } } } diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 57dce0098a1..85d2f933dd0 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -238,7 +238,7 @@ dp264_device_interrupt(unsigned long vector) if (i == 55) isa_device_interrupt(vector); else - handle_irq(16 + i, get_irq_regs()); + handle_irq(16 + i); #if 0 TSUNAMI_cchip->dir0.csr = 1UL << i; mb(); tmp = TSUNAMI_cchip->dir0.csr; @@ -268,7 +268,7 @@ dp264_srm_device_interrupt(unsigned long vector) if (irq >= 32) irq -= 16; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void @@ -290,7 +290,7 @@ clipper_srm_device_interrupt(unsigned long vector) * * Eg IRQ 24 is DRIR bit 8, etc, etc */ - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c index 90d27256d7d..9c5a306dc0e 100644 --- a/arch/alpha/kernel/sys_eb64p.c +++ b/arch/alpha/kernel/sys_eb64p.c @@ -99,7 +99,7 @@ eb64p_device_interrupt(unsigned long vector) if (i == 5) { isa_device_interrupt(vector); } else { - handle_irq(16 + i, get_irq_regs()); + handle_irq(16 + i); } } } diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c index f38cded2df9..7ef3b6fb370 100644 --- a/arch/alpha/kernel/sys_eiger.c +++ b/arch/alpha/kernel/sys_eiger.c @@ -118,10 +118,10 @@ eiger_device_interrupt(unsigned long vector) * despatch an interrupt if it's set. */ - if (intstatus & 8) handle_irq(16+3, get_irq_regs()); - if (intstatus & 4) handle_irq(16+2, get_irq_regs()); - if (intstatus & 2) handle_irq(16+1, get_irq_regs()); - if (intstatus & 1) handle_irq(16+0, get_irq_regs()); + if (intstatus & 8) handle_irq(16+3); + if (intstatus & 4) handle_irq(16+2); + if (intstatus & 2) handle_irq(16+1); + if (intstatus & 1) handle_irq(16+0); } else { isa_device_interrupt(vector); } @@ -131,7 +131,7 @@ static void eiger_srm_device_interrupt(unsigned long vector) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index fc316369f4d..a7b89022938 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c @@ -198,7 +198,7 @@ jensen_device_interrupt(unsigned long vector) } #endif - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index 4ea5615be43..e349f03b830 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c @@ -64,7 +64,7 @@ io7_device_interrupt(unsigned long vector) irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* not too many bits */ irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */ - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static volatile unsigned long * diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c index fbbd95212a9..b8b817feb1e 100644 --- a/arch/alpha/kernel/sys_miata.c +++ b/arch/alpha/kernel/sys_miata.c @@ -56,7 +56,7 @@ miata_srm_device_interrupt(unsigned long vector) if (irq >= 16) irq = irq + 8; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index 5429ba0e08f..ba98048d61a 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -99,7 +99,7 @@ mikasa_device_interrupt(unsigned long vector) if (i < 16) { isa_device_interrupt(vector); } else { - handle_irq(i, get_irq_regs()); + handle_irq(i); } } } diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c index b9a843447b8..679836205f0 100644 --- a/arch/alpha/kernel/sys_noritake.c +++ b/arch/alpha/kernel/sys_noritake.c @@ -98,7 +98,7 @@ noritake_device_interrupt(unsigned long vector) if (i < 16) { isa_device_interrupt(vector); } else { - handle_irq(i, get_irq_regs()); + handle_irq(i); } } } @@ -122,7 +122,7 @@ noritake_srm_device_interrupt(unsigned long vector) if (irq >= 16) irq = irq + 1; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c index bef65162bfa..581d08c70b9 100644 --- a/arch/alpha/kernel/sys_rawhide.c +++ b/arch/alpha/kernel/sys_rawhide.c @@ -158,7 +158,7 @@ rawhide_srm_device_interrupt(unsigned long vector) /* Adjust by which hose it is from. */ irq -= ((irq + 16) >> 2) & 0x38; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c index fa8eef8dd8c..ce1faa6f1df 100644 --- a/arch/alpha/kernel/sys_rx164.c +++ b/arch/alpha/kernel/sys_rx164.c @@ -102,9 +102,9 @@ rx164_device_interrupt(unsigned long vector) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 20) { - isa_no_iack_sc_device_interrupt(vector, get_irq_regs()); + isa_no_iack_sc_device_interrupt(vector); } else { - handle_irq(16+i, get_irq_regs()); + handle_irq(16+i); } } } diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c index 791379101e7..906019cfa68 100644 --- a/arch/alpha/kernel/sys_sable.c +++ b/arch/alpha/kernel/sys_sable.c @@ -526,7 +526,7 @@ sable_lynx_srm_device_interrupt(unsigned long vector) printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n", __FUNCTION__, vector, bit, irq); #endif - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c index ce2d3b081dc..9bd9a31450c 100644 --- a/arch/alpha/kernel/sys_takara.c +++ b/arch/alpha/kernel/sys_takara.c @@ -112,10 +112,10 @@ takara_device_interrupt(unsigned long vector) * despatch an interrupt if it's set. */ - if (intstatus & 8) handle_irq(16+3, get_irq_regs()); - if (intstatus & 4) handle_irq(16+2, get_irq_regs()); - if (intstatus & 2) handle_irq(16+1, get_irq_regs()); - if (intstatus & 1) handle_irq(16+0, get_irq_regs()); + if (intstatus & 8) handle_irq(16+3); + if (intstatus & 4) handle_irq(16+2); + if (intstatus & 2) handle_irq(16+1); + if (intstatus & 1) handle_irq(16+0); } else { isa_device_interrupt (vector); } @@ -125,7 +125,7 @@ static void takara_srm_device_interrupt(unsigned long vector) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } static void __init diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c index 1473aa0e698..e8e8ec9c0f4 100644 --- a/arch/alpha/kernel/sys_titan.c +++ b/arch/alpha/kernel/sys_titan.c @@ -178,7 +178,7 @@ titan_srm_device_interrupt(unsigned long vector) int irq; irq = (vector - 0x800) >> 4; - handle_irq(irq, get_irq_regs()); + handle_irq(irq); } diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c index ddf5edd0cec..42c3eede4d0 100644 --- a/arch/alpha/kernel/sys_wildfire.c +++ b/arch/alpha/kernel/sys_wildfire.c @@ -246,7 +246,7 @@ wildfire_device_interrupt(unsigned long vector) * bits 5-0: irq in PCA */ - handle_irq(irq, get_irq_regs()); + handle_irq(irq); return; } -- GitLab From 4fa1970a23bf8fc68e86b65a87c32556e20a6be6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:44:38 +0100 Subject: [PATCH 0782/1619] [PATCH] alpha pt_regs cleanups: machine_check() do set_irq_regs() in caller, kill pt_regs argument. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/core_apecs.c | 5 ++--- arch/alpha/kernel/core_cia.c | 5 ++--- arch/alpha/kernel/core_lca.c | 6 +++--- arch/alpha/kernel/core_mcpcia.c | 5 ++--- arch/alpha/kernel/core_polaris.c | 5 ++--- arch/alpha/kernel/core_t2.c | 5 ++--- arch/alpha/kernel/core_tsunami.c | 5 ++--- arch/alpha/kernel/core_wildfire.c | 5 ++--- arch/alpha/kernel/err_ev6.c | 5 +++-- arch/alpha/kernel/err_ev7.c | 2 +- arch/alpha/kernel/err_impl.h | 10 +++++----- arch/alpha/kernel/err_marvel.c | 4 ++-- arch/alpha/kernel/err_titan.c | 14 +++++++------- arch/alpha/kernel/irq_alpha.c | 11 ++++++----- arch/alpha/kernel/proto.h | 23 +++++++++++------------ arch/alpha/kernel/sys_jensen.c | 2 +- arch/alpha/kernel/sys_mikasa.c | 5 ++--- arch/alpha/kernel/sys_nautilus.c | 7 +++---- arch/alpha/kernel/sys_noritake.c | 5 ++--- include/asm-alpha/machvec.h | 3 +-- 20 files changed, 61 insertions(+), 71 deletions(-) diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c index a27ba12ba35..ca46b2c2445 100644 --- a/arch/alpha/kernel/core_apecs.c +++ b/arch/alpha/kernel/core_apecs.c @@ -387,8 +387,7 @@ apecs_pci_clr_err(void) } void -apecs_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +apecs_machine_check(unsigned long vector, unsigned long la_ptr) { struct el_common *mchk_header; struct el_apecs_procdata *mchk_procdata; @@ -412,7 +411,7 @@ apecs_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(0x7); /* reset machine check pending flag */ mb(); - process_mcheck_info(vector, la_ptr, regs, "APECS", + process_mcheck_info(vector, la_ptr, "APECS", (mcheck_expected(0) && (mchk_sysdata->epic_dcsr & 0x0c00UL))); } diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index fd563064363..1d6ee6c985f 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -1192,8 +1192,7 @@ cia_decode_mchk(unsigned long la_ptr) } void -cia_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +cia_machine_check(unsigned long vector, unsigned long la_ptr) { int expected; @@ -1208,5 +1207,5 @@ cia_machine_check(unsigned long vector, unsigned long la_ptr, expected = mcheck_expected(0); if (!expected && vector == 0x660) expected = cia_decode_mchk(la_ptr); - process_mcheck_info(vector, la_ptr, regs, "CIA", expected); + process_mcheck_info(vector, la_ptr, "CIA", expected); } diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c index 6a5a9145c67..4843f6ec9f3 100644 --- a/arch/alpha/kernel/core_lca.c +++ b/arch/alpha/kernel/core_lca.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "proto.h" @@ -386,8 +387,7 @@ ioc_error(__u32 stat0, __u32 stat1) } void -lca_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs *regs) +lca_machine_check(unsigned long vector, unsigned long la_ptr) { const char * reason; union el_lca el; @@ -397,7 +397,7 @@ lca_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(rdmces()); /* reset machine check pending flag */ printk(KERN_CRIT "LCA machine check: vector=%#lx pc=%#lx code=%#x\n", - vector, regs->pc, (unsigned int) el.c->code); + vector, get_irq_regs()->pc, (unsigned int) el.c->code); /* * The first quadword after the common header always seems to diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index 28849c89415..8d019071190 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -572,8 +572,7 @@ mcpcia_print_system_area(unsigned long la_ptr) } void -mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +mcpcia_machine_check(unsigned long vector, unsigned long la_ptr) { struct el_common *mchk_header; struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout; @@ -610,7 +609,7 @@ mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(0x7); mb(); - process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0); + process_mcheck_info(vector, la_ptr, "MCPCIA", expected != 0); if (!expected && vector != 0x620 && vector != 0x630) { mcpcia_print_uncorrectable(mchk_logout); mcpcia_print_system_area(la_ptr); diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c index 277674a500f..c5a271d37ab 100644 --- a/arch/alpha/kernel/core_polaris.c +++ b/arch/alpha/kernel/core_polaris.c @@ -187,8 +187,7 @@ polaris_pci_clr_err(void) } void -polaris_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +polaris_machine_check(unsigned long vector, unsigned long la_ptr) { /* Clear the error before any reporting. */ mb(); @@ -198,6 +197,6 @@ polaris_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(0x7); mb(); - process_mcheck_info(vector, la_ptr, regs, "POLARIS", + process_mcheck_info(vector, la_ptr, "POLARIS", mcheck_expected(0)); } diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c index ecce09e3626..f5ca5255eb0 100644 --- a/arch/alpha/kernel/core_t2.c +++ b/arch/alpha/kernel/core_t2.c @@ -551,8 +551,7 @@ t2_clear_errors(int cpu) * Hence all the taken/expected/any_expected/last_taken stuff... */ void -t2_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +t2_machine_check(unsigned long vector, unsigned long la_ptr) { int cpu = smp_processor_id(); #ifdef CONFIG_VERBOSE_MCHECK @@ -618,5 +617,5 @@ t2_machine_check(unsigned long vector, unsigned long la_ptr, } #endif - process_mcheck_info(vector, la_ptr, regs, "T2", mcheck_expected(cpu)); + process_mcheck_info(vector, la_ptr, "T2", mcheck_expected(cpu)); } diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index 8aa305bd6a2..ce623c6e55e 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -443,8 +443,7 @@ tsunami_pci_clr_err(void) } void -tsunami_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +tsunami_machine_check(unsigned long vector, unsigned long la_ptr) { /* Clear error before any reporting. */ mb(); @@ -454,6 +453,6 @@ tsunami_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(0x7); mb(); - process_mcheck_info(vector, la_ptr, regs, "TSUNAMI", + process_mcheck_info(vector, la_ptr, "TSUNAMI", mcheck_expected(smp_processor_id())); } diff --git a/arch/alpha/kernel/core_wildfire.c b/arch/alpha/kernel/core_wildfire.c index 2b767a1bad9..7e072443d7f 100644 --- a/arch/alpha/kernel/core_wildfire.c +++ b/arch/alpha/kernel/core_wildfire.c @@ -322,8 +322,7 @@ wildfire_init_arch(void) } void -wildfire_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +wildfire_machine_check(unsigned long vector, unsigned long la_ptr) { mb(); mb(); /* magic */ @@ -332,7 +331,7 @@ wildfire_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(0x7); mb(); - process_mcheck_info(vector, la_ptr, regs, "WILDFIRE", + process_mcheck_info(vector, la_ptr, "WILDFIRE", mcheck_expected(smp_processor_id())); } diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c index 64f59f2fcf5..69b5f4ea735 100644 --- a/arch/alpha/kernel/err_ev6.c +++ b/arch/alpha/kernel/err_ev6.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -229,7 +230,7 @@ ev6_process_logout_frame(struct el_common *mchk_header, int print) } void -ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +ev6_machine_check(u64 vector, u64 la_ptr) { struct el_common *mchk_header = (struct el_common *)la_ptr; @@ -260,7 +261,7 @@ ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) (unsigned int)vector, (int)smp_processor_id()); ev6_process_logout_frame(mchk_header, 1); - dik_show_regs(regs, NULL); + dik_show_regs(get_irq_regs(), NULL); err_print_prefix = saved_err_prefix; } diff --git a/arch/alpha/kernel/err_ev7.c b/arch/alpha/kernel/err_ev7.c index fed6b3d1b80..95463ab1cf3 100644 --- a/arch/alpha/kernel/err_ev7.c +++ b/arch/alpha/kernel/err_ev7.c @@ -118,7 +118,7 @@ ev7_collect_logout_frame_subpackets(struct el_subpacket *el_ptr, } void -ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +ev7_machine_check(u64 vector, u64 la_ptr) { struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr; char *saved_err_prefix = err_print_prefix; diff --git a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h index 64e9b73809f..3c12258158e 100644 --- a/arch/alpha/kernel/err_impl.h +++ b/arch/alpha/kernel/err_impl.h @@ -60,26 +60,26 @@ extern struct ev7_lf_subpackets * ev7_collect_logout_frame_subpackets(struct el_subpacket *, struct ev7_lf_subpackets *); extern void ev7_register_error_handlers(void); -extern void ev7_machine_check(u64, u64, struct pt_regs *); +extern void ev7_machine_check(u64, u64); /* * err_ev6.c */ extern void ev6_register_error_handlers(void); extern int ev6_process_logout_frame(struct el_common *, int); -extern void ev6_machine_check(u64, u64, struct pt_regs *); +extern void ev6_machine_check(u64, u64); /* * err_marvel.c */ -extern void marvel_machine_check(u64, u64, struct pt_regs *); +extern void marvel_machine_check(u64, u64); extern void marvel_register_error_handlers(void); /* * err_titan.c */ extern int titan_process_logout_frame(struct el_common *, int); -extern void titan_machine_check(u64, u64, struct pt_regs *); +extern void titan_machine_check(u64, u64); extern void titan_register_error_handlers(void); extern int privateer_process_logout_frame(struct el_common *, int); -extern void privateer_machine_check(u64, u64, struct pt_regs *); +extern void privateer_machine_check(u64, u64); diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c index 70b38b1d2af..f2956ac8dcc 100644 --- a/arch/alpha/kernel/err_marvel.c +++ b/arch/alpha/kernel/err_marvel.c @@ -1042,7 +1042,7 @@ marvel_process_logout_frame(struct ev7_lf_subpackets *lf_subpackets, int print) } void -marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +marvel_machine_check(u64 vector, u64 la_ptr) { struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr; int (*process_frame)(struct ev7_lf_subpackets *, int) = NULL; @@ -1077,7 +1077,7 @@ marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) default: /* Don't know it - pass it up. */ - ev7_machine_check(vector, la_ptr, regs); + ev7_machine_check(vector, la_ptr); return; } diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c index 7e6720d45f0..2e6e6293332 100644 --- a/arch/alpha/kernel/err_titan.c +++ b/arch/alpha/kernel/err_titan.c @@ -379,7 +379,7 @@ titan_process_logout_frame(struct el_common *mchk_header, int print) } void -titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +titan_machine_check(u64 vector, u64 la_ptr) { struct el_common *mchk_header = (struct el_common *)la_ptr; struct el_TITAN_sysdata_mcheck *tmchk = @@ -408,7 +408,7 @@ titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) * Only handle system errors here */ if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) { - ev6_machine_check(vector, la_ptr, regs); + ev6_machine_check(vector, la_ptr); return; } @@ -442,7 +442,7 @@ titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) #ifdef CONFIG_VERBOSE_MCHECK titan_process_logout_frame(mchk_header, alpha_verbose_mcheck); if (alpha_verbose_mcheck) - dik_show_regs(regs, NULL); + dik_show_regs(get_irq_regs(), NULL); #endif /* CONFIG_VERBOSE_MCHECK */ err_print_prefix = saved_err_prefix; @@ -452,7 +452,7 @@ titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) * machine checks to interrupts */ irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK; - titan_dispatch_irqs(irqmask, regs); + titan_dispatch_irqs(irqmask, get_irq_regs()); } @@ -701,7 +701,7 @@ privateer_process_logout_frame(struct el_common *mchk_header, int print) } void -privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +privateer_machine_check(u64 vector, u64 la_ptr) { struct el_common *mchk_header = (struct el_common *)la_ptr; struct el_TITAN_sysdata_mcheck *tmchk = @@ -723,7 +723,7 @@ privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) * Only handle system events here. */ if (vector != SCB_Q_SYSEVENT) - return titan_machine_check(vector, la_ptr, regs); + return titan_machine_check(vector, la_ptr); /* * Report the event - System Events should be reported even if no @@ -746,7 +746,7 @@ privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) /* * Dispatch the interrupt(s). */ - titan_dispatch_irqs(irqmask, regs); + titan_dispatch_irqs(irqmask, get_irq_regs()); /* * Release the logout frame. diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 51d66b7f99e..6dd126b8be8 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -72,7 +72,9 @@ do_entInt(unsigned long type, unsigned long vector, set_irq_regs(old_regs); return; case 2: - alpha_mv.machine_check(vector, la_ptr, regs); + old_regs = set_irq_regs(regs); + alpha_mv.machine_check(vector, la_ptr); + set_irq_regs(old_regs); return; case 3: old_regs = set_irq_regs(regs); @@ -125,8 +127,7 @@ struct mcheck_info __mcheck_info; void process_mcheck_info(unsigned long vector, unsigned long la_ptr, - struct pt_regs *regs, const char *machine, - int expected) + const char *machine, int expected) { struct el_common *mchk_header; const char *reason; @@ -153,7 +154,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr, mchk_header = (struct el_common *)la_ptr; printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n", - machine, vector, regs->pc, mchk_header->code); + machine, vector, get_irq_regs()->pc, mchk_header->code); switch (mchk_header->code) { /* Machine check reasons. Defined according to PALcode sources. */ @@ -194,7 +195,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr, printk(KERN_CRIT "machine check type: %s%s\n", reason, mchk_header->retry ? " (retryable)" : ""); - dik_show_regs(regs, NULL); + dik_show_regs(get_irq_regs(), NULL); #ifdef CONFIG_VERBOSE_MCHECK if (alpha_verbose_mcheck > 1) { diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 408bda25b0b..3fff8873419 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -20,7 +20,7 @@ struct pci_controller; extern struct pci_ops apecs_pci_ops; extern void apecs_init_arch(void); extern void apecs_pci_clr_err(void); -extern void apecs_machine_check(u64, u64, struct pt_regs *); +extern void apecs_machine_check(u64, u64); extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_cia.c */ @@ -29,7 +29,7 @@ extern void cia_init_pci(void); extern void cia_init_arch(void); extern void pyxis_init_arch(void); extern void cia_kill_arch(int); -extern void cia_machine_check(u64, u64, struct pt_regs *); +extern void cia_machine_check(u64, u64); extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_irongate.c */ @@ -42,14 +42,14 @@ extern void irongate_machine_check(u64, u64, struct pt_regs *); /* core_lca.c */ extern struct pci_ops lca_pci_ops; extern void lca_init_arch(void); -extern void lca_machine_check(u64, u64, struct pt_regs *); +extern void lca_machine_check(u64, u64); extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_marvel.c */ extern struct pci_ops marvel_pci_ops; extern void marvel_init_arch(void); extern void marvel_kill_arch(int); -extern void marvel_machine_check(u64, u64, struct pt_regs *); +extern void marvel_machine_check(u64, u64); extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); extern int marvel_pa_to_nid(unsigned long); extern int marvel_cpuid_to_nid(int); @@ -64,7 +64,7 @@ void io7_clear_errors(struct io7 *io7); extern struct pci_ops mcpcia_pci_ops; extern void mcpcia_init_arch(void); extern void mcpcia_init_hoses(void); -extern void mcpcia_machine_check(u64, u64, struct pt_regs *); +extern void mcpcia_machine_check(u64, u64); extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_polaris.c */ @@ -72,21 +72,21 @@ extern struct pci_ops polaris_pci_ops; extern int polaris_read_config_dword(struct pci_dev *, int, u32 *); extern int polaris_write_config_dword(struct pci_dev *, int, u32); extern void polaris_init_arch(void); -extern void polaris_machine_check(u64, u64, struct pt_regs *); +extern void polaris_machine_check(u64, u64); #define polaris_pci_tbi ((void *)0) /* core_t2.c */ extern struct pci_ops t2_pci_ops; extern void t2_init_arch(void); extern void t2_kill_arch(int); -extern void t2_machine_check(u64, u64, struct pt_regs *); +extern void t2_machine_check(u64, u64); extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_titan.c */ extern struct pci_ops titan_pci_ops; extern void titan_init_arch(void); extern void titan_kill_arch(int); -extern void titan_machine_check(u64, u64, struct pt_regs *); +extern void titan_machine_check(u64, u64); extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); extern struct _alpha_agp_info *titan_agp_info(void); @@ -94,14 +94,14 @@ extern struct _alpha_agp_info *titan_agp_info(void); extern struct pci_ops tsunami_pci_ops; extern void tsunami_init_arch(void); extern void tsunami_kill_arch(int); -extern void tsunami_machine_check(u64, u64, struct pt_regs *); +extern void tsunami_machine_check(u64, u64); extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_wildfire.c */ extern struct pci_ops wildfire_pci_ops; extern void wildfire_init_arch(void); extern void wildfire_kill_arch(int); -extern void wildfire_machine_check(u64, u64, struct pt_regs *); +extern void wildfire_machine_check(u64, u64); extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); extern int wildfire_pa_to_nid(unsigned long); extern int wildfire_cpuid_to_nid(int); @@ -214,5 +214,4 @@ extern struct mcheck_info #endif extern void process_mcheck_info(unsigned long vector, unsigned long la_ptr, - struct pt_regs *regs, const char *machine, - int expected); + const char *machine, int expected); diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index a7b89022938..2c3de97de46 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c @@ -244,7 +244,7 @@ jensen_init_arch(void) } static void -jensen_machine_check (u64 vector, u64 la, struct pt_regs *regs) +jensen_machine_check (u64 vector, u64 la) { printk(KERN_CRIT "Machine check\n"); } diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index ba98048d61a..8d3e9429c5e 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -182,8 +182,7 @@ mikasa_map_irq(struct pci_dev *dev, u8 slot, u8 pin) #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) static void -mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr) { #define MCHK_NO_DEVSEL 0x205U #define MCHK_NO_TABT 0x204U @@ -202,7 +201,7 @@ mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr, mb(); code = mchk_header->code; - process_mcheck_info(vector, la_ptr, regs, "MIKASA APECS", + process_mcheck_info(vector, la_ptr, "MIKASA APECS", (mcheck_expected(0) && (code == MCHK_NO_DEVSEL || code == MCHK_NO_TABT))); diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c index c0d696efec5..93744bab73f 100644 --- a/arch/alpha/kernel/sys_nautilus.c +++ b/arch/alpha/kernel/sys_nautilus.c @@ -124,8 +124,7 @@ naut_sys_machine_check(unsigned long vector, unsigned long la_ptr, in the system. They are analysed separately but all starts here. */ void -nautilus_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs *regs) +nautilus_machine_check(unsigned long vector, unsigned long la_ptr) { char *mchk_class; @@ -165,7 +164,7 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr, else if (vector == SCB_Q_SYSMCHK) mchk_class = "Fatal"; else { - ev6_machine_check(vector, la_ptr, regs); + ev6_machine_check(vector, la_ptr); return; } @@ -173,7 +172,7 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr, "[%s System Machine Check (NMI)]\n", vector, mchk_class); - naut_sys_machine_check(vector, la_ptr, regs); + naut_sys_machine_check(vector, la_ptr, get_irq_regs()); /* Tell the PALcode to clear the machine check */ draina(); diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c index 679836205f0..de6ba3432e8 100644 --- a/arch/alpha/kernel/sys_noritake.c +++ b/arch/alpha/kernel/sys_noritake.c @@ -264,8 +264,7 @@ noritake_swizzle(struct pci_dev *dev, u8 *pinp) #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) static void -noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr) { #define MCHK_NO_DEVSEL 0x205U #define MCHK_NO_TABT 0x204U @@ -284,7 +283,7 @@ noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr, mb(); code = mchk_header->code; - process_mcheck_info(vector, la_ptr, regs, "NORITAKE APECS", + process_mcheck_info(vector, la_ptr, "NORITAKE APECS", (mcheck_expected(0) && (code == MCHK_NO_DEVSEL || code == MCHK_NO_TABT))); diff --git a/include/asm-alpha/machvec.h b/include/asm-alpha/machvec.h index 7ae744240f8..a86c083cdf7 100644 --- a/include/asm-alpha/machvec.h +++ b/include/asm-alpha/machvec.h @@ -15,7 +15,6 @@ struct task_struct; struct mm_struct; -struct pt_regs; struct vm_area_struct; struct linux_hose_info; struct pci_dev; @@ -80,7 +79,7 @@ struct alpha_machine_vector void (*update_irq_hw)(unsigned long, unsigned long, int); void (*ack_irq)(unsigned long); void (*device_interrupt)(unsigned long vector); - void (*machine_check)(u64 vector, u64 la, struct pt_regs *regs); + void (*machine_check)(u64 vector, u64 la); void (*smp_callin)(void); void (*init_arch)(void); -- GitLab From 2f116cbf369ec3148cef9821f6c7f2b8fb78a071 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:45:28 +0100 Subject: [PATCH 0783/1619] [PATCH] alpha pt_regs cleanups: collapse set_irq_regs() in titan_dispatch_irqs() titan_dispatch_irqs() always gets get_irq_regs() as argument; kill the argument and collapse set_irq_regs() in body. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/err_titan.c | 4 ++-- arch/alpha/kernel/proto.h | 2 +- arch/alpha/kernel/sys_titan.c | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c index 2e6e6293332..febe71c6869 100644 --- a/arch/alpha/kernel/err_titan.c +++ b/arch/alpha/kernel/err_titan.c @@ -452,7 +452,7 @@ titan_machine_check(u64 vector, u64 la_ptr) * machine checks to interrupts */ irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK; - titan_dispatch_irqs(irqmask, get_irq_regs()); + titan_dispatch_irqs(irqmask); } @@ -746,7 +746,7 @@ privateer_machine_check(u64 vector, u64 la_ptr) /* * Dispatch the interrupt(s). */ - titan_dispatch_irqs(irqmask, get_irq_regs()); + titan_dispatch_irqs(irqmask); /* * Release the logout frame. diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 3fff8873419..daccd4b6d28 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -177,7 +177,7 @@ extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15); extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *); /* sys_titan.c */ -extern void titan_dispatch_irqs(u64, struct pt_regs *); +extern void titan_dispatch_irqs(u64); /* ../mm/init.c */ extern void switch_to_system_map(void); diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c index e8e8ec9c0f4..161d6915dc4 100644 --- a/arch/alpha/kernel/sys_titan.c +++ b/arch/alpha/kernel/sys_titan.c @@ -243,9 +243,8 @@ titan_legacy_init_irq(void) } void -titan_dispatch_irqs(u64 mask, struct pt_regs *regs) +titan_dispatch_irqs(u64 mask) { - struct pt_regs *old_regs; unsigned long vector; /* @@ -253,7 +252,6 @@ titan_dispatch_irqs(u64 mask, struct pt_regs *regs) */ mask &= titan_cpu_irq_affinity[smp_processor_id()]; - old_regs = set_irq_regs(regs); /* * Dispatch all requested interrupts */ @@ -267,7 +265,6 @@ titan_dispatch_irqs(u64 mask, struct pt_regs *regs) /* dispatch it */ alpha_mv.device_interrupt(vector); } - set_irq_regs(old_regs); } -- GitLab From 5dcded1b0b4f1537bb6dff453fb805517756c94b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 14:59:19 +0100 Subject: [PATCH 0784/1619] [PATCH] missed ia64 pt_regs fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ia64/hp/sim/simeth.c | 4 ++-- arch/ia64/hp/sim/simserial.c | 10 +++++----- arch/ia64/sn/kernel/xpc_main.c | 7 ++----- include/asm-ia64/sn/xpc.h | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index e1a1b11473e..be769ef326a 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -54,7 +54,7 @@ static int simeth_close(struct net_device *dev); static int simeth_tx(struct sk_buff *skb, struct net_device *dev); static int simeth_rx(struct net_device *dev); static struct net_device_stats *simeth_get_stats(struct net_device *dev); -static irqreturn_t simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t simeth_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr); @@ -497,7 +497,7 @@ simeth_rx(struct net_device *dev) * Interrupt handler (Yes, we can do it too !!!) */ static irqreturn_t -simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs) +simeth_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 246eb3d3757..77819acaea9 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -130,7 +130,7 @@ static void rs_start(struct tty_struct *tty) #endif } -static void receive_chars(struct tty_struct *tty, struct pt_regs *regs) +static void receive_chars(struct tty_struct *tty) { unsigned char ch; static unsigned char seen_esc = 0; @@ -152,7 +152,7 @@ static void receive_chars(struct tty_struct *tty, struct pt_regs *regs) ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); while (!ch); - handle_sysrq(ch, regs, NULL); + handle_sysrq(ch, NULL); } #endif seen_esc = 0; @@ -170,7 +170,7 @@ static void receive_chars(struct tty_struct *tty, struct pt_regs *regs) /* * This is the serial driver's interrupt routine for a single port */ -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 async_struct * info; @@ -187,7 +187,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * r * pretty simple in our case, because we only get interrupts * on inbound traffic */ - receive_chars(info->tty, regs); + receive_chars(info->tty); return IRQ_HANDLED; } @@ -714,7 +714,7 @@ startup(struct async_struct *info) { unsigned long flags; int retval=0; - irqreturn_t (*handler)(int, void *, struct pt_regs *); + irqreturn_t (*handler)(int, void *); struct serial_state *state= info->state; unsigned long page; diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index 4d026f9dd98..fa96dfc0e1a 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c @@ -222,7 +222,7 @@ xpc_timeout_partition_disengage_request(unsigned long data) * Notify the heartbeat check thread that an IRQ has been received. */ static irqreturn_t -xpc_act_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs) +xpc_act_IRQ_handler(int irq, void *dev_id) { atomic_inc(&xpc_act_IRQ_rcvd); wake_up_interruptible(&xpc_act_IRQ_wq); @@ -607,12 +607,9 @@ xpc_activate_partition(struct xpc_partition *part) * irq - Interrupt ReQuest number. NOT USED. * * dev_id - partid of IPI's potential sender. - * - * regs - processor's context before the processor entered - * interrupt code. NOT USED. */ irqreturn_t -xpc_notify_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs) +xpc_notify_IRQ_handler(int irq, void *dev_id) { partid_t partid = (partid_t) (u64) dev_id; struct xpc_partition *part = &xpc_partitions[partid]; diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h index 35e1386f37a..1d45e1518fb 100644 --- a/include/asm-ia64/sn/xpc.h +++ b/include/asm-ia64/sn/xpc.h @@ -669,7 +669,7 @@ extern struct device *xpc_part; extern struct device *xpc_chan; extern int xpc_disengage_request_timelimit; extern int xpc_disengage_request_timedout; -extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *); +extern irqreturn_t xpc_notify_IRQ_handler(int, void *); extern void xpc_dropped_IPI_check(struct xpc_partition *); extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); -- GitLab From 28431146993e0ab3a2a592af8541543fe0cc2c8e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:00:12 +0100 Subject: [PATCH 0785/1619] [PATCH] misc arm pt_regs fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/net/dm9000.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 2 +- include/asm-arm/hw_irq.h | 2 +- sound/oss/vidc.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 3641f3b4a2c..615d2b14efa 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -346,7 +346,7 @@ static void dm9000_timeout(struct net_device *dev) static void dm9000_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - dm9000_interrupt(dev->irq,dev,NULL); + dm9000_interrupt(dev->irq,dev); enable_irq(dev->irq); } #endif diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4d2946e540c..f1f32d7be5f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1551,7 +1551,7 @@ return_urb: ep->already_seen = ep->setup_stage = 0; spin_unlock (&dum->lock); - usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL); + usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); goto restart; diff --git a/include/asm-arm/hw_irq.h b/include/asm-arm/hw_irq.h index ea856971989..98d594a973d 100644 --- a/include/asm-arm/hw_irq.h +++ b/include/asm-arm/hw_irq.h @@ -12,7 +12,7 @@ if (!(action->flags & IRQF_TIMER) && system_timer->dyn_tick) { \ write_seqlock(&xtime_lock); \ if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) \ - system_timer->dyn_tick->handler(irq, 0, regs); \ + system_timer->dyn_tick->handler(irq, NULL); \ write_sequnlock(&xtime_lock); \ } #endif diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c index 8932d89408e..bb4a0969f46 100644 --- a/sound/oss/vidc.c +++ b/sound/oss/vidc.c @@ -372,7 +372,7 @@ static void vidc_audio_trigger(int dev, int enable_bits) adev->flags |= DMA_ACTIVE; dma_interrupt = vidc_audio_dma_interrupt; - vidc_sound_dma_irq(0, NULL, NULL); + vidc_sound_dma_irq(0, NULL); iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR); local_irq_restore(flags); -- GitLab From 9da3b1ad7b074effd56729f9fc01cc5abf6503cc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:00:44 +0100 Subject: [PATCH 0786/1619] [PATCH] misc ppc pt_regs fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/macintosh/macio-adb.c | 2 +- drivers/net/mv643xx_eth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 57ccc19cbdb..797cef72258 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -270,6 +270,6 @@ static void macio_adb_poll(void) local_irq_save(flags); if (in_8(&adb->intr.r) != 0) - macio_adb_interrupt(0, NULL, NULL); + macio_adb_interrupt(0, NULL); local_irq_restore(flags); } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index d26a819a973..2ffa3a59e70 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1251,7 +1251,7 @@ static void mv643xx_netpoll(struct net_device *netdev) /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); - mv643xx_eth_int_handler(netdev->irq, netdev, NULL); + mv643xx_eth_int_handler(netdev->irq, netdev); mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); } -- GitLab From 97432886617825d412bcedadf5e5b308f931caad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:01:14 +0100 Subject: [PATCH 0787/1619] [PATCH] missing include in pdaudiocf_irq Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c index 732263e4a43..5bd69206ba6 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c @@ -22,6 +22,7 @@ #include #include "pdaudiocf.h" #include +#include /* * -- GitLab From a8f47c45aee6efa5ef7ec209b90681b091bd3d2c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:04:15 +0100 Subject: [PATCH 0788/1619] [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(+) diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 203dd5e11ec..dfb8052eee5 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 { -- GitLab From 9288d1a3c7ed0abaa7976844e5d42bbd4fa0eae3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:05:14 +0100 Subject: [PATCH 0789/1619] [PATCH] missing forward declaration of pt_regs (asm-m68k/signal.h) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/asm-m68k/signal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h index de1ba6ead3b..3db8a81942f 100644 --- a/include/asm-m68k/signal.h +++ b/include/asm-m68k/signal.h @@ -198,6 +198,7 @@ static inline int sigfindinword(unsigned long word) return word ^ 31; } +struct pt_regs; extern void ptrace_signal_deliver(struct pt_regs *regs, void *cookie); #endif /* __KERNEL__ */ -- GitLab From cb1055fb1b79775d398038ad8dcd2c7581f141d8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:08:45 +0100 Subject: [PATCH 0790/1619] [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(+) diff --git a/include/linux/io.h b/include/linux/io.h index aa3f5af670b..2ad96c3f0e4 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 -- GitLab From 0bae89ec8b1519dae67036637942f5b5bbaa9424 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Oct 2006 14:33:24 -0400 Subject: [PATCH 0791/1619] [PATCH] NFS: Fix typo in nfs_get_client() Commit ca4aa09635516258f158a7bc1594a794e4c34864 fixed waiting for the structure to get initialised, but it is also possible to break out of the loop while still in TASK_INTERRUPTIBLE. Replace the whole thing by wait_event_interruptible, which is much more readable, and doesn't suffer from these problems. Signed-off-by: Trond Myklebust Signed-off-by: Linus Torvalds --- fs/nfs/client.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d2533e21425..013cdbc3b00 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -322,25 +322,11 @@ found_client: if (new) nfs_free_client(new); - if (clp->cl_cons_state == NFS_CS_INITING) { - DECLARE_WAITQUEUE(myself, current); - - add_wait_queue(&nfs_client_active_wq, &myself); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current) || - clp->cl_cons_state != NFS_CS_INITING) - break; - schedule(); - } - - remove_wait_queue(&nfs_client_active_wq, &myself); - - if (signal_pending(current)) { - nfs_put_client(clp); - return ERR_PTR(-ERESTARTSYS); - } + error = wait_event_interruptible(&nfs_client_active_wq, + clp->cl_cons_state != NFS_CS_INITING); + if (error < 0) { + nfs_put_client(clp); + return ERR_PTR(-ERESTARTSYS); } if (clp->cl_cons_state < NFS_CS_READY) { -- GitLab From e24bb60e11e3fe9858b71874a4ac59333adbc4fc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 8 Oct 2006 15:38:22 -0700 Subject: [PATCH 0792/1619] Revert "[POWERPC] Don't get PCI IRQ from OF for devices with no IRQ" This reverts commit 41550c5128150175197257b6ceab2cd50dea7b51. Quoth Ben Herrenschmidt: "Please revert this one for now. It seems to break G5s :( Looks like PCI cells inside Apple IO ASICs don't have a PCI_INTERRUPT_LINE set. I need to figure out a better fix." Signed-off-by: Linus Torvalds --- arch/powerpc/kernel/prom_parse.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 17fcb4842fe..603dff3ad62 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -914,17 +914,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) u8 pin; int rc; - /* We need to first check if the PCI device has a PCI interrupt at all - * since we have cases where the device-node might expose non-PCI - * interrupts, but the device has no PCI interrupt to it - */ - rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); - if (rc != 0) - return rc; - /* No pin, exit */ - if (pin == 0) - return -ENODEV; - /* Check if we have a device node, if yes, fallback to standard OF * parsing */ @@ -936,6 +925,12 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) * interrupt spec. we assume #interrupt-cells is 1, which is standard * for PCI. If you do different, then don't use that routine. */ + rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); + if (rc != 0) + return rc; + /* No pin, exit */ + if (pin == 0) + return -ENODEV; /* Now we walk up the PCI tree */ lspec = pin; -- GitLab From b104189c203a47219e51ab179e50fd0c73ccea3b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 Oct 2006 00:15:27 +0100 Subject: [PATCH 0793/1619] handle_sysrq lost its pt_regs * argument Signed-off-by: Ralf Baechle --- arch/ppc/4xx_io/serial_sicc.c | 2 +- arch/um/drivers/mconsole_kern.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c index 87fe9a89dba..080a20531f8 100644 --- a/arch/ppc/4xx_io/serial_sicc.c +++ b/arch/ppc/4xx_io/serial_sicc.c @@ -441,7 +441,7 @@ siccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs) #ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL); + handle_sysrq(ch, NULL); info->sysrq = 0; goto ignore_char; } diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index a67dcbd78de..8568abff66b 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -675,7 +675,7 @@ static void sysrq_proc(void *arg) { char *op = arg; - handle_sysrq(*op, ¤t->thread.regs, NULL); + handle_sysrq(*op, NULL); } void mconsole_sysrq(struct mc_request *req) -- GitLab From d62801e961e148313910ec430e230e488fadc196 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 17:38:18 +0100 Subject: [PATCH 0794/1619] [MIPS] DEC: pt_regs fixes for dec_intr_halt. Signed-off-by: Ralf Baechle --- arch/mips/dec/reset.c | 2 +- arch/mips/dec/setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c index f78c6da4792..8c95ea19efb 100644 --- a/arch/mips/dec/reset.c +++ b/arch/mips/dec/reset.c @@ -35,7 +35,7 @@ void ATTRIB_NORET dec_machine_power_off(void) back_to_prom(); } -irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t dec_intr_halt(int irq, void *dev_id) { dec_machine_halt(); } diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index d43241c2f54..6b7481e97be 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -46,7 +46,7 @@ extern void dec_machine_restart(char *command); extern void dec_machine_halt(void); extern void dec_machine_power_off(void); -extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t dec_intr_halt(int irq, void *dev_id); unsigned long dec_kn_slot_base, dec_kn_slot_size; -- GitLab From 2cf69e765a99baacf0121f3312ec84ff1031961d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 19:19:11 +0100 Subject: [PATCH 0795/1619] [MIPS] Jazz: Fix I/O port resources. struct resource members were shuffeled a while ago. Signed-off-by: Ralf Baechle --- arch/mips/jazz/setup.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 487a9ea1ef0..3a7869fbaf3 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -45,10 +45,27 @@ void __init plat_time_init(struct irqaction *irq) } static struct resource jazz_io_resources[] = { - { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, - { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, - { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, - { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, + { + .start = 0x00, + .end = 0x1f, + .name = "dma1", + .flags = IORESOURCE_BUSY + }, { + .start = 0x40, + .end = 0x5f, + .name = "timer", + .end = IORESOURCE_BUSY + }, { + .start = 0x80, + .end = 0x8f, + .name = "dma page reg", + .flags = IORESOURCE_BUSY + }, { + .start = 0xc0, + .end = 0xdf, + .name = "dma2", + .flags = IORESOURCE_BUSY + } }; void __init plat_mem_setup(void) -- GitLab From 3bdcdd681b64fa92934039ff0d217414720a4b1e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 19:28:44 +0100 Subject: [PATCH 0796/1619] [MIPS] Jazz: Remove warning. After 7 years probably somebody test this ;) Signed-off-by: Ralf Baechle --- arch/mips/jazz/setup.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 3a7869fbaf3..50cecfca7f8 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -98,8 +98,6 @@ void __init plat_mem_setup(void) _machine_halt = jazz_machine_halt; pm_power_off = jazz_machine_power_off; -#warning "Somebody should check if screen_info is ok for Jazz." - screen_info = (struct screen_info) { 0, 0, /* orig-x, orig-y */ 0, /* unused */ -- GitLab From 06e80113c765119e73394a5878c137f2d09a4dcd Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 19:35:00 +0100 Subject: [PATCH 0797/1619] [MIPS] Jazz: build fix - include Signed-off-by: Ralf Baechle --- arch/mips/jazz/setup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 50cecfca7f8..a3354c1f3d7 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include -- GitLab From de4f742b96f286ac20c04dd9c53897a05b412843 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 20:50:12 +0100 Subject: [PATCH 0798/1619] [MIPS] Jazz defconfig file. Signed-off-by: Ralf Baechle --- arch/mips/configs/jazz_defconfig | 1404 ++++++++++++++++++++++++++++++ 1 file changed, 1404 insertions(+) create mode 100644 arch/mips/configs/jazz_defconfig diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig new file mode 100644 index 00000000000..382083ebea0 --- /dev/null +++ b/arch/mips/configs/jazz_defconfig @@ -0,0 +1,1404 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-rc1 +# Sun Oct 8 19:03:07 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_MACH_JAZZ=y +# 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_ACER_PICA_61 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +CONFIG_OLIVETTI_M700=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARC=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_I8259=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_ARC32=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 +CONFIG_ARC_MEMORY=y +CONFIG_ARC_PROMLIB=y + +# +# 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=y +# 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 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_R4X00=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_SMP is not set +# CONFIG_MIPS_MT_SMTC 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_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=y +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_100HZ=y +CONFIG_HZ=100 +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# 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_IPC_NS is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_RELAY=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +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_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=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 is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# 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_ISA=y +CONFIG_MMU=y +CONFIG_I8253=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_TRAD_SIGNALS=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# 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=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +# CONFIG_NETFILTER_XT_TARGET_CONNSECMARK is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +CONFIG_IP_NF_CONNTRACK_MARK=y +CONFIG_IP_NF_CONNTRACK_SECMARK=y +CONFIG_IP_NF_CONNTRACK_EVENTS=y +CONFIG_IP_NF_CONNTRACK_NETLINK=m +CONFIG_IP_NF_CT_PROTO_SCTP=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_H323=m +CONFIG_IP_NF_SIP=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_HASHLIMIT=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_H323=m +CONFIG_IP_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m + +# +# 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=m +# CONFIG_VLAN_8021Q is not set +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=m +# 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_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CLK_JIFFIES=y +# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set +# CONFIG_NET_SCH_CLK_CPU is not set + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_CLS_POLICE=y +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_ESTIMATOR=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_YAM 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=y +# 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=m +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_AX88796 is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +CONFIG_PARIDE=m +CONFIG_PARIDE_PARPORT=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# 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=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_FC_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +CONFIG_ISCSI_TCP=m +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_JAZZ_ESP=y + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_CRYPT is not set +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m + +# +# 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 +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MIPS_JAZZ_SONIC=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_DM9000 is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +CONFIG_NET_ISA=y +# CONFIG_E2100 is not set +# CONFIG_EWRK3 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HPLAN is not set +# CONFIG_LP486E is not set +# CONFIG_ETH16I is not set +CONFIG_NE2000=m +# CONFIG_SEEQ8005 is not set +CONFIG_NET_PCI=y +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# 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_PLIP=m +# 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 +CONFIG_INPUT_FF_MEMLESS=m + +# +# 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=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_VSXXXAA 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=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_LIBPS2=y +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=m +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_TIPAR=m + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_RTC=m +# 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=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# + +# +# 1-wire Slaves +# +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2433 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# 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=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# 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=m +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +# CONFIG_ECRYPT_FS is not set +CONFIG_HFS_FS=m +# CONFIG_HFSPLUS_FS is not set +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +CONFIG_CODA_FS_OLD_API=y +CONFIG_AFS_FS=m +CONFIG_RXRPC=m +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Distributed Lock Manager +# + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# 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_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=m +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_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=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=m +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y -- GitLab From d864b96bb08f88d000cf8f78b5bac93fe631d0f5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 21:32:40 +0100 Subject: [PATCH 0799/1619] [MIPS] Ocelot C: Build fix - ll_mv64340_irq takes no more regs argument. Signed-off-by: Ralf Baechle --- arch/mips/momentum/ocelot_c/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c index 4be7b26e30e..ea65223a6d2 100644 --- a/arch/mips/momentum/ocelot_c/irq.c +++ b/arch/mips/momentum/ocelot_c/irq.c @@ -79,7 +79,7 @@ asmlinkage void plat_irq_dispatch(void) else if (pending & STATUSF_IP5) ll_cpci_irq(); else if (pending & STATUSF_IP6) - ll_mv64340_irq(regs); + ll_mv64340_irq(); else if (pending & STATUSF_IP7) do_IRQ(7); else -- GitLab From 65542070de7d6cd307657a71ab1712a6c58c0889 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 8 Oct 2006 23:56:13 +0100 Subject: [PATCH 0800/1619] [MIPS] Fix return type of gt64120_irq. Signed-off-by: Ralf Baechle --- arch/mips/gt64120/common/time.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c index b203169f19c..efafabdd5bb 100644 --- a/arch/mips/gt64120/common/time.c +++ b/arch/mips/gt64120/common/time.c @@ -20,7 +20,7 @@ * differently than other MIPS interrupts. */ -static void gt64120_irq(int irq, void *dev_id) +static irqreturn_t gt64120_irq(int irq, void *dev_id) { unsigned int irq_src, int_high_src, irq_src_mask, int_high_src_mask; int handled = 0; @@ -43,6 +43,8 @@ static void gt64120_irq(int irq, void *dev_id) GT_WRITE(GT_INTRCAUSE_OFS, 0); GT_WRITE(GT_HINTRCAUSE_OFS, 0); + + return IRQ_HANDLED; } /* -- GitLab From 6dab2f4564b3dc8747452e256fb779f320ff5650 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 Oct 2006 00:00:31 +0100 Subject: [PATCH 0801/1619] [MIPS] DEC: pt_regs fixes for buserror handlers Signed-off-by: Ralf Baechle --- arch/mips/dec/ecc-berr.c | 5 ++++- arch/mips/dec/kn01-berr.c | 4 ++-- arch/mips/dec/kn02xa-berr.c | 6 ++++-- include/asm-mips/dec/ecc.h | 3 +-- include/asm-mips/dec/kn01.h | 3 +-- include/asm-mips/dec/kn02xa.h | 3 +-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c index cc24c5ed0c0..3e374d05978 100644 --- a/arch/mips/dec/ecc-berr.c +++ b/arch/mips/dec/ecc-berr.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -200,8 +201,10 @@ int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup) return dec_ecc_be_backend(regs, is_fixup, 0); } -irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id) { + struct pt_regs *regs = get_irq_regs(); + int action = dec_ecc_be_backend(regs, 0, 1); if (action == MIPS_BE_DISCARD) diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c index b9271db9bc7..f19b4617a0a 100644 --- a/arch/mips/dec/kn01-berr.c +++ b/arch/mips/dec/kn01-berr.c @@ -150,10 +150,10 @@ int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup) return dec_kn01_be_backend(regs, is_fixup, 0); } -irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id) { volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR); + struct pt_regs *regs = get_irq_regs(); int action; if (!(*csr & KN01_CSR_MEMERR)) diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c index 6cd3f94f79f..7a053aadcd3 100644 --- a/arch/mips/dec/kn02xa-berr.c +++ b/arch/mips/dec/kn02xa-berr.c @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include @@ -104,9 +106,9 @@ int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup) return dec_kn02xa_be_backend(regs, is_fixup, 0); } -irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id) { + struct pt_regs *regs = get_irq_regs(); int action = dec_kn02xa_be_backend(regs, 0, 1); if (action == MIPS_BE_DISCARD) diff --git a/include/asm-mips/dec/ecc.h b/include/asm-mips/dec/ecc.h index 19495a490e7..707ffdbc9ad 100644 --- a/include/asm-mips/dec/ecc.h +++ b/include/asm-mips/dec/ecc.h @@ -49,8 +49,7 @@ struct pt_regs; extern void dec_ecc_be_init(void); extern int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup); -extern irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +extern irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id); #endif #endif /* __ASM_MIPS_DEC_ECC_H */ diff --git a/include/asm-mips/dec/kn01.h b/include/asm-mips/dec/kn01.h index eb522aa1e22..28fa717ac42 100644 --- a/include/asm-mips/dec/kn01.h +++ b/include/asm-mips/dec/kn01.h @@ -84,8 +84,7 @@ extern spinlock_t kn01_lock; extern void dec_kn01_be_init(void); extern int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup); -extern irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +extern irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id); #endif #endif /* __ASM_MIPS_DEC_KN01_H */ diff --git a/include/asm-mips/dec/kn02xa.h b/include/asm-mips/dec/kn02xa.h index a25f3d7da7f..b56b4577f6e 100644 --- a/include/asm-mips/dec/kn02xa.h +++ b/include/asm-mips/dec/kn02xa.h @@ -78,8 +78,7 @@ struct pt_regs; extern void dec_kn02xa_be_init(void); extern int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup); -extern irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +extern irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id); #endif #endif /* __ASM_MIPS_DEC_KN02XA_H */ -- GitLab From 27f768192fe2d96936cef5d4713e228daee07ae2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 Oct 2006 00:03:05 +0100 Subject: [PATCH 0802/1619] [MIPS] Cleanup unnecessary inclusions. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/time.c | 1 - arch/mips/cobalt/irq.c | 1 - arch/mips/dec/reset.c | 1 - arch/mips/gt64120/common/time.c | 1 - arch/mips/gt64120/ev64120/setup.c | 1 - arch/mips/gt64120/momenco_ocelot/setup.c | 1 - arch/mips/jazz/setup.c | 1 - arch/mips/kernel/irq-msc01.c | 9 +++++---- arch/mips/kernel/irq-mv6434x.c | 3 +-- arch/mips/mips-boards/generic/time.c | 1 - arch/mips/mips-boards/sim/sim_time.c | 1 - arch/mips/momentum/jaguar_atx/setup.c | 1 - arch/mips/momentum/ocelot_3/setup.c | 1 - arch/mips/momentum/ocelot_c/cpci-irq.c | 1 - arch/mips/momentum/ocelot_c/setup.c | 1 - arch/mips/momentum/ocelot_c/uart-irq.c | 1 - arch/mips/momentum/ocelot_g/gt-irq.c | 1 - arch/mips/momentum/ocelot_g/setup.c | 1 - arch/mips/pmc-sierra/yosemite/setup.c | 1 - arch/mips/sgi-ip27/ip27-irq.c | 1 - arch/mips/sgi-ip32/crime.c | 1 - arch/mips/sibyte/bcm1480/irq.c | 1 - arch/mips/sibyte/bcm1480/time.c | 1 - arch/mips/sibyte/sb1250/irq.c | 1 - arch/mips/sibyte/sb1250/time.c | 1 - arch/mips/sni/setup.c | 1 - arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c | 1 - .../tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 1 - arch/mips/tx4938/toshiba_rbtx4938/irq.c | 1 - 29 files changed, 6 insertions(+), 33 deletions(-) diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 1989d56139c..dd9c364b474 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -41,7 +41,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 1117fab1973..82e569d5b02 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -16,7 +16,6 @@ #include #include #include -#include #include diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c index 8c95ea19efb..56397227adb 100644 --- a/arch/mips/dec/reset.c +++ b/arch/mips/dec/reset.c @@ -8,7 +8,6 @@ #include #include -#include typedef void ATTRIB_NORET (* noret_func_t)(void); diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c index efafabdd5bb..c83ae6acd60 100644 --- a/arch/mips/gt64120/common/time.c +++ b/arch/mips/gt64120/common/time.c @@ -11,7 +11,6 @@ #include #include #include -#include #include /* diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c index 4236da31ecc..91c2d3f4161 100644 --- a/arch/mips/gt64120/ev64120/setup.c +++ b/arch/mips/gt64120/ev64120/setup.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/gt64120/momenco_ocelot/setup.c b/arch/mips/gt64120/momenco_ocelot/setup.c index 9804642ecf8..0e5bbee2d5b 100644 --- a/arch/mips/gt64120/momenco_ocelot/setup.c +++ b/arch/mips/gt64120/momenco_ocelot/setup.c @@ -56,7 +56,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index a3354c1f3d7..6dc4135d6e1 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 71e8e45f368..650a80ca374 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -1,16 +1,17 @@ /* - * Copyright (c) 2004 MIPS Inc - * Author: chris@mips.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. + * + * Copyright (c) 2004 MIPS Inc + * Author: chris@mips.com + * + * Copyright (C) 2004, 06 Ralf Baechle */ #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c index 39c94fd8d8b..37d106202b8 100644 --- a/arch/mips/kernel/irq-mv6434x.c +++ b/arch/mips/kernel/irq-mv6434x.c @@ -1,7 +1,7 @@ /* * Copyright 2002 Momentum Computer * Author: mdharm@momenco.com - * Copyright (C) 2004 Ralf Baechle + * Copyright (C) 2004, 06 Ralf Baechle * * 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 @@ -15,7 +15,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index d379000162f..6f8a9fe7c1e 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c index acd83a37955..c566b9bd042 100644 --- a/arch/mips/mips-boards/sim/sim_time.c +++ b/arch/mips/mips-boards/sim/sim_time.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c index e6fe2992227..5a510142b97 100644 --- a/arch/mips/momentum/jaguar_atx/setup.c +++ b/arch/mips/momentum/jaguar_atx/setup.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c index 435d0787329..7d74f8c5412 100644 --- a/arch/mips/momentum/ocelot_3/setup.c +++ b/arch/mips/momentum/ocelot_3/setup.c @@ -67,7 +67,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c index 2fb14bb08e6..47e3fa32b07 100644 --- a/arch/mips/momentum/ocelot_c/cpci-irq.c +++ b/arch/mips/momentum/ocelot_c/cpci-irq.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c index 36f570ecc6f..9c0c462af65 100644 --- a/arch/mips/momentum/ocelot_c/setup.c +++ b/arch/mips/momentum/ocelot_c/setup.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c index f8efe2370ff..510257dc205 100644 --- a/arch/mips/momentum/ocelot_c/uart-irq.c +++ b/arch/mips/momentum/ocelot_c/uart-irq.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c index b8cffa80548..7b5cc6648f7 100644 --- a/arch/mips/momentum/ocelot_g/gt-irq.c +++ b/arch/mips/momentum/ocelot_g/gt-irq.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c index c580b1de33b..56ec47039c1 100644 --- a/arch/mips/momentum/ocelot_g/setup.c +++ b/arch/mips/momentum/ocelot_g/setup.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 0a6ee8e5eec..1b9b0d396d3 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index f41587a206e..f01ba1f9077 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c index f1f2c45a6c8..bff508704d0 100644 --- a/arch/mips/sgi-ip32/crime.c +++ b/arch/mips/sgi-ip32/crime.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 0c00f676b8b..8b1f4148492 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index f228f711dc3..bf12af46132 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index f6d2e19592e..d5d26770daf 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 0d17aec03dd..0ccf1796dd7 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 4e98feb1541..afeb7f13e5b 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index b0f021f2a6c..3e24413d4c0 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -127,7 +127,6 @@ JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthB #include #include #include -#include #include #include #include diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index bea19098ac2..735cb8778f4 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index 83f2750825a..bbb3390e98f 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c @@ -81,7 +81,6 @@ IRQ Device #include #include #include -#include #include #include #include -- GitLab From 7bea96fd22a8fd19f90817405b4abe032317a0e3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 22:49:34 +0100 Subject: [PATCH 0803/1619] [PATCH] uml pt_regs fixes Real fix for UML pt_regs stuff. Note set_irq_regs() logics in there... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/um/drivers/line.c | 7 +++---- arch/um/drivers/mconsole_kern.c | 8 ++++---- arch/um/drivers/net_kern.c | 2 +- arch/um/drivers/port_kern.c | 4 ++-- arch/um/drivers/ubd_kern.c | 2 +- arch/um/drivers/xterm_kern.c | 2 +- arch/um/include/irq_kern.h | 5 ++--- arch/um/kernel/irq.c | 15 ++++++++------- arch/um/kernel/sigio.c | 2 +- arch/um/kernel/time.c | 2 +- 10 files changed, 24 insertions(+), 25 deletions(-) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index cfd9f01fd46..426633e5d6e 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -20,7 +20,7 @@ #define LINE_BUFSIZE 4096 -static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; @@ -364,8 +364,7 @@ void line_unthrottle(struct tty_struct *tty) reactivate_chan(&line->chan_list, line->driver->read_irq); } -static irqreturn_t line_write_interrupt(int irq, void *data, - struct pt_regs *unused) +static irqreturn_t line_write_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; @@ -712,7 +711,7 @@ struct winch { struct tty_struct *tty; }; -static irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t winch_interrupt(int irq, void *data) { struct winch *winch = data; struct tty_struct *tty; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index a67dcbd78de..d08bd036ccb 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -74,8 +74,7 @@ static void mc_work_proc(void *unused) static DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -static irqreturn_t mconsole_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t mconsole_interrupt(int irq, void *dev_id) { /* long to avoid size mismatch warnings from gcc */ long fd; @@ -674,8 +673,9 @@ static void with_console(struct mc_request *req, void (*proc)(void *), static void sysrq_proc(void *arg) { char *op = arg; - - handle_sysrq(*op, ¤t->thread.regs, NULL); + struct pt_regs *old_regs = set_irq_regs(¤t->thread.regs); + handle_sysrq(*op, NULL); + set_irq_regs(old_regs); } void mconsole_sysrq(struct mc_request *req) diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index c1c5604752f..ec9eb8bd943 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -77,7 +77,7 @@ static void uml_dev_close(void* dev) dev_close( (struct net_device *) dev); } -irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t uml_net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct uml_net_private *lp = dev->priv; diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 73755f37a8a..ce9f3733f73 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -47,7 +47,7 @@ struct connection { struct port_list *port; }; -static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t pipe_interrupt(int irq, void *data) { struct connection *conn = data; int fd; @@ -152,7 +152,7 @@ void port_work_proc(void *unused) DECLARE_WORK(port_work, port_work_proc, NULL); -static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t port_interrupt(int irq, void *data) { struct port_list *port = data; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f0b0668458b..bc458f57921 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -524,7 +524,7 @@ static void ubd_handler(void) do_ubd_request(ubd_queue); } -static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) +static irqreturn_t ubd_intr(int irq, void *dev) { ubd_handler(); return(IRQ_HANDLED); diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index 6036ec85895..a4ce7058e10 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -21,7 +21,7 @@ struct xterm_wait { int new_fd; }; -static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t xterm_interrupt(int irq, void *data) { struct xterm_wait *xterm = data; int fd; diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h index c222d56b149..81beb184129 100644 --- a/arch/um/include/irq_kern.h +++ b/arch/um/include/irq_kern.h @@ -10,12 +10,11 @@ #include "asm/ptrace.h" extern int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *, - struct pt_regs *), + irqreturn_t (*handler)(int, void *), unsigned long irqflags, const char * devname, void *dev_id); extern int init_aio_irq(int irq, char *name, - irqreturn_t (*handler)(int, void *, struct pt_regs *)); + irqreturn_t (*handler)(int, void *)); #endif diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 7c41dabe7a2..3c01c2bc979 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -355,14 +355,16 @@ void forward_interrupts(int pid) */ unsigned int do_IRQ(int irq, union uml_pt_regs *regs) { - irq_enter(); - __do_IRQ(irq); - irq_exit(); - return 1; + struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs); + irq_enter(); + __do_IRQ(irq); + irq_exit(); + set_irq_regs(old_regs); + return 1; } int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *), unsigned long irqflags, const char * devname, void *dev_id) { @@ -423,8 +425,7 @@ void __init init_IRQ(void) } } -int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, - struct pt_regs *)) +int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *)) { int fds[2], err; diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index 0ad755ceb21..2b0ab438301 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c @@ -17,7 +17,7 @@ /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; -static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t sigio_interrupt(int irq, void *data) { char c; diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index a92965f8f9c..2e354b3ca06 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -86,7 +86,7 @@ static inline unsigned long long get_time(void) return nsecs; } -irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) +irqreturn_t um_timer(int irq, void *dev) { unsigned long long nsecs; unsigned long flags; -- GitLab From 832504933757ba7913bf64cd574326e014215b41 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 8 Oct 2006 17:28:25 -0700 Subject: [PATCH 0804/1619] Fix extraneous '&' in recent NFS client cleanup We should pass "wait_event_interruptible()" the wait-queue itself, not the pointer to it. The magic macro will pointerize it internally. Signed-off-by: Linus Torvalds --- fs/nfs/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 013cdbc3b00..34c3996bd0f 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -322,7 +322,7 @@ found_client: if (new) nfs_free_client(new); - error = wait_event_interruptible(&nfs_client_active_wq, + error = wait_event_interruptible(nfs_client_active_wq, clp->cl_cons_state != NFS_CS_INITING); if (error < 0) { nfs_put_client(clp); -- GitLab From 1622605cf6e15bfdc55a3dc78b792018edded435 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 02:09:49 +0100 Subject: [PATCH 0805/1619] [PATCH] arm: it's OK to pass pointer to volatile as iounmap() argument... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/arm/mm/ioremap.c | 6 +++--- include/asm-arm/io.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 591fc3187c7..46544059279 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -361,14 +361,14 @@ __ioremap(unsigned long phys_addr, size_t size, unsigned long flags) } EXPORT_SYMBOL(__ioremap); -void __iounmap(void __iomem *addr) +void __iounmap(volatile void __iomem *addr) { #ifndef CONFIG_SMP struct vm_struct **p, *tmp; #endif unsigned int section_mapping = 0; - addr = (void __iomem *)(PAGE_MASK & (unsigned long)addr); + addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long)addr); #ifndef CONFIG_SMP /* @@ -395,6 +395,6 @@ void __iounmap(void __iomem *addr) #endif if (!section_mapping) - vunmap(addr); + vunmap((void __force *)addr); } EXPORT_SYMBOL(__iounmap); diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 8076a85c367..34aaaac4f61 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -63,7 +63,7 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); */ extern void __iomem * __ioremap_pfn(unsigned long, unsigned long, size_t, unsigned long); extern void __iomem * __ioremap(unsigned long, size_t, unsigned long); -extern void __iounmap(void __iomem *addr); +extern void __iounmap(volatile void __iomem *addr); /* * Bad read/write accesses... -- GitLab From 58ba81dba77eab43633ea47d82e96245ae3ff666 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 02:11:47 +0100 Subject: [PATCH 0806/1619] [PATCH] m68k/kernel/dma.c assumes !MMU_SUN3 Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m68k/kernel/Makefile | 3 ++- include/asm-m68k/dma-mapping.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index dae609797dc..1c9ecaa473d 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -9,10 +9,11 @@ else endif extra-y += vmlinux.lds -obj-y := entry.o process.o traps.o ints.o dma.o signal.o ptrace.o \ +obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o obj-$(CONFIG_PCI) += bios32.o obj-$(CONFIG_MODULES) += module.o +obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo EXTRA_AFLAGS := -traditional diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h index c1299c3beb5..d90d841d3df 100644 --- a/include/asm-m68k/dma-mapping.h +++ b/include/asm-m68k/dma-mapping.h @@ -5,6 +5,7 @@ struct scatterlist; +#ifndef CONFIG_MMU_SUN3 static inline int dma_supported(struct device *dev, u64 mask) { return 1; @@ -88,4 +89,8 @@ static inline int dma_mapping_error(dma_addr_t handle) return 0; } +#else +#include +#endif + #endif /* _M68K_DMA_MAPPING_H */ -- GitLab From 40220c1a192f51695f806d75b1f9970f0f17a6e8 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 9 Oct 2006 12:19:47 +0100 Subject: [PATCH 0807/1619] IRQ: Use the new typedef for interrupt handler function pointers Use the new typedef for interrupt handler function pointers rather than actually spelling out the full thing each time. This was scripted with the following small shell script: #!/bin/sh egrep -nHrl -e 'irqreturn_t[ ]*[(][*]' $* | while read i do echo $i perl -pi -e 's/irqreturn_t\s*[(]\s*[*]\s*([_a-zA-Z0-9]*)\s*[)]\s*[(]\s*int\s*,\s*void\s*[*]\s*[)]/irq_handler_t \1/g' $i || exit $? done Signed-Off-By: David Howells --- arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/idp.c | 2 +- arch/arm/mach-pxa/lubbock.c | 4 ++-- arch/arm/mach-pxa/mainstone.c | 2 +- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/spitz.c | 2 +- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-pxa/trizeps4.c | 2 +- arch/ia64/hp/sim/simserial.c | 2 +- arch/m68k/amiga/config.c | 4 ++-- arch/m68k/apollo/config.c | 6 +++--- arch/m68k/atari/config.c | 2 +- arch/m68k/atari/stdma.c | 4 ++-- arch/m68k/atari/time.c | 2 +- arch/m68k/bvme6000/config.c | 6 +++--- arch/m68k/hp300/time.c | 4 ++-- arch/m68k/hp300/time.h | 2 +- arch/m68k/kernel/ints.c | 2 +- arch/m68k/kernel/setup.c | 2 +- arch/m68k/mac/config.c | 4 ++-- arch/m68k/mac/via.c | 2 +- arch/m68k/mvme147/config.c | 6 +++--- arch/m68k/mvme16x/config.c | 6 +++--- arch/m68k/q40/config.c | 2 +- arch/m68k/q40/q40ints.c | 4 ++-- arch/m68k/sun3/config.c | 4 ++-- arch/m68k/sun3x/time.c | 2 +- arch/m68k/sun3x/time.h | 2 +- arch/mips/au1000/common/dma.c | 2 +- arch/mips/au1000/common/irq.c | 2 +- arch/mips/au1000/common/time.c | 2 +- arch/powerpc/kernel/ibmebus.c | 2 +- arch/sparc/kernel/irq.c | 10 +++++----- arch/sparc/kernel/sun4c_irq.c | 2 +- arch/sparc/kernel/sun4d_irq.c | 4 ++-- arch/sparc/kernel/sun4m_irq.c | 2 +- arch/sparc/kernel/tick14.c | 2 +- arch/um/include/irq_kern.h | 4 ++-- arch/um/kernel/irq.c | 4 ++-- include/asm-arm/arch-pxa/mmc.h | 2 +- include/asm-m68k/atari_stdma.h | 2 +- include/asm-m68k/ide.h | 2 +- include/asm-m68k/machdep.h | 2 +- include/asm-mips/mach-au1x00/au1000_dma.h | 2 +- include/asm-powerpc/ibmebus.h | 2 +- include/asm-sparc/irq.h | 6 +++--- 46 files changed, 70 insertions(+), 70 deletions(-) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 74f8378d7bb..a1a900d1666 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -212,7 +212,7 @@ static struct platform_device corgits_device = { */ static struct pxamci_platform_data corgi_mci_platform_data; -static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *), void *data) +static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, void *data) { int err; diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index a4cb875b748..64df44043a6 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -125,7 +125,7 @@ static struct pxafb_mach_info sharp_lm8v31 = { .pxafb_lcd_power = &idp_lcd_power }; -static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *), void *data) +static int idp_mci_init(struct device *dev, irq_handler_t idp_detect_int, void *data) { /* setup GPIO for PXA25x MMC controller */ pxa_gpio_mode(GPIO6_MMCCLK_MD); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index b1e77bd85a3..ee80d62119d 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -378,7 +378,7 @@ static struct pxafb_mach_info sharp_lm8v31 = { #define MMC_POLL_RATE msecs_to_jiffies(1000) static void lubbock_mmc_poll(unsigned long); -static irqreturn_t (*mmc_detect_int)(int, void *); +static irq_handler_t mmc_detect_int; static struct timer_list mmc_timer = { .function = lubbock_mmc_poll, @@ -412,7 +412,7 @@ static irqreturn_t lubbock_detect_int(int irq, void *data) } static int lubbock_mci_init(struct device *dev, - irqreturn_t (*detect_int)(int, void *), + irq_handler_t detect_int, void *data) { /* setup GPIO for PXA25x MMC controller */ diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 8c301978491..49c34d94a9f 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -313,7 +313,7 @@ static struct pxafb_mach_info mainstone_pxafb_info = { .pxafb_backlight_power = mainstone_backlight_power, }; -static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *), void *data) +static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_int, void *data) { int err; diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 9052a971c8a..34fb80b3702 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -197,7 +197,7 @@ static struct platform_device poodle_ts_device = { */ static struct pxamci_platform_data poodle_mci_platform_data; -static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(int, void *), void *data) +static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int, void *data) { int err; diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 911452dd0b4..3cbac63bed3 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -291,7 +291,7 @@ static struct platform_device spitzts_device = { static struct pxamci_platform_data spitz_mci_platform_data; -static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *), void *data) +static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, void *data) { int err; diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 17e46c1060b..7915a5a2286 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -174,7 +174,7 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = { */ static struct pxamci_platform_data tosa_mci_platform_data; -static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *), void *data) +static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void *data) { int err; diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index a2c05a840a2..c1827d021ba 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -270,7 +270,7 @@ void board_pcmcia_power(int power) {;} #endif /* CONFIG_MACH_TRIZEPS4_CONXS */ EXPORT_SYMBOL(board_pcmcia_power); -static int trizeps4_mci_init(struct device *dev, irqreturn_t (*mci_detect_int)(int, void *), void *data) +static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, void *data) { int err; /* setup GPIO for PXA27x MMC controller */ diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 77819acaea9..5095778be53 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -714,7 +714,7 @@ startup(struct async_struct *info) { unsigned long flags; int retval=0; - irqreturn_t (*handler)(int, void *); + irq_handler_t handler; struct serial_state *state= info->state; unsigned long page; diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 6f63d62bd7d..3204f412cad 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -83,7 +83,7 @@ static char amiga_model_name[13] = "Amiga "; extern char m68k_debug_device[]; -static void amiga_sched_init(irqreturn_t (*handler)(int, void *)); +static void amiga_sched_init(irq_handler_t handler); /* amiga specific irq functions */ extern void amiga_init_IRQ (void); static void amiga_get_model(char *model); @@ -487,7 +487,7 @@ void __init config_amiga(void) static unsigned short jiffy_ticks; -static void __init amiga_sched_init(irqreturn_t (*timer_routine)(int, void *)) +static void __init amiga_sched_init(irq_handler_t timer_routine) { static struct resource sched_res = { .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c index b2eea00796a..cb8e7609df4 100644 --- a/arch/m68k/apollo/config.c +++ b/arch/m68k/apollo/config.c @@ -25,7 +25,7 @@ u_long cpuctrl_physaddr; u_long timer_physaddr; u_long apollo_model; -extern void dn_sched_init(irqreturn_t (*handler)(int,void *)); +extern void dn_sched_init(irq_handler_t handler); extern void dn_init_IRQ(void); extern unsigned long dn_gettimeoffset(void); extern int dn_dummy_hwclk(int, struct rtc_time *); @@ -176,7 +176,7 @@ void config_apollo(void) { irqreturn_t dn_timer_int(int irq, void *dev_id) { - irqreturn_t (*timer_handler)(int, void *) = dev_id; + irq_handler_t timer_handler = dev_id; volatile unsigned char x; @@ -188,7 +188,7 @@ irqreturn_t dn_timer_int(int irq, void *dev_id) return IRQ_HANDLED; } -void dn_sched_init(irqreturn_t (*timer_routine)(int, void *)) +void dn_sched_init(irq_handler_t timer_routine) { /* program timer 1 */ *(volatile unsigned char *)(timer+3)=0x01; diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 76760eebbbc..ca5cd4344e3 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -62,7 +62,7 @@ static void atari_heartbeat( int on ); #endif /* atari specific timer functions (in time.c) */ -extern void atari_sched_init(irqreturn_t (*)(int, void *)); +extern void atari_sched_init(irq_handler_t ); extern unsigned long atari_gettimeoffset (void); extern int atari_mste_hwclk (int, struct rtc_time *); extern int atari_tt_hwclk (int, struct rtc_time *); diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 5283c73d3f7..d64b5804e98 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -44,7 +44,7 @@ static int stdma_locked; /* the semaphore */ /* int func to be called */ -static irqreturn_t (*stdma_isr)(int, void *); +static irq_handler_t stdma_isr; static void *stdma_isr_data; /* data passed to isr */ static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ @@ -75,7 +75,7 @@ static irqreturn_t stdma_int (int irq, void *dummy); * */ -void stdma_lock(irqreturn_t (*handler)(int, void *), void *data) +void stdma_lock(irq_handler_t handler, void *data) { unsigned long flags; diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index b8fe71cfc62..c44df4a4a33 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -20,7 +20,7 @@ #include void __init -atari_sched_init(irqreturn_t (*timer_routine)(int, void *)) +atari_sched_init(irq_handler_t timer_routine) { /* set Timer C data Register */ mfp.tim_dt_c = INT_TICKS; diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index df64efc940c..896ae3d3d91 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -38,7 +38,7 @@ static void bvme6000_get_model(char *model); static int bvme6000_get_hardware_list(char *buffer); -extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *)); +extern void bvme6000_sched_init(irq_handler_t handler); extern unsigned long bvme6000_gettimeoffset (void); extern int bvme6000_hwclk (int, struct rtc_time *); extern int bvme6000_set_clock_mmss (unsigned long); @@ -52,7 +52,7 @@ static unsigned char bin2bcd (unsigned char b); /* Save tick handler routine pointer, will point to do_timer() in * kernel/sched.c, called via bvme6000_process_int() */ -static irqreturn_t (*tick_handler)(int, void *); +static irq_handler_t tick_handler; int bvme6000_parse_bootinfo(const struct bi_record *bi) @@ -190,7 +190,7 @@ static irqreturn_t bvme6000_timer_int (int irq, void *dev_id) * so divide by 8 to get the microsecond result. */ -void bvme6000_sched_init (irqreturn_t (*timer_routine)(int, void *)) +void bvme6000_sched_init (irq_handler_t timer_routine) { volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; unsigned char msr = rtc->msr & 0xc0; diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c index 086058fd838..dd7c8a2583d 100644 --- a/arch/m68k/hp300/time.c +++ b/arch/m68k/hp300/time.c @@ -39,7 +39,7 @@ static irqreturn_t hp300_tick(int irq, void *dev_id) { unsigned long tmp; - irqreturn_t (*vector)(int, void *) = dev_id; + irq_handler_t vector = dev_id; in_8(CLOCKBASE + CLKSR); asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE)); /* Turn off the network and SCSI leds */ @@ -63,7 +63,7 @@ unsigned long hp300_gettimeoffset(void) return (USECS_PER_JIFFY * ticks) / INTVAL; } -void __init hp300_sched_init(irqreturn_t (*vector)(int, void *)) +void __init hp300_sched_init(irq_handler_t vector) { out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */ out_8(CLOCKBASE + CLKCR1, 0x1); /* reset */ diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h index ca66a039d6f..f5b3d098b0f 100644 --- a/arch/m68k/hp300/time.h +++ b/arch/m68k/hp300/time.h @@ -1,4 +1,4 @@ -extern void hp300_sched_init(irqreturn_t (*vector)(int, void *)); +extern void hp300_sched_init(irq_handler_t vector); extern unsigned long hp300_gettimeoffset (void); diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 6fa893fc5fd..849c9488c7f 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -216,7 +216,7 @@ int setup_irq(unsigned int irq, struct irq_node *node) } int request_irq(unsigned int irq, - irqreturn_t (*handler) (int, void *), + irq_handler_t handler, unsigned long flags, const char *devname, void *dev_id) { struct irq_node *node; diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 869c4861346..42d5b85f335 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -64,7 +64,7 @@ static char m68k_command_line[CL_SIZE]; char m68k_debug_device[6] = ""; -void (*mach_sched_init) (irqreturn_t (*handler)(int, void *)) __initdata = NULL; +void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; void (*mach_get_model) (char *model); diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 029bae65c5d..562b38d0018 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -72,7 +72,7 @@ extern int show_mac_interrupts(struct seq_file *, void *); extern void iop_preinit(void); extern void iop_init(void); extern void via_init(void); -extern void via_init_clock(irqreturn_t (*func)(int, void *)); +extern void via_init_clock(irq_handler_t func); extern void via_flush_cache(void); extern void oss_init(void); extern void psc_init(void); @@ -88,7 +88,7 @@ extern void mac_debugging_long(int, long); static void mac_get_model(char *str); -static void mac_sched_init(irqreturn_t (*vector)(int, void *)) +static void mac_sched_init(irq_handler_t vector) { via_init_clock(vector); } diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 9b6c80c4bbe..e27735be292 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -235,7 +235,7 @@ void __init via_init(void) * Start the 100 Hz clock */ -void __init via_init_clock(irqreturn_t (*func)(int, void *)) +void __init via_init_clock(irq_handler_t func) { via1[vACR] |= 0x40; via1[vT1LL] = MAC_CLOCK_LOW; diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index c864d641518..4a7df9c3f85 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -38,7 +38,7 @@ static void mvme147_get_model(char *model); static int mvme147_get_hardware_list(char *buffer); -extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *)); +extern void mvme147_sched_init(irq_handler_t handler); extern unsigned long mvme147_gettimeoffset (void); extern int mvme147_hwclk (int, struct rtc_time *); extern int mvme147_set_clock_mmss (unsigned long); @@ -51,7 +51,7 @@ static int bcd2int (unsigned char b); /* Save tick handler routine pointer, will point to do_timer() in * kernel/sched.c, called via mvme147_process_int() */ -irqreturn_t (*tick_handler)(int, void *); +irq_handler_t tick_handler; int mvme147_parse_bootinfo(const struct bi_record *bi) @@ -122,7 +122,7 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id) } -void mvme147_sched_init (irqreturn_t (*timer_routine)(int, void *)) +void mvme147_sched_init (irq_handler_t timer_routine) { tick_handler = timer_routine; request_irq (PCC_IRQ_TIMER1, mvme147_timer_int, diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index 2c91cee1709..c829ebb6b1a 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -42,7 +42,7 @@ static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE; static void mvme16x_get_model(char *model); static int mvme16x_get_hardware_list(char *buffer); -extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *)); +extern void mvme16x_sched_init(irq_handler_t handler); extern unsigned long mvme16x_gettimeoffset (void); extern int mvme16x_hwclk (int, struct rtc_time *); extern int mvme16x_set_clock_mmss (unsigned long); @@ -54,7 +54,7 @@ int bcd2int (unsigned char b); /* Save tick handler routine pointer, will point to do_timer() in * kernel/sched.c, called via mvme16x_process_int() */ -static irqreturn_t (*tick_handler)(int, void *); +static irq_handler_t tick_handler; unsigned short mvme16x_config; @@ -224,7 +224,7 @@ static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) return tick_handler(irq, dev_id); } -void mvme16x_sched_init (irqreturn_t (*timer_routine)(int, void *)) +void mvme16x_sched_init (irq_handler_t timer_routine) { p_bdid p = &mvme_bdid; int irq; diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 5123f693948..92f873cc706 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c @@ -39,7 +39,7 @@ extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); extern void q40_init_IRQ (void); static void q40_get_model(char *model); static int q40_get_hardware_list(char *buffer); -extern void q40_sched_init(irqreturn_t (*handler)(int, void *)); +extern void q40_sched_init(irq_handler_t handler); extern unsigned long q40_gettimeoffset (void); extern int q40_hwclk (int, struct rtc_time *); diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 4a4ee4dfa6f..31cc07d8cec 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -125,7 +125,7 @@ void q40_mksound(unsigned int hz, unsigned int ticks) sound_ticks = ticks << 1; } -static irqreturn_t (*q40_timer_routine)(int, void *); +static irq_handler_t q40_timer_routine; static irqreturn_t q40_timer_int (int irq, void * dev) { @@ -142,7 +142,7 @@ static irqreturn_t q40_timer_int (int irq, void * dev) return IRQ_HANDLED; } -void q40_sched_init (irqreturn_t (*timer_routine)(int, void *)) +void q40_sched_init (irq_handler_t timer_routine) { int timer_irq; diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index 43e4aa3f404..4851b8437a8 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -35,7 +35,7 @@ extern char _text, _end; char sun3_reserved_pmeg[SUN3_PMEGS_NUM]; extern unsigned long sun3_gettimeoffset(void); -extern void sun3_sched_init(irqreturn_t (*handler)(int, void *)); +extern void sun3_sched_init(irq_handler_t handler); extern void sun3_get_model (char* model); extern void idprom_init (void); extern int sun3_hwclk(int set, struct rtc_time *t); @@ -162,7 +162,7 @@ void __init config_sun3(void) sun3_bootmem_alloc(memory_start, memory_end); } -void __init sun3_sched_init(irqreturn_t (*timer_routine)(int, void *)) +void __init sun3_sched_init(irq_handler_t timer_routine) { sun3_disable_interrupts(); intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE); diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c index 33eb1ecc888..f5eaafb00d2 100644 --- a/arch/m68k/sun3x/time.c +++ b/arch/m68k/sun3x/time.c @@ -90,7 +90,7 @@ static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs) } #endif -void __init sun3x_sched_init(irqreturn_t (*vector)(int, void *)) +void __init sun3x_sched_init(irq_handler_t vector) { sun3_disable_interrupts(); diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h index e39079c781d..6909e129753 100644 --- a/arch/m68k/sun3x/time.h +++ b/arch/m68k/sun3x/time.h @@ -3,7 +3,7 @@ extern int sun3x_hwclk(int set, struct rtc_time *t); unsigned long sun3x_gettimeoffset (void); -void sun3x_sched_init(irqreturn_t (*vector)(int, void *)); +void sun3x_sched_init(irq_handler_t vector); struct mostek_dt { volatile unsigned char csr; diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c index c3019b9c91b..c78260d4e83 100644 --- a/arch/mips/au1000/common/dma.c +++ b/arch/mips/au1000/common/dma.c @@ -160,7 +160,7 @@ void dump_au1000_dma_channel(unsigned int dmanr) * Requests the DMA done IRQ if irqhandler != NULL. */ int request_au1000_dma(int dev_id, const char *dev_str, - irqreturn_t (*irqhandler)(int, void *), + irq_handler_t irqhandler, unsigned long irqflags, void *irq_dev_id) { diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index b32597e05a6..2abe132bb07 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -288,7 +288,7 @@ static struct irq_chip level_irq_type = { }; #ifdef CONFIG_PM -void startup_match20_interrupt(irqreturn_t (*handler)(int, void *)) +void startup_match20_interrupt(irq_handler_t handler) { struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT]; diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index dd9c364b474..94f09194d63 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -61,7 +61,7 @@ static unsigned int timerhi = 0, timerlo = 0; #error "unsupported HZ value! Must be in [100,1000]" #endif #define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */ -extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *)); +extern void startup_match20_interrupt(irq_handler_t handler); static unsigned long last_pc0, last_match20; #endif diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index da9fe254eb9..39db7a3affe 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -319,7 +319,7 @@ EXPORT_SYMBOL(ibmebus_unregister_driver); int ibmebus_request_irq(struct ibmebus_dev *dev, u32 ist, - irqreturn_t (*handler)(int, void*), + irq_handler_t handler, unsigned long irq_flags, const char * devname, void *dev_id) { diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index ae4dfc89ca5..b3b6680a2a3 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -134,8 +134,8 @@ static void irq_panic(void) prom_halt(); } -void (*sparc_init_timers)(irqreturn_t (*)(int, void *)) = - (void (*)(irqreturn_t (*)(int, void *))) irq_panic; +void (*sparc_init_timers)(irq_handler_t ) = + (void (*)(irq_handler_t )) irq_panic; /* * Dave Redman (djhr@tadpole.co.uk) @@ -376,7 +376,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) * thus no sharing possible. */ int request_fast_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *), + irq_handler_t handler, unsigned long irqflags, const char *devname) { struct irqaction *action; @@ -475,7 +475,7 @@ out: } int request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *), + irq_handler_t handler, unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction * action, **actionp; @@ -485,7 +485,7 @@ int request_irq(unsigned int irq, if (sparc_cpu_model == sun4d) { extern int sun4d_request_irq(unsigned int, - irqreturn_t (*)(int, void *), + irq_handler_t , unsigned long, const char *, void *); return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); } diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 2eaa0d085e1..009e891a432 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c @@ -154,7 +154,7 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) /* Errm.. not sure how to do this.. */ } -static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *)) +static void __init sun4c_init_timers(irq_handler_t counter_fn) { int irq; diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 836d1562787..d4f9da8170c 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -276,7 +276,7 @@ unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) } int sun4d_request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *), + irq_handler_t handler, unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction *action, *tmp = NULL, **actionp; @@ -470,7 +470,7 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit) bw_set_prof_limit(cpu, limit); } -static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *)) +static void __init sun4d_init_timers(irq_handler_t counter_fn) { int irq; int cpu; diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 28bcf8e2c5b..a654c16f402 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -228,7 +228,7 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit) sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; } -static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *)) +static void __init sun4m_init_timers(irq_handler_t counter_fn) { int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c index 7107d2f0625..f1a7bd19e04 100644 --- a/arch/sparc/kernel/tick14.c +++ b/arch/sparc/kernel/tick14.c @@ -55,7 +55,7 @@ void install_obp_ticker(void) linux_lvl14[3] = obp_lvl14[3]; } -void claim_ticker14(irqreturn_t (*handler)(int, void *), +void claim_ticker14(irq_handler_t handler, int irq_nr, unsigned int timeout ) { int cpu = smp_processor_id(); diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h index 81beb184129..4f775597fd5 100644 --- a/arch/um/include/irq_kern.h +++ b/arch/um/include/irq_kern.h @@ -10,11 +10,11 @@ #include "asm/ptrace.h" extern int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *), + irq_handler_t handler, unsigned long irqflags, const char * devname, void *dev_id); extern int init_aio_irq(int irq, char *name, - irqreturn_t (*handler)(int, void *)); + irq_handler_t handler); #endif diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 3c01c2bc979..ef259569fd8 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -364,7 +364,7 @@ unsigned int do_IRQ(int irq, union uml_pt_regs *regs) } int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *), + irq_handler_t handler, unsigned long irqflags, const char * devname, void *dev_id) { @@ -425,7 +425,7 @@ void __init init_IRQ(void) } } -int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *)) +int init_aio_irq(int irq, char *name, irq_handler_t handler) { int fds[2], err; diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h index b704c4f05f4..a38a28c4bbd 100644 --- a/include/asm-arm/arch-pxa/mmc.h +++ b/include/asm-arm/arch-pxa/mmc.h @@ -10,7 +10,7 @@ struct mmc_host; struct pxamci_platform_data { unsigned int ocr_mask; /* available voltages */ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ - int (*init)(struct device *, irqreturn_t (*)(int, void *), void *); + int (*init)(struct device *, irq_handler_t , void *); int (*get_ro)(struct device *); void (*setpower)(struct device *, unsigned int); void (*exit)(struct device *, void *); diff --git a/include/asm-m68k/atari_stdma.h b/include/asm-m68k/atari_stdma.h index a6986af7915..8e389b7fa70 100644 --- a/include/asm-m68k/atari_stdma.h +++ b/include/asm-m68k/atari_stdma.h @@ -8,7 +8,7 @@ /***************************** Prototypes *****************************/ -void stdma_lock(irqreturn_t (*handler)(int, void *), void *data); +void stdma_lock(irq_handler_t handler, void *data); void stdma_release( void ); int stdma_others_waiting( void ); int stdma_islocked( void ); diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h index 896683a7a1f..f9ffb2cbbae 100644 --- a/include/asm-m68k/ide.h +++ b/include/asm-m68k/ide.h @@ -123,7 +123,7 @@ static __inline__ void ide_release_lock (void) } static __inline__ void -ide_get_lock(irqreturn_t (*handler)(int, void *), void *data) +ide_get_lock(irq_handler_t handler, void *data) { if (MACH_IS_ATARI) { if (falconide_intr_lock == 0) { diff --git a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h index 862afa4c35d..26d2b91209c 100644 --- a/include/asm-m68k/machdep.h +++ b/include/asm-m68k/machdep.h @@ -10,7 +10,7 @@ struct rtc_time; struct rtc_pll_info; struct buffer_head; -extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *)); +extern void (*mach_sched_init) (irq_handler_t handler); /* machine dependent irq functions */ extern void (*mach_init_IRQ) (void); extern void (*mach_get_model) (char *model); diff --git a/include/asm-mips/mach-au1x00/au1000_dma.h b/include/asm-mips/mach-au1x00/au1000_dma.h index 0493cb0d617..9f29520e8fb 100644 --- a/include/asm-mips/mach-au1x00/au1000_dma.h +++ b/include/asm-mips/mach-au1x00/au1000_dma.h @@ -123,7 +123,7 @@ struct dma_chan { extern struct dma_chan au1000_dma_table[]; extern int request_au1000_dma(int dev_id, const char *dev_str, - irqreturn_t (*irqhandler)(int, void *), + irq_handler_t irqhandler, unsigned long irqflags, void *irq_dev_id); extern void free_au1000_dma(unsigned int dmanr); diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h index 9d25f2063b0..3493429b70f 100644 --- a/include/asm-powerpc/ibmebus.h +++ b/include/asm-powerpc/ibmebus.h @@ -65,7 +65,7 @@ void ibmebus_unregister_driver(struct ibmebus_driver *drv); int ibmebus_request_irq(struct ibmebus_dev *dev, u32 ist, - irqreturn_t (*handler)(int, void*), + irq_handler_t handler, unsigned long irq_flags, const char * devname, void *dev_id); void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id); diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h index 70867330f42..ff520ea9747 100644 --- a/include/asm-sparc/irq.h +++ b/include/asm-sparc/irq.h @@ -76,8 +76,8 @@ static inline void load_profile_irq(int cpu, int limit) BTFIXUP_CALL(load_profile_irq)(cpu, limit); } -extern void (*sparc_init_timers)(irqreturn_t (*lvl10_irq)(int, void *)); -extern void claim_ticker14(irqreturn_t (*irq_handler)(int, void *), +extern void (*sparc_init_timers)(irq_handler_t lvl10_irq); +extern void claim_ticker14(irq_handler_t irq_handler, int irq, unsigned int timeout); @@ -91,7 +91,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int) #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) #endif -extern int request_fast_irq(unsigned int irq, irqreturn_t (*handler)(int, void *), unsigned long flags, __const__ char *devname); +extern int request_fast_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, __const__ char *devname); /* On the sun4m, just like the timers, we have both per-cpu and master * interrupt registers. -- GitLab From 63540ba3691600759c6732f800dcf0fe8075960b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 11:51:14 +0100 Subject: [PATCH 0808/1619] [PATCH] sparc64 irq pt_regs fallout Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/sparc64/kernel/irq.c | 7 +++++-- arch/sparc64/kernel/time.c | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index ce05deb1bc9..d64b1ea848d 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -522,12 +522,13 @@ void ack_bad_irq(unsigned int virt_irq) } #ifndef CONFIG_SMP -extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); +extern irqreturn_t timer_interrupt(int, void *); void timer_irq(int irq, struct pt_regs *regs) { unsigned long clr_mask = 1 << irq; unsigned long tick_mask = tick_ops->softint_mask; + struct pt_regs *old_regs; if (get_softint() & tick_mask) { irq = 0; @@ -535,12 +536,14 @@ void timer_irq(int irq, struct pt_regs *regs) } clear_softint(clr_mask); + old_regs = set_irq_regs(regs); irq_enter(); kstat_this_cpu.irqs[0]++; - timer_interrupt(irq, NULL, regs); + timer_interrupt(irq, NULL); irq_exit(); + set_irq_regs(old_regs); } #endif diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 00f6fc4aaaf..061e1b1fa58 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -45,6 +45,7 @@ #include #include #include +#include DEFINE_SPINLOCK(mostek_lock); DEFINE_SPINLOCK(rtc_lock); @@ -452,7 +453,7 @@ static inline void timer_check_rtc(void) } } -irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t timer_interrupt(int irq, void *dev_id) { unsigned long ticks, compare, pstate; @@ -460,8 +461,8 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) do { #ifndef CONFIG_SMP - profile_tick(CPU_PROFILING, regs); - update_process_times(user_mode(regs)); + profile_tick(CPU_PROFILING); + update_process_times(user_mode(get_irq_regs())); #endif do_timer(1); -- GitLab From 041a6baec5a9260ad8b71c43a7ea1de95dfa974c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 12:46:52 +0100 Subject: [PATCH 0809/1619] [PATCH] fallout from alpha pt_regs patches missed irq handler in sys_titan and forgotten prototype update. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/proto.h | 2 +- arch/alpha/kernel/sys_titan.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index daccd4b6d28..95912ecc65e 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -36,7 +36,7 @@ extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); extern struct pci_ops irongate_pci_ops; extern int irongate_pci_clr_err(void); extern void irongate_init_arch(void); -extern void irongate_machine_check(u64, u64, struct pt_regs *); +extern void irongate_machine_check(u64, u64); #define irongate_pci_tbi ((void *)0) /* core_lca.c */ diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c index 161d6915dc4..29ab7db81c3 100644 --- a/arch/alpha/kernel/sys_titan.c +++ b/arch/alpha/kernel/sys_titan.c @@ -204,7 +204,7 @@ static struct hw_interrupt_type titan_irq_type = { }; static irqreturn_t -titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs) +titan_intr_nop(int irq, void *dev_id) { /* * This is a NOP interrupt handler for the purposes of -- GitLab From a23b7cb998f18101f9b0f505d81e6c68a7830a05 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 12:47:31 +0100 Subject: [PATCH 0810/1619] [PATCH] more ia64 irq handlers Cast to (void *) in request_irq() argument is stupid and only hides problems... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ia64/sn/kernel/huberror.c | 4 ++-- arch/ia64/sn/pci/pcibr/pcibr_provider.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c index 96fb81e6321..abca6bd7962 100644 --- a/arch/ia64/sn/kernel/huberror.c +++ b/arch/ia64/sn/kernel/huberror.c @@ -22,7 +22,7 @@ void hubiio_crb_error_handler(struct hubdev_info *hubdev_info); extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *, int); -static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep) +static irqreturn_t hub_eint_handler(int irq, void *arg) { struct hubdev_info *hubdev_info; struct ia64_sal_retval ret_stuff; @@ -178,7 +178,7 @@ void hubiio_crb_error_handler(struct hubdev_info *hubdev_info) */ void hub_error_init(struct hubdev_info *hubdev_info) { - if (request_irq(SGI_II_ERROR, (void *)hub_eint_handler, IRQF_SHARED, + if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED, "SN_hub_error", (void *)hubdev_info)) printk("hub_error_init: Failed to request_irq for 0x%p\n", hubdev_info); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 838c93c9a16..27dd7df0f44 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -95,7 +95,7 @@ u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus) * bridge sends an error interrupt. */ static irqreturn_t -pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *regs) +pcibr_error_intr_handler(int irq, void *arg) { struct pcibus_info *soft = (struct pcibus_info *)arg; @@ -138,7 +138,7 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont /* * register the bridge's error interrupt handler */ - if (request_irq(SGI_PCIASIC_ERROR, (void *)pcibr_error_intr_handler, + if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler, IRQF_SHARED, "PCIBR error", (void *)(soft))) { printk(KERN_WARNING "pcibr cannot allocate interrupt for error handler\n"); -- GitLab From f3d2ab41b5e2dfb2fc8679b786476327cea2f249 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 16:22:09 +0100 Subject: [PATCH 0811/1619] [PATCH] extern doesn't make sense on a definition of function... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/powerpc/kernel/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 829ac18b566..5e37bf14ef2 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -572,8 +572,8 @@ unsigned int irq_create_mapping(struct irq_host *host, } EXPORT_SYMBOL_GPL(irq_create_mapping); -extern unsigned int irq_create_of_mapping(struct device_node *controller, - u32 *intspec, unsigned int intsize) +unsigned int irq_create_of_mapping(struct device_node *controller, + u32 *intspec, unsigned int intsize) { struct irq_host *host; irq_hw_number_t hwirq; -- GitLab From 7c84ace9bcd90e38ebf88b304a8ed4fed7ff3574 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 16:23:09 +0100 Subject: [PATCH 0812/1619] [PATCH] trivial iomem annotations (arch/powerpc/platfroms/parsemi/pci.c) Signed-off-by: Al Viro Acked-by: Olof Johansson Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/pasemi/pci.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index 4679c523041..39020c1fa13 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -35,17 +35,17 @@ #define CONFIG_OFFSET_VALID(off) ((off) < 4096) -static unsigned long pa_pxp_cfg_addr(struct pci_controller *hose, +static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose, u8 bus, u8 devfn, int offset) { - return ((unsigned long)hose->cfg_data) + PA_PXP_CFA(bus, devfn, offset); + return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset); } static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { struct pci_controller *hose; - unsigned long addr; + void volatile __iomem *addr; hose = pci_bus_to_host(bus); if (!hose) @@ -62,13 +62,13 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, */ switch (len) { case 1: - *val = in_8((u8 *)addr); + *val = in_8(addr); break; case 2: - *val = in_le16((u16 *)addr); + *val = in_le16(addr); break; default: - *val = in_le32((u32 *)addr); + *val = in_le32(addr); break; } @@ -79,7 +79,7 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { struct pci_controller *hose; - unsigned long addr; + void volatile __iomem *addr; hose = pci_bus_to_host(bus); if (!hose) @@ -96,16 +96,16 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, */ switch (len) { case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); + out_8(addr, val); + (void) in_8(addr); break; case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); + out_le16(addr, val); + (void) in_le16(addr); break; default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); + out_le32(addr, val); + (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; -- GitLab From 8dc42f9e037e5fb7b01c1334b7752b9355f5293a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 16:26:47 +0100 Subject: [PATCH 0813/1619] [PATCH] mv64630_pic NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ppc/syslib/mv64360_pic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c index 3f6d162f87c..5104386601e 100644 --- a/arch/ppc/syslib/mv64360_pic.c +++ b/arch/ppc/syslib/mv64360_pic.c @@ -380,7 +380,7 @@ mv64360_register_hdlrs(void) /* Clear old errors and register CPU interface error intr handler */ mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0); if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base, - mv64360_cpu_error_int_handler, IRQF_DISABLED, CPU_INTR_STR, 0))) + mv64360_cpu_error_int_handler, IRQF_DISABLED, CPU_INTR_STR, NULL))) printk(KERN_WARNING "Can't register cpu error handler: %d", rc); mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0); @@ -389,7 +389,7 @@ mv64360_register_hdlrs(void) /* Clear old errors and register internal SRAM error intr handler */ mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0); if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base, - mv64360_sram_error_int_handler,IRQF_DISABLED,SRAM_INTR_STR, 0))) + mv64360_sram_error_int_handler,IRQF_DISABLED,SRAM_INTR_STR, NULL))) printk(KERN_WARNING "Can't register SRAM error handler: %d",rc); /* Clear old errors and register PCI 0 error intr handler */ -- GitLab From 5c09d96b34ac9b95ab4606e51ddb34ed0f19faf1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 20:24:49 +0100 Subject: [PATCH 0814/1619] [PATCH] wrong order of arguments in copy_to_user() in ncpfs Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/ncpfs/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index a89ac84a824..589d1eac55c 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -726,7 +726,7 @@ outrel: struct compat_ncp_privatedata_ioctl user32; user32.len = user.len; user32.data = (unsigned long) user.data; - if (copy_to_user(&user32, argp, sizeof(user32))) + if (copy_to_user(argp, &user32, sizeof(user32))) return -EFAULT; } else #endif -- GitLab From 38d6fd26ea7f291141039fe340a581dc6f770fc0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 20:27:30 +0100 Subject: [PATCH 0815/1619] [PATCH] dlm gfp_t annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/dlm/lowcomms.c | 6 +++--- fs/dlm/lowcomms.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 23f5ce12080..7bcea7c5add 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -174,7 +174,7 @@ static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr) return 0; } -static struct nodeinfo *nodeid2nodeinfo(int nodeid, int alloc) +static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc) { struct nodeinfo *ni; int r; @@ -726,7 +726,7 @@ static int init_sock(void) } -static struct writequeue_entry *new_writequeue_entry(int allocation) +static struct writequeue_entry *new_writequeue_entry(gfp_t allocation) { struct writequeue_entry *entry; @@ -748,7 +748,7 @@ static struct writequeue_entry *new_writequeue_entry(int allocation) return entry; } -void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc) +void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc) { struct writequeue_entry *e; int offset = 0; diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h index 6c04bb09cfa..2d045e0daae 100644 --- a/fs/dlm/lowcomms.h +++ b/fs/dlm/lowcomms.h @@ -19,7 +19,7 @@ void dlm_lowcomms_exit(void); int dlm_lowcomms_start(void); void dlm_lowcomms_stop(void); int dlm_lowcomms_close(int nodeid); -void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc); +void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc); void dlm_lowcomms_commit_buffer(void *mh); #endif /* __LOWCOMMS_DOT_H__ */ -- GitLab From c8adf94a4806b4ae49a3057d434471a0b01096e3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 20:26:58 +0100 Subject: [PATCH 0816/1619] [PATCH] hppfs: readdir callback missed in prototype change Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/hppfs/hppfs_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index dcb6d2e988b..642675fc394 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -572,7 +572,7 @@ struct hppfs_dirent { }; static int hppfs_filldir(void *d, const char *name, int size, - loff_t offset, ino_t inode, unsigned int type) + loff_t offset, u64 inode, unsigned int type) { struct hppfs_dirent *dirent = d; -- GitLab From 5a42b81f03b756116f982e72838bc358bc4e460f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 20:28:03 +0100 Subject: [PATCH 0817/1619] [PATCH] s390 traps.c __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/s390/kernel/traps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 05bf3cc8530..66375a5e3d1 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -474,7 +474,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) signal = math_emu_b3(opcode, regs); } else if (opcode[0] == 0xed) { get_user(*((__u32 *) (opcode+2)), - (__u32 *)(location+1)); + (__u32 __user *)(location+1)); signal = math_emu_ed(opcode, regs); } else if (*((__u16 *) opcode) == 0xb299) { get_user(*((__u16 *) (opcode+2)), location+1); @@ -499,7 +499,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) info.si_signo = signal; info.si_errno = 0; info.si_code = SEGV_MAPERR; - info.si_addr = (void *) location; + info.si_addr = (void __user *) location; do_trap(interruption_code, signal, "user address fault", regs, &info); } else @@ -520,10 +520,10 @@ asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; - __u16 *location = NULL; + __u16 __user *location = NULL; int signal = 0; - location = (__u16 *) get_check_address(regs); + location = (__u16 __user *) get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -632,7 +632,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) break; case 0xed: get_user(*((__u32 *) (opcode+2)), - (__u32 *)(location+1)); + (__u32 __user *)(location+1)); signal = math_emu_ed(opcode, regs); break; case 0xb2: -- GitLab From 97c4965d970587a1cc4264c1cffbf0ea9c1e35e8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 20:29:03 +0100 Subject: [PATCH 0818/1619] [PATCH] mos7840 annotations __user annotations, NULL noise removal, %p use for pointers Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/serial/mos7840.c | 46 +++++++++++++----------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 2306d493e55..021be39fe16 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1087,7 +1087,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) mos7840_port->icount.tx = 0; mos7840_port->icount.rx = 0; - dbg("\n\nusb_serial serial:%x mos7840_port:%x\n usb_serial_port port:%x\n\n", (unsigned int)serial, (unsigned int)mos7840_port, (unsigned int)port); + dbg("\n\nusb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p\n\n", serial, mos7840_port, port); return 0; @@ -1420,7 +1420,6 @@ static int mos7840_write(struct usb_serial_port *port, int i; int bytes_sent = 0; int transfer_size; - int from_user = 0; struct moschip_port *mos7840_port; struct usb_serial *serial; @@ -1511,15 +1510,7 @@ static int mos7840_write(struct usb_serial_port *port, } transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); - if (from_user) { - if (copy_from_user - (urb->transfer_buffer, current_position, transfer_size)) { - bytes_sent = -EFAULT; - goto exit; - } - } else { - memcpy(urb->transfer_buffer, current_position, transfer_size); - } + memcpy(urb->transfer_buffer, current_position, transfer_size); /* fill urb with data and submit */ usb_fill_bulk_urb(urb, @@ -2225,7 +2216,7 @@ static void mos7840_set_termios(struct usb_serial_port *port, *****************************************************************************/ static int mos7840_get_lsr_info(struct moschip_port *mos7840_port, - unsigned int *value) + unsigned int __user *value) { int count; unsigned int result = 0; @@ -2248,7 +2239,7 @@ static int mos7840_get_lsr_info(struct moschip_port *mos7840_port, *****************************************************************************/ static int mos7840_get_bytes_avail(struct moschip_port *mos7840_port, - unsigned int *value) + unsigned int __user *value) { unsigned int result = 0; struct tty_struct *tty = mos7840_port->port->tty; @@ -2271,7 +2262,7 @@ static int mos7840_get_bytes_avail(struct moschip_port *mos7840_port, *****************************************************************************/ static int mos7840_set_modem_info(struct moschip_port *mos7840_port, - unsigned int cmd, unsigned int *value) + unsigned int cmd, unsigned int __user *value) { unsigned int mcr; unsigned int arg; @@ -2341,7 +2332,7 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port, *****************************************************************************/ static int mos7840_get_modem_info(struct moschip_port *mos7840_port, - unsigned int *value) + unsigned int __user *value) { unsigned int result = 0; __u16 msr; @@ -2370,7 +2361,7 @@ static int mos7840_get_modem_info(struct moschip_port *mos7840_port, *****************************************************************************/ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, - struct serial_struct *retinfo) + struct serial_struct __user *retinfo) { struct serial_struct tmp; @@ -2405,6 +2396,7 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { + void __user *argp = (void __user *)arg; struct moschip_port *mos7840_port; struct tty_struct *tty; @@ -2433,16 +2425,13 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, case TIOCINQ: dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); - return mos7840_get_bytes_avail(mos7840_port, - (unsigned int *)arg); - break; + return mos7840_get_bytes_avail(mos7840_port, argp); case TIOCOUTQ: dbg("%s (%d) TIOCOUTQ", __FUNCTION__, port->number); return put_user(tty->driver->chars_in_buffer ? tty->driver->chars_in_buffer(tty) : 0, (int __user *)arg); - break; case TCFLSH: retval = tty_check_change(tty); @@ -2472,13 +2461,13 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, case TCGETS: if (kernel_termios_to_user_termios - ((struct termios __user *)arg, tty->termios)) + ((struct termios __user *)argp, tty->termios)) return -EFAULT; return 0; case TIOCSERGETLSR: dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); - return mos7840_get_lsr_info(mos7840_port, (unsigned int *)arg); + return mos7840_get_lsr_info(mos7840_port, argp); return 0; case TIOCMBIS: @@ -2487,19 +2476,16 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number); mosret = - mos7840_set_modem_info(mos7840_port, cmd, - (unsigned int *)arg); + mos7840_set_modem_info(mos7840_port, cmd, argp); return mosret; case TIOCMGET: dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); - return mos7840_get_modem_info(mos7840_port, - (unsigned int *)arg); + return mos7840_get_modem_info(mos7840_port, argp); case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); - return mos7840_get_serial_info(mos7840_port, - (struct serial_struct *)arg); + return mos7840_get_serial_info(mos7840_port, argp); case TIOCSSERIAL: dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); @@ -2549,7 +2535,7 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, port->number, icount.rx, icount.tx); - if (copy_to_user((void *)arg, &icount, sizeof(icount))) + if (copy_to_user(argp, &icount, sizeof(icount))) return -EFAULT; return 0; @@ -2817,7 +2803,7 @@ static int mos7840_startup(struct usb_serial *serial) /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8) 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 5 * HZ); + (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ); return 0; } -- GitLab From e069d79d23739977800c3b8495853b735f77ef30 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 20:29:43 +0100 Subject: [PATCH 0819/1619] [PATCH] tifm __iomem annotations, NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/misc/tifm_7xx1.c | 13 +++++++------ drivers/misc/tifm_core.c | 2 +- drivers/mmc/tifm_sd.c | 14 +++++++------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index b1748669e05..1ba8754e938 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -48,7 +48,7 @@ static void tifm_7xx1_remove_media(void *adapter) printk(KERN_INFO DRIVER_NAME ": demand removing card from socket %d\n", cnt); sock = fm->sockets[cnt]; - fm->sockets[cnt] = 0; + fm->sockets[cnt] = NULL; fm->remove_mask &= ~(1 << cnt); writel(0x0e00, sock->addr + SOCK_CONTROL); @@ -118,7 +118,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static tifm_media_id tifm_7xx1_toggle_sock_power(char *sock_addr, int is_x2) +static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2) { unsigned int s_state; int cnt; @@ -163,7 +163,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char *sock_addr, int is_x2) return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; } -inline static char *tifm_7xx1_sock_addr(char *base_addr, unsigned int sock_num) +inline static char __iomem * +tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) { return base_addr + ((sock_num + 1) << 10); } @@ -176,7 +177,7 @@ static void tifm_7xx1_insert_media(void *adapter) char *card_name = "xx"; int cnt, ok_to_register; unsigned int insert_mask; - struct tifm_dev *new_sock = 0; + struct tifm_dev *new_sock = NULL; if (!class_device_get(&fm->cdev)) return; @@ -230,7 +231,7 @@ static void tifm_7xx1_insert_media(void *adapter) if (!ok_to_register || device_register(&new_sock->dev)) { spin_lock_irqsave(&fm->lock, flags); - fm->sockets[cnt] = 0; + fm->sockets[cnt] = NULL; spin_unlock_irqrestore(&fm->lock, flags); tifm_free_device(&new_sock->dev); @@ -390,7 +391,7 @@ static void tifm_7xx1_remove(struct pci_dev *dev) tifm_remove_adapter(fm); - pci_set_drvdata(dev, 0); + pci_set_drvdata(dev, NULL); iounmap(fm->addr); pci_intx(dev, 0); diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index cca5f852246..ee326136d03 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -157,7 +157,7 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id) dev->wq = create_singlethread_workqueue(dev->wq_name); if (!dev->wq) { kfree(dev); - return 0; + return NULL; } dev->dev.parent = fm->dev; dev->dev.bus = &tifm_bus_type; diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 6d23dc08d16..2bacff60913 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -501,13 +501,13 @@ static void tifm_sd_end_cmd(void *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; + struct mmc_data *r_data = NULL; unsigned long flags; spin_lock_irqsave(&sock->lock, flags); mrq = host->req; - host->req = 0; + host->req = NULL; host->state = IDLE; if (!mrq) { @@ -546,7 +546,7 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) struct tifm_dev *sock = host->dev; unsigned long flags; struct mmc_data *r_data = mrq->cmd->data; - char *t_buffer = 0; + char *t_buffer = NULL; if (r_data) { t_buffer = kmap(r_data->sg->page); @@ -613,13 +613,13 @@ static void tifm_sd_end_cmd_nodma(void *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; + struct mmc_data *r_data = NULL; unsigned long flags; spin_lock_irqsave(&sock->lock, flags); mrq = host->req; - host->req = 0; + host->req = NULL; host->state = IDLE; if (!mrq) { @@ -644,7 +644,7 @@ static void tifm_sd_end_cmd_nodma(void *data) r_data->bytes_xfered += r_data->blksz - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; } - host->buffer = 0; + host->buffer = NULL; host->buffer_pos = 0; host->buffer_size = 0; } @@ -895,7 +895,7 @@ static void tifm_sd_remove(struct tifm_dev *sock) sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - tifm_set_drvdata(sock, 0); + tifm_set_drvdata(sock, NULL); mmc_free_host(mmc); } -- GitLab From 659564c8adfe1765476beee8d55cd18986946892 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Mon, 9 Oct 2006 16:10:48 -0400 Subject: [PATCH 0820/1619] [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(-) diff --git a/fs/xattr.c b/fs/xattr.c index c32f15b5f60..395635100f7 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 cda8a96e2fa..0e7f1e20ea4 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 *); -- GitLab From d3696cf7370583b272ff2f09524c9d37a83c71b2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Oct 2006 23:41:59 -0600 Subject: [PATCH 0821/1619] [PATCH] x86_64 irq: Scream but don't die if we receive an unexpected irq Due to code bugs or misbehaving hardware it is possible that we can receive an interrupt that we have not mapped into a linux irq. Calling BUG when that happens is very rude, and if the problem is mild enough prevents anything else from getting done. So instead of calling BUG just scream loudly about the problem and continue running. We don't have enough knowledge to know which interrupt triggered this behavior so we don't acknowledge it. This will likely prevent a recurrence of the problem by jamming up the works with an unacknowledged interrupt. If the interrupt was something important it is quite possible that nothing productive will happen past this point. But it is now at least possible to keep working if the kernel can survive without the interrupt we dropped on the floor. Solutions like irqpoll should generally make dropped irqs non-fatal. Signed-off-by: Eric W. Biederman Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/irq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index b8a407fcd5d..dff68eb2b78 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -114,16 +114,16 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) irq_enter(); irq = __get_cpu_var(vector_irq)[vector]; - if (unlikely(irq >= NR_IRQS)) { - printk(KERN_EMERG "%s: cannot handle IRQ %d\n", - __FUNCTION__, irq); - BUG(); - } - #ifdef CONFIG_DEBUG_STACKOVERFLOW stack_overflow_check(regs); #endif - generic_handle_irq(irq); + + if (likely(irq < NR_IRQS)) + generic_handle_irq(irq); + else + printk(KERN_EMERG "%s: %d.%d No irq handler for vector\n", + __func__, smp_processor_id(), vector); + irq_exit(); set_irq_regs(old_regs); -- GitLab From 6aabd6af4aaf6d794f67226934ad731eb1765e5d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:02:25 +0200 Subject: [PATCH 0822/1619] [PATCH] m68k: syscall updates Add some missing system calls (recent udev needs them) Signed-off-by: Kars de Jong Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- arch/m68k/kernel/entry.S | 5 +++++ include/asm-m68k/unistd.h | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 34bf7bd126d..03375414eb5 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -706,4 +706,9 @@ sys_call_table: .long sys_add_key .long sys_request_key /* 280 */ .long sys_keyctl + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init + .long sys_inotify_add_watch /* 285 */ + .long sys_inotify_rm_watch diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index 3ab716f0fc1..682bd2fb591 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -284,10 +284,15 @@ #define __NR_add_key 279 #define __NR_request_key 280 #define __NR_keyctl 281 +#define __NR_ioprio_set 282 +#define __NR_ioprio_get 283 +#define __NR_inotify_init 284 +#define __NR_inotify_add_watch 285 +#define __NR_inotify_rm_watch 286 #ifdef __KERNEL__ -#define NR_syscalls 282 +#define NR_syscalls 287 #include /* user-visible error numbers are in the range -1 - -MAX_ERRNO: see -- GitLab From 6fb8296aa1681e74b2aa3c59169d9014e6a0dfc3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:02:31 +0200 Subject: [PATCH 0823/1619] [PATCH] m68k: more syscall updates Add missing syscalls Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- arch/m68k/kernel/entry.S | 24 ++++++++++++++++++++++++ include/asm-m68k/unistd.h | 26 +++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 03375414eb5..222ce424456 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -711,4 +711,28 @@ sys_call_table: .long sys_inotify_init .long sys_inotify_add_watch /* 285 */ .long sys_inotify_rm_watch + .long sys_migrate_pages + .long sys_openat + .long sys_mkdirat + .long sys_mknodat /* 290 */ + .long sys_fchownat + .long sys_futimesat + .long sys_fstatat64 + .long sys_unlinkat + .long sys_renameat /* 295 */ + .long sys_linkat + .long sys_symlinkat + .long sys_readlinkat + .long sys_fchmodat + .long sys_faccessat /* 300 */ + .long sys_ni_syscall /* Reserved for pselect6 */ + .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_unshare + .long sys_set_robust_list + .long sys_get_robust_list /* 305 */ + .long sys_splice + .long sys_sync_file_range + .long sys_tee + .long sys_vmsplice + .long sys_move_pages /* 310 */ diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index 682bd2fb591..ad4348058c6 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -289,10 +289,34 @@ #define __NR_inotify_init 284 #define __NR_inotify_add_watch 285 #define __NR_inotify_rm_watch 286 +#define __NR_migrate_pages 287 +#define __NR_openat 288 +#define __NR_mkdirat 289 +#define __NR_mknodat 290 +#define __NR_fchownat 291 +#define __NR_futimesat 292 +#define __NR_fstatat64 293 +#define __NR_unlinkat 294 +#define __NR_renameat 295 +#define __NR_linkat 296 +#define __NR_symlinkat 297 +#define __NR_readlinkat 298 +#define __NR_fchmodat 299 +#define __NR_faccessat 300 +#define __NR_pselect6 301 +#define __NR_ppoll 302 +#define __NR_unshare 303 +#define __NR_set_robust_list 304 +#define __NR_get_robust_list 305 +#define __NR_splice 306 +#define __NR_sync_file_range 307 +#define __NR_tee 308 +#define __NR_vmsplice 309 +#define __NR_move_pages 310 #ifdef __KERNEL__ -#define NR_syscalls 287 +#define NR_syscalls 311 #include /* user-visible error numbers are in the range -1 - -MAX_ERRNO: see -- GitLab From da96d0b58adddf3bdeaa9644ac74f0dcc9039407 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:22:37 +0200 Subject: [PATCH 0824/1619] [PATCH] m68k/HP300: Enable HIL configuration options Enable HIL configuration options on HP300 Signed-off-by: Kars de Jong Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- drivers/input/keyboard/Kconfig | 4 ++-- drivers/input/misc/Kconfig | 2 +- drivers/input/mouse/Kconfig | 2 +- drivers/input/serio/Kconfig | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 679bde34d24..81a333f7301 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -166,7 +166,7 @@ config KEYBOARD_AMIGA config KEYBOARD_HIL_OLD tristate "HP HIL keyboard support (simple driver)" - depends on GSC + depends on GSC || HP300 default y help The "Human Interface Loop" is a older, 8-channel USB-like @@ -183,7 +183,7 @@ config KEYBOARD_HIL_OLD config KEYBOARD_HIL tristate "HP HIL keyboard support" - depends on GSC + depends on GSC || HP300 default y select HP_SDC select HIL_MLC diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index a6dfc745573..ba0e88c64e1 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -73,7 +73,7 @@ config INPUT_UINPUT config HP_SDC_RTC tristate "HP SDC Real Time Clock" - depends on GSC + depends on GSC || HP300 select HP_SDC help Say Y here if you want to support the built-in real time clock diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index f15ccf78168..35d998c3e57 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -119,7 +119,7 @@ config MOUSE_VSXXXAA config MOUSE_HIL tristate "HIL pointers (mice etc)." - depends on GSC + depends on GSC || HP300 select HP_SDC select HIL_MLC help diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 8cdbfeca590..adef447f23e 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -112,7 +112,7 @@ config SERIO_GSCPS2 config HP_SDC tristate "HP System Device Controller i8042 Support" - depends on GSC && SERIO + depends on (GSC || HP300) && SERIO default y ---help--- This option enables support for the "System Device -- GitLab From 69961c375288bdab7604e0bb1c8d22999bb8a347 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:23:31 +0200 Subject: [PATCH 0825/1619] [PATCH] m68k/Atari: Interrupt updates Misc Atari fixes: - initialize correct number of atari irqs - silence vbl interrupt until it's used by atafb - use mdelay() to read clock if necessary Signed-off-by: Roman Zippel Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- arch/m68k/atari/ataints.c | 9 +++++++-- arch/m68k/atari/time.c | 9 +++++++-- arch/m68k/kernel/ints.c | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index ece13cbf995..7f812641790 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -332,6 +332,9 @@ static void atari_shutdown_irq(unsigned int irq) atari_disable_irq(irq); atari_turnoff_irq(irq); m68k_irq_shutdown(irq); + + if (irq == IRQ_AUTO_4) + vectors[VEC_INT4] = falcon_hblhandler; } static struct irq_controller atari_irq_controller = { @@ -356,7 +359,7 @@ static struct irq_controller atari_irq_controller = { void __init atari_init_IRQ(void) { - m68k_setup_user_interrupt(VEC_USER, 192, NULL); + m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL); m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1); /* Initialize the MFP(s) */ @@ -403,8 +406,10 @@ void __init atari_init_IRQ(void) * gets overruns) */ - if (!MACH_IS_HADES) + if (!MACH_IS_HADES) { vectors[VEC_INT2] = falcon_hblhandler; + vectors[VEC_INT4] = falcon_hblhandler; + } } if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index c44df4a4a33..e0d3c8bfb40 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -212,8 +213,12 @@ int atari_tt_hwclk( int op, struct rtc_time *t ) * additionally the RTC_SET bit is set to prevent an update cycle. */ - while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) - schedule_timeout_interruptible(HWCLK_POLL_INTERVAL); + while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { + if (in_atomic() || irqs_disabled()) + mdelay(1); + else + schedule_timeout_interruptible(HWCLK_POLL_INTERVAL); + } local_irq_save(flags); RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 849c9488c7f..84aceca6c05 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -132,6 +132,7 @@ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, { int i; + BUG_ON(IRQ_USER + cnt >= NR_IRQS); m68k_first_user_vec = vec; for (i = 0; i < cnt; i++) irq_controller[IRQ_USER + i] = &user_irq_controller; -- GitLab From 2ed0ce5b57950a620155433c62a5a02a067f1376 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:23:56 +0200 Subject: [PATCH 0826/1619] [PATCH] m68k/Apollo: Remove obsolete arch/m68k/apollo/dma.c Remove unused arch/m68k/apollo/dma.c, which was obsoleted by the move to the generic DMA API. Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- arch/m68k/apollo/dma.c | 50 ------------------------------------------ 1 file changed, 50 deletions(-) delete mode 100644 arch/m68k/apollo/dma.c diff --git a/arch/m68k/apollo/dma.c b/arch/m68k/apollo/dma.c deleted file mode 100644 index aed8be177ef..00000000000 --- a/arch/m68k/apollo/dma.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* note only works for 16 Bit 1 page DMA's */ - -static unsigned short next_free_xlat_entry=0; - -unsigned short dma_map_page(unsigned long phys_addr,int count,int type) { - - unsigned long page_aligned_addr=phys_addr & (~((1<<12)-1)); - unsigned short start_map_addr=page_aligned_addr >> 10; - unsigned short free_xlat_entry, *xlat_map_entry; - int i; - - free_xlat_entry=next_free_xlat_entry; - for(i=0,xlat_map_entry=addr_xlat_map+(free_xlat_entry<<2);i<8;i++,xlat_map_entry++) { -#if 0 - printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i); -#endif - out_be16(xlat_map_entry, start_map_addr+i); - } - - next_free_xlat_entry+=2; - if(next_free_xlat_entry>125) - next_free_xlat_entry=0; - -#if 0 - printk("next_free_xlat_entry: %d\n",next_free_xlat_entry); -#endif - - return free_xlat_entry<<10; -} - -void dma_unmap_page(unsigned short dma_addr) { - - return ; - -} - -- GitLab From ea62aa1b6f6d31b53a34a6f5271ed85735ccc0bc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:27:42 +0200 Subject: [PATCH 0827/1619] [PATCH] m68k/MVME167: SERIAL167 is no longer broken - SERIAL167 is no longer broken - Removed some unused variables from the driver to fix compiler warnings Signed-off-by: Kars de Jong Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- arch/m68k/Kconfig | 2 +- drivers/char/serial167.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 805b81fedf8..7bc14461a6a 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -600,7 +600,7 @@ config MVME147_SCC config SERIAL167 bool "CD2401 support for MVME166/7 serial ports" - depends on MVME16x && BROKEN + depends on MVME16x help This is the driver for the serial ports on the Motorola MVME166, 167, and 172 boards. Everyone using one of these boards should say diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 6f13f98e317..defc0dbdedb 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -1422,7 +1422,6 @@ cy_tiocmget(struct tty_struct *tty, struct file *file) volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; unsigned char status; - unsigned int result; channel = info->line; @@ -1446,7 +1445,6 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, int channel; volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; - unsigned int arg; channel = info->line; -- GitLab From 81e859ac1eef300c1b2ff49a2f2da8ee4ce1e844 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Oct 2006 22:27:42 +0200 Subject: [PATCH 0828/1619] [PATCH] m68k/MVME167: SERIAL167 tty flip buffer updates Compile fixes related to changed tty flip buffer handling. Signed-off-by: Kars de Jong Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Torvalds --- drivers/char/serial167.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index defc0dbdedb..461bfe0234c 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -427,8 +428,9 @@ cd2401_rxerr_interrupt(int irq, void *dev_id) overflowing, we still loose the next incoming character. */ - tty_insert_flip_char(tty, data, TTY_NORMAL); - } + if (tty_buffer_request_room(tty, 1) != 0){ + tty_insert_flip_char(tty, data, TTY_FRAME); + } /* These two conditions may imply */ /* a normal read should be done. */ /* else if(data & CyTIMEOUT) */ @@ -437,14 +439,14 @@ cd2401_rxerr_interrupt(int irq, void *dev_id) tty_insert_flip_char(tty, 0, TTY_NORMAL); } }else{ - tty_insert_flip_char(tty, data, TTY_NORMAL); + tty_insert_flip_char(tty, data, TTY_NORMAL); } }else{ /* there was a software buffer overrun and nothing could be done about it!!! */ } } - schedule_delayed_work(&tty->flip.work, 1); + tty_schedule_flip(tty); /* end of service */ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; return IRQ_HANDLED; @@ -635,6 +637,7 @@ cd2401_rx_interrupt(int irq, void *dev_id) char data; int char_count; int save_cnt; + int len; /* determine the channel and change to that context */ channel = (u_short ) (base_addr[CyLICR] >> 2); @@ -667,14 +670,15 @@ cd2401_rx_interrupt(int irq, void *dev_id) info->mon.char_max = char_count; info->mon.char_last = char_count; #endif - while(char_count--){ + len = tty_buffer_request_room(tty, char_count); + while(len--){ data = base_addr[CyRDR]; tty_insert_flip_char(tty, data, TTY_NORMAL); #ifdef CYCLOM_16Y_HACK udelay(10L); #endif } - schedule_delayed_work(&tty->flip.work, 1); + tty_schedule_flip(tty); } /* end of service */ base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS; -- GitLab From 441ee341ad63572f39cb8074e31806b5b1471d0b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 2 Jun 2006 11:48:11 +0100 Subject: [PATCH 0829/1619] [MIPS] Fix RM9000 wait instruction detection. Only revisions < 4.0 don't have a functional wait instruction. From Thomas Koeller (Thomas.Koeller@baslerweb.com). Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 9fbf8430c84..8485af340ee 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -135,7 +135,6 @@ static inline void check_wait(void) case CPU_R5000: case CPU_NEVADA: case CPU_RM7000: - case CPU_RM9000: case CPU_4KC: case CPU_4KEC: case CPU_4KSC: @@ -164,6 +163,14 @@ static inline void check_wait(void) } else printk(" unavailable.\n"); break; + case CPU_RM9000: + if ((c->processor_id & 0x00ff) >= 0x40) { + cpu_wait = r4k_wait; + printk(" available.\n"); + } else { + printk(" unavailable.\n"); + } + break; default: printk(" unavailable.\n"); break; -- GitLab From f431baa55abf8adeed0c718b51deacbc151f58f1 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 9 Oct 2006 01:24:23 +0900 Subject: [PATCH 0830/1619] [MIPS] ret_from_irq adjustment Make sure that RA on top of interrupt stack is an address of ret_from_irq, so that dump_stack etc. can trace info interrupted context. Also this patch fixes except_vec_vi_handler and __smtc_ipi_vector which seems broken. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/dec/int-handler.S | 11 ++++------- arch/mips/kernel/entry.S | 14 +++++++++----- arch/mips/kernel/genex.S | 8 +++----- arch/mips/kernel/smtc-asm.S | 9 +++------ 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 55d60d5e0e8..31dd47d1002 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -266,10 +266,8 @@ handle_it: LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) - jal do_IRQ - LONG_S s0, TI_REGS($28) - - j ret_from_irq + PTR_LA ra, ret_from_irq + j do_IRQ nop #ifdef CONFIG_32BIT @@ -279,9 +277,8 @@ fpu: #endif spurious: - jal spurious_interrupt - nop - j ret_from_irq + PTR_LA ra, _ret_from_irq + j spurious_interrupt nop END(plat_irq_dispatch) diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index e93e43e1f42..417c08ac76e 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -20,10 +20,7 @@ #include #endif -#ifdef CONFIG_PREEMPT - .macro preempt_stop - .endm -#else +#ifndef CONFIG_PREEMPT .macro preempt_stop local_irq_disable .endm @@ -32,9 +29,16 @@ .text .align 5 +FEXPORT(ret_from_irq) + LONG_S s0, TI_REGS($28) +#ifdef CONFIG_PREEMPT +FEXPORT(ret_from_exception) +#else + b _ret_from_irq FEXPORT(ret_from_exception) preempt_stop -FEXPORT(ret_from_irq) +#endif +FEXPORT(_ret_from_irq) LONG_L t0, PT_STATUS(sp) # returning to kernel mode? andi t0, t0, KU_USER beqz t0, resume_kernel diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 50ed7729772..5baca16993d 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -133,9 +133,8 @@ NESTED(handle_int, PT_SIZE, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) - jal plat_irq_dispatch - LONG_S s0, TI_REGS($28) - j ret_from_irq + PTR_LA ra, ret_from_irq + j plat_irq_dispatch END(handle_int) __INIT @@ -224,9 +223,8 @@ NESTED(except_vec_vi_handler, 0, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) - jalr v0 - LONG_S s0, TI_REGS($28) PTR_LA ra, ret_from_irq + jr v0 END(except_vec_vi_handler) /* diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S index 76cb31d5748..1cb9441f147 100644 --- a/arch/mips/kernel/smtc-asm.S +++ b/arch/mips/kernel/smtc-asm.S @@ -97,15 +97,12 @@ FEXPORT(__smtc_ipi_vector) SAVE_ALL CLI TRACE_IRQS_OFF - move a0,sp /* Function to be invoked passed stack pad slot 5 */ lw t0,PT_PADSLOT5(sp) /* Argument from sender passed in stack pad slot 4 */ - lw a1,PT_PADSLOT4(sp) - jalr t0 - nop - j ret_from_irq - nop + lw a0,PT_PADSLOT4(sp) + PTR_LA ra, _ret_from_irq + jr t0 /* * Called from idle loop to provoke processing of queued IPIs -- GitLab From 18965513fdc3af976f000f231ee216500d707c11 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 Oct 2006 23:20:46 +0100 Subject: [PATCH 0831/1619] [MIPS] qtronix: remove driver. Another leftover of removing support for the ITE8172. Signed-off-by: Ralf Baechle --- drivers/char/qtronix.c | 605 ----------------------------------------- 1 file changed, 605 deletions(-) delete mode 100644 drivers/char/qtronix.c diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c deleted file mode 100644 index 5c9477741a3..00000000000 --- a/drivers/char/qtronix.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Qtronix 990P infrared keyboard driver. - * - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * - * The bottom portion of this driver was take from - * pc_keyb.c Please see that file for copyrights. - * - * 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. - */ - - -/* - * NOTE: - * - * This driver has only been tested with the Consumer IR - * port of the ITE 8172 system controller. - * - * You do not need this driver if you are using the ps/2 or - * USB adapter that the keyboard ships with. You only need - * this driver if your board has a IR port and the keyboard - * data is being sent directly to the IR. In that case, - * you also need some low-level IR support. See it8172_cir.c. - * - */ - -#ifdef CONFIG_QTRONIX_KEYBOARD - -#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 -#include - -#define leading1 0 -#define leading2 0xF - -#define KBD_CIR_PORT 0 -#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */ - -static int data_index; -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); -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); -static int __init psaux_init(void); - -static struct aux_queue *queue; /* Mouse data buffer. */ -static int aux_count = 0; - -/* - * Keys accessed through the 'Fn' key - * The Fn key does not produce a key-up sequence. So, the first - * time the user presses it, it will be key-down event. The key - * stays down until the user presses it again. - */ -#define NUM_FN_KEYS 56 -static unsigned char fn_keys[NUM_FN_KEYS] = { - 0,0,0,0,0,0,0,0, /* 0 7 */ - 8,9,10,93,0,0,0,0, /* 8 15 */ - 0,0,0,0,0,0,0,5, /* 16 23 */ - 6,7,91,0,0,0,0,0, /* 24 31 */ - 0,0,0,0,0,2,3,4, /* 32 39 */ - 92,0,0,0,0,0,0,0, /* 40 47 */ - 0,0,0,0,11,0,94,95 /* 48 55 */ - -}; - -void __init init_qtronix_990P_kbd(void) -{ - int retval; - - cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL); - if (!cir) { - printk("Unable to initialize Qtronix keyboard\n"); - return; - } - - /* - * revisit - * this should be programmable, somehow by the, by the user. - */ - cir->port = KBD_CIR_PORT; - cir->baud_rate = 0x1d; - cir->rdwos = 0; - cir->rxdcr = 0x3; - cir->hcfs = 0; - cir->fifo_tl = 0; - cir->cfq = 0x1d; - cir_port_init(cir); - - retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler, - (unsigned long )(IRQF_DISABLED|IRQF_SHARED), - (const char *)"Qtronix IR Keyboard", (void *)cir); - - if (retval) { - printk("unable to allocate cir %d irq %d\n", - cir->port, IT8172_CIR0_IRQ); - } -#ifdef CONFIG_PSMOUSE - psaux_init(); -#endif -} - -static inline unsigned char BitReverse(unsigned short key) -{ - unsigned char rkey = 0; - rkey |= (key & 0x1) << 7; - rkey |= (key & 0x2) << 5; - rkey |= (key & 0x4) << 3; - rkey |= (key & 0x8) << 1; - rkey |= (key & 0x10) >> 1; - rkey |= (key & 0x20) >> 3; - rkey |= (key & 0x40) >> 5; - rkey |= (key & 0x80) >> 7; - return rkey; - -} - - -static inline u_int8_t UpperByte(u_int8_t data) -{ - return (data >> 4); -} - - -static inline u_int8_t LowerByte(u_int8_t data) -{ - return (data & 0xF); -} - - -int CheckSumOk(u_int8_t byte1, u_int8_t byte2, - u_int8_t byte3, u_int8_t byte4, u_int8_t byte5) -{ - u_int8_t CheckSum; - - CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5; - if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) ) - return 0; - else - return 1; -} - - -static void kbd_int_handler(int irq, void *dev_id) -{ - struct cir_port *cir; - int j; - unsigned char int_status; - - cir = (struct cir_port *)dev_id; - int_status = get_int_status(cir); - if (int_status & 0x4) { - clear_fifo(cir); - return; - } - - while (cir_get_rx_count(cir)) { - - cir_data[data_index] = cir_read_data(cir); - - if (data_index == 0) {/* expecting first byte */ - if (cir_data[data_index] != leading1) { - //printk("!leading byte %x\n", cir_data[data_index]); - set_rx_active(cir); - clear_fifo(cir); - continue; - } - } - if (data_index == 1) { - if ((cir_data[data_index] & 0xf) != leading2) { - set_rx_active(cir); - data_index = 0; /* start over */ - clear_fifo(cir); - continue; - } - } - - if ( (cir_data[data_index] == 0xff)) { /* last byte */ - //printk("data_index %d\n", data_index); - set_rx_active(cir); -#if 0 - for (j=0; j<=data_index; j++) { - printk("rx_data %d: %x\n", j, cir_data[j]); - } -#endif - data_index = 0; - handle_data(cir_data); - return; - } - else if (data_index>16) { - set_rx_active(cir); -#if 0 - printk("warning: data_index %d\n", data_index); - for (j=0; j<=data_index; j++) { - printk("rx_data %d: %x\n", j, cir_data[j]); - } -#endif - data_index = 0; - clear_fifo(cir); - return; - } - data_index++; - } -} - - -#define NUM_KBD_BYTES 5 -static int handle_data(unsigned char *p_data) -{ - u_int32_t bit_bucket; - u_int32_t i, j; - u_int32_t got_bits, next_byte; - int down = 0; - - /* Reorganize the bit stream */ - for (i=0; i<16; i++) - p_data[i] = BitReverse(~p_data[i]); - - /* - * We've already previously checked that p_data[0] - * is equal to leading1 and that (p_data[1] & 0xf) - * is equal to leading2. These twelve bits are the - * leader code. We can now throw them away (the 12 - * bits) and continue parsing the stream. - */ - bit_bucket = p_data[1] << 12; - got_bits = 4; - next_byte = 2; - - /* - * Process four bits at a time - */ - for (i=0; i> 1); - got_bits -= 4; - bit_bucket = bit_bucket << 4; - } - else if ((bit_bucket & 0xC000) == 0x8000) { - /* Convert 10b to 0 */ - kbdbytes[i] = kbdbytes[i] >> 1; - got_bits -= 2; - bit_bucket = bit_bucket << 2; - } - else { - /* bad serial stream */ - return 1; - } - - if (next_byte > 16) { - //printk("error: too many bytes\n"); - return 1; - } - } - } - - - if (!CheckSumOk(kbdbytes[0], kbdbytes[1], - kbdbytes[2], kbdbytes[3], kbdbytes[4])) { - //printk("checksum failed\n"); - return 1; - } - - if (kbdbytes[1] & 0x08) { - //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]); - handle_mouse_event(kbdbytes[1]); - handle_mouse_event(kbdbytes[2]); - handle_mouse_event(kbdbytes[3]); - } - else { - if (kbdbytes[2] == 0) down = 1; -#if 0 - if (down) - printk("down %d\n", kbdbytes[3]); - else - printk("up %d\n", kbdbytes[3]); -#endif - handle_keyboard_event(kbdbytes[3], down); - } - return 0; -} - - -DEFINE_SPINLOCK(kbd_controller_lock); -static unsigned char handle_kbd_event(void); - - -int kbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode); - return 0; -} - -int kbd_getkeycode(unsigned int scancode) -{ - return scancode; -} - - -int kbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ - static int prev_scancode = 0; - - if (scancode == 0x00 || scancode == 0xff) { - prev_scancode = 0; - return 0; - } - - /* todo */ - if (!prev_scancode && scancode == 160) { /* Fn key down */ - //printk("Fn key down\n"); - prev_scancode = 160; - return 0; - } - else if (prev_scancode && scancode == 160) { /* Fn key up */ - //printk("Fn key up\n"); - prev_scancode = 0; - return 0; - } - - /* todo */ - if (prev_scancode == 160) { - if (scancode <= NUM_FN_KEYS) { - *keycode = fn_keys[scancode]; - //printk("fn keycode %d\n", *keycode); - } - else - return 0; - } - else if (scancode <= 127) { - *keycode = scancode; - } - else - return 0; - - - return 1; -} - -char kbd_unexpected_up(unsigned char keycode) -{ - //printk("kbd_unexpected_up\n"); - return 0; -} - -static unsigned char kbd_exists = 1; - -static inline void handle_keyboard_event(unsigned char scancode, int down) -{ - kbd_exists = 1; - handle_scancode(scancode, down); - tasklet_schedule(&keyboard_tasklet); -} - - -void kbd_leds(unsigned char leds) -{ -} - -/* dummy */ -void kbd_init_hw(void) -{ -} - - - -static inline void handle_mouse_event(unsigned char scancode) -{ - if(scancode == AUX_RECONNECT){ - queue->head = queue->tail = 0; /* Flush input queue */ - // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ - return; - } - - if (aux_count) { - int head = queue->head; - - queue->buf[head] = scancode; - head = (head + 1) & (AUX_BUF_SIZE-1); - if (head != queue->tail) { - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); - } - } -} - -static unsigned char get_from_queue(void) -{ - unsigned char result; - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - //printk("fasync_aux\n"); - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - - -/* - * Random magic cookie for the aux device - */ -#define AUX_DEV ((void *)queue) - -static int release_aux(struct inode * inode, struct file * file) -{ - fasync_aux(-1, file, 0); - aux_count--; - return 0; -} - -static int open_aux(struct inode * inode, struct file * file) -{ - if (aux_count++) { - return 0; - } - queue->head = queue->tail = 0; /* Flush input queue */ - return 0; -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - struct inode *inode = file->f_dentry->d_inode; - inode->i_atime = current_fs_time(inode->i_sb); - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - /* - * The ITE boards this was tested on did not have the - * transmit wires connected. - */ - return count; -} - -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations psaux_fops = { - .read = read_aux, - .write = write_aux, - .poll = aux_poll, - .open = open_aux, - .release = release_aux, - .fasync = fasync_aux, -}; - -/* - * Initialize driver. - */ -static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &psaux_fops -}; - -static int __init psaux_init(void) -{ - int retval; - - retval = misc_register(&psaux_mouse); - if(retval < 0) - return retval; - - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) { - misc_deregister(&psaux_mouse); - return -ENOMEM; - } - - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - - return 0; -} -module_init(init_qtronix_990P_kbd); -#endif -- GitLab From 0e8f8f54c1537d22eb0168622a5f6aef4040da6a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 8 Jul 2006 01:07:40 +0200 Subject: [PATCH 0832/1619] [MIPS] NUMA: Register all nodes before cpus or sysfs will barf. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 221895802dc..1af3612a1ce 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -467,14 +467,18 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); static int __init topology_init(void) { - int cpu; - int ret; + int i, ret; - for_each_present_cpu(cpu) { - ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu); +#ifdef CONFIG_NUMA + for_each_online_node(i) + register_one_node(i); +#endif /* CONFIG_NUMA */ + + for_each_present_cpu(i) { + ret = register_cpu(&per_cpu(cpu_devices, i), i); if (ret) printk(KERN_WARNING "topology_init: register_cpu %d " - "failed (%d)\n", cpu, ret); + "failed (%d)\n", i, ret); } return 0; -- GitLab From 12a0a703b3f07e5b01c81fe4f5d2a221c9318f16 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 Oct 2006 23:20:47 +0100 Subject: [PATCH 0833/1619] [RTC] Consistently use of tabs for formatting. --- drivers/char/rtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index abee7a33946..66a7385bc34 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -35,13 +35,13 @@ * 1.09a Pete Zaitcev: Sun SPARC * 1.09b Jeff Garzik: Modularize, init cleanup * 1.09c Jeff Garzik: SMP cleanup - * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10 Paul Barton-Davis: add support for async I/O * 1.10a Andrea Arcangeli: Alpha updates * 1.10b Andrew Morton: SMP lock fix * 1.10c Cesar Barros: SMP locking fixes and cleanup * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. - * 1.11 Takashi Iwai: Kernel access functions + * 1.11 Takashi Iwai: Kernel access functions * rtc_register/rtc_unregister/rtc_control * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer -- GitLab From 0118c3ca9e7518b06a10e9d7f4bd15957df45783 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 5 Jun 2006 11:54:41 +0100 Subject: [PATCH 0834/1619] [MIPS] Malta: Fix build for non-MIPS32/64 configuration. Signed-off-by: Ralf Baechle --- arch/mips/mips-boards/malta/malta_int.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index ed221dc7f6a..6244d0e2c7d 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -212,23 +212,23 @@ static inline unsigned int irq_ffs(unsigned int pending) unsigned int a0 = 7; unsigned int t0; - t0 = s0 & 0xf000; + t0 = pending & 0xf000; t0 = t0 < 1; t0 = t0 << 2; a0 = a0 - t0; - s0 = s0 << t0; + pending = pending << t0; - t0 = s0 & 0xc000; + t0 = pending & 0xc000; t0 = t0 < 1; t0 = t0 << 1; a0 = a0 - t0; - s0 = s0 << t0; + pending = pending << t0; - t0 = s0 & 0x8000; + t0 = pending & 0x8000; t0 = t0 < 1; //t0 = t0 << 2; a0 = a0 - t0; - //s0 = s0 << t0; + //pending = pending << t0; return a0; #endif -- GitLab From 5536b2351425136e629bd9fc18135c6e21e125c2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 Oct 2006 16:34:41 +0100 Subject: [PATCH 0835/1619] [MIPS] Alchemy: nuke usbdev; it's useless as is ... Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 5 - arch/mips/au1000/common/Makefile | 1 - arch/mips/au1000/common/usbdev.c | 1552 ------------------ arch/mips/au1000/db1x00/board_setup.c | 5 - arch/mips/au1000/mtx-1/board_setup.c | 8 +- arch/mips/au1000/pb1000/board_setup.c | 10 +- arch/mips/au1000/pb1100/board_setup.c | 6 +- arch/mips/au1000/pb1500/board_setup.c | 9 +- arch/mips/configs/pb1100_defconfig | 1 - arch/mips/configs/pb1500_defconfig | 1 - include/asm-mips/mach-au1x00/au1000_usbdev.h | 73 - 11 files changed, 9 insertions(+), 1662 deletions(-) delete mode 100644 arch/mips/au1000/common/usbdev.c delete mode 100644 include/asm-mips/mach-au1x00/au1000_usbdev.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 731b942a824..14af6cce2fa 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1010,11 +1010,6 @@ endchoice config ARC32 bool -config AU1X00_USB_DEVICE - bool - depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000 - default n - config BOOT_ELF32 bool diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile index bf682f50b85..4c35525edb4 100644 --- a/arch/mips/au1000/common/Makefile +++ b/arch/mips/au1000/common/Makefile @@ -10,6 +10,5 @@ obj-y += prom.o irq.o puts.o time.o reset.o \ au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ sleeper.o cputable.o dma.o dbdma.o gpio.o -obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o obj-$(CONFIG_KGDB) += dbg_io.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c deleted file mode 100644 index 70dc82e536c..00000000000 --- a/arch/mips/au1000/common/usbdev.c +++ /dev/null @@ -1,1552 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Au1000 USB Device-Side (device layer) - * - * Copyright 2001-2002 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 -#include -#include -#define DEBUG -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG -#undef VDEBUG -#ifdef VDEBUG -#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg) -#else -#define vdbg(fmt, arg...) do {} while (0) -#endif -#else -#define vdbg(fmt, arg...) do {} while (0) -#endif - -#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL) - -#define EP_FIFO_DEPTH 8 - -typedef enum { - SETUP_STAGE = 0, - DATA_STAGE, - STATUS_STAGE -} ep0_stage_t; - -typedef struct { - int read_fifo; - int write_fifo; - int ctrl_stat; - int read_fifo_status; - int write_fifo_status; -} endpoint_reg_t; - -typedef struct { - usbdev_pkt_t *head; - usbdev_pkt_t *tail; - int count; -} pkt_list_t; - -typedef struct { - int active; - struct usb_endpoint_descriptor *desc; - endpoint_reg_t *reg; - /* Only one of these are used, unless this is the control ep */ - pkt_list_t inlist; - pkt_list_t outlist; - unsigned int indma, outdma; /* DMA channel numbers for IN, OUT */ - /* following are extracted from endpoint descriptor for easy access */ - int max_pkt_size; - int type; - int direction; - /* WE assign endpoint addresses! */ - int address; - spinlock_t lock; -} endpoint_t; - - -static struct usb_dev { - endpoint_t ep[6]; - ep0_stage_t ep0_stage; - - struct usb_device_descriptor * dev_desc; - struct usb_interface_descriptor* if_desc; - struct usb_config_descriptor * conf_desc; - u8 * full_conf_desc; - struct usb_string_descriptor * str_desc[6]; - - /* callback to function layer */ - void (*func_cb)(usbdev_cb_type_t type, unsigned long arg, - void *cb_data); - void* cb_data; - - usbdev_state_t state; // device state - int suspended; // suspended flag - int address; // device address - int interface; - int num_ep; - u8 alternate_setting; - u8 configuration; // configuration value - int remote_wakeup_en; -} usbdev; - - -static endpoint_reg_t ep_reg[] = { - // FIFO's 0 and 1 are EP0 default control - {USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT }, - {0}, - // FIFO 2 is EP2, IN - { -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT }, - // FIFO 3 is EP3, IN - { -1, USBD_EP3WR, USBD_EP3CS, -1, USBD_EP3WRSTAT }, - // FIFO 4 is EP4, OUT - {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP4RDSTAT, -1 }, - // FIFO 5 is EP5, OUT - {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1 } -}; - -static struct { - unsigned int id; - const char *str; -} ep_dma_id[] = { - { DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" }, - { DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" }, - { DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" }, - { DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" }, - { DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" }, - { DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" } -}; - -#define DIR_OUT 0 -#define DIR_IN (1<<3) - -#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL -#define BULK_EP USB_ENDPOINT_XFER_BULK - -static inline endpoint_t * -epaddr_to_ep(struct usb_dev* dev, int ep_addr) -{ - if (ep_addr >= 0 && ep_addr < 2) - return &dev->ep[0]; - if (ep_addr < 6) - return &dev->ep[ep_addr]; - return NULL; -} - -static const char* std_req_name[] = { - "GET_STATUS", - "CLEAR_FEATURE", - "RESERVED", - "SET_FEATURE", - "RESERVED", - "SET_ADDRESS", - "GET_DESCRIPTOR", - "SET_DESCRIPTOR", - "GET_CONFIGURATION", - "SET_CONFIGURATION", - "GET_INTERFACE", - "SET_INTERFACE", - "SYNCH_FRAME" -}; - -static inline const char* -get_std_req_name(int req) -{ - return (req >= 0 && req <= 12) ? std_req_name[req] : "UNKNOWN"; -} - -#if 0 -static void -dump_setup(struct usb_ctrlrequest* s) -{ - dbg("%s: requesttype=%d", __FUNCTION__, s->requesttype); - dbg("%s: request=%d %s", __FUNCTION__, s->request, - get_std_req_name(s->request)); - dbg("%s: value=0x%04x", __FUNCTION__, s->wValue); - dbg("%s: index=%d", __FUNCTION__, s->index); - dbg("%s: length=%d", __FUNCTION__, s->length); -} -#endif - -static inline usbdev_pkt_t * -alloc_packet(endpoint_t * ep, int data_size, void* data) -{ - usbdev_pkt_t* pkt = kmalloc(sizeof(usbdev_pkt_t) + data_size, - ALLOC_FLAGS); - if (!pkt) - return NULL; - pkt->ep_addr = ep->address; - pkt->size = data_size; - pkt->status = 0; - pkt->next = NULL; - if (data) - memcpy(pkt->payload, data, data_size); - - return pkt; -} - - -/* - * Link a packet to the tail of the enpoint's packet list. - * EP spinlock must be held when calling. - */ -static void -link_tail(endpoint_t * ep, pkt_list_t * list, usbdev_pkt_t * pkt) -{ - if (!list->tail) { - list->head = list->tail = pkt; - list->count = 1; - } else { - list->tail->next = pkt; - list->tail = pkt; - list->count++; - } -} - -/* - * Unlink and return a packet from the head of the given packet - * list. It is the responsibility of the caller to free the packet. - * EP spinlock must be held when calling. - */ -static usbdev_pkt_t * -unlink_head(pkt_list_t * list) -{ - usbdev_pkt_t *pkt; - - pkt = list->head; - if (!pkt || !list->count) { - return NULL; - } - - list->head = pkt->next; - if (!list->head) { - list->head = list->tail = NULL; - list->count = 0; - } else - list->count--; - - return pkt; -} - -/* - * Create and attach a new packet to the tail of the enpoint's - * packet list. EP spinlock must be held when calling. - */ -static usbdev_pkt_t * -add_packet(endpoint_t * ep, pkt_list_t * list, int size) -{ - usbdev_pkt_t *pkt = alloc_packet(ep, size, NULL); - if (!pkt) - return NULL; - - link_tail(ep, list, pkt); - return pkt; -} - - -/* - * Unlink and free a packet from the head of the enpoint's - * packet list. EP spinlock must be held when calling. - */ -static inline void -free_packet(pkt_list_t * list) -{ - kfree(unlink_head(list)); -} - -/* EP spinlock must be held when calling. */ -static inline void -flush_pkt_list(pkt_list_t * list) -{ - while (list->count) - free_packet(list); -} - -/* EP spinlock must be held when calling */ -static inline void -flush_write_fifo(endpoint_t * ep) -{ - if (ep->reg->write_fifo_status >= 0) { - au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | - USBDEV_FSTAT_OF, - ep->reg->write_fifo_status); - //udelay(100); - //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, - // ep->reg->write_fifo_status); - } -} - -/* EP spinlock must be held when calling */ -static inline void -flush_read_fifo(endpoint_t * ep) -{ - if (ep->reg->read_fifo_status >= 0) { - au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | - USBDEV_FSTAT_OF, - ep->reg->read_fifo_status); - //udelay(100); - //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, - // ep->reg->read_fifo_status); - } -} - - -/* EP spinlock must be held when calling. */ -static void -endpoint_flush(endpoint_t * ep) -{ - // First, flush all packets - flush_pkt_list(&ep->inlist); - flush_pkt_list(&ep->outlist); - - // Now flush the endpoint's h/w FIFO(s) - flush_write_fifo(ep); - flush_read_fifo(ep); -} - -/* EP spinlock must be held when calling. */ -static void -endpoint_stall(endpoint_t * ep) -{ - u32 cs; - - warn("%s", __FUNCTION__); - - cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL; - au_writel(cs, ep->reg->ctrl_stat); -} - -/* EP spinlock must be held when calling. */ -static void -endpoint_unstall(endpoint_t * ep) -{ - u32 cs; - - warn("%s", __FUNCTION__); - - cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL; - au_writel(cs, ep->reg->ctrl_stat); -} - -static void -endpoint_reset_datatoggle(endpoint_t * ep) -{ - // FIXME: is this possible? -} - - -/* EP spinlock must be held when calling. */ -static int -endpoint_fifo_read(endpoint_t * ep) -{ - int read_count = 0; - u8 *bufptr; - usbdev_pkt_t *pkt = ep->outlist.tail; - - if (!pkt) - return -EINVAL; - - bufptr = &pkt->payload[pkt->size]; - while (au_readl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) { - *bufptr++ = au_readl(ep->reg->read_fifo) & 0xff; - read_count++; - pkt->size++; - } - - return read_count; -} - -#if 0 -/* EP spinlock must be held when calling. */ -static int -endpoint_fifo_write(endpoint_t * ep, int index) -{ - int write_count = 0; - u8 *bufptr; - usbdev_pkt_t *pkt = ep->inlist.head; - - if (!pkt) - return -EINVAL; - - bufptr = &pkt->payload[index]; - while ((au_readl(ep->reg->write_fifo_status) & - USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) { - if (bufptr < pkt->payload + pkt->size) { - au_writel(*bufptr++, ep->reg->write_fifo); - write_count++; - } else { - break; - } - } - - return write_count; -} -#endif - -/* - * This routine is called to restart transmission of a packet. - * The endpoint's TSIZE must be set to the new packet's size, - * and DMA to the write FIFO needs to be restarted. - * EP spinlock must be held when calling. - */ -static void -kickstart_send_packet(endpoint_t * ep) -{ - u32 cs; - usbdev_pkt_t *pkt = ep->inlist.head; - - vdbg("%s: ep%d, pkt=%p", __FUNCTION__, ep->address, pkt); - - if (!pkt) { - err("%s: head=NULL! list->count=%d", __FUNCTION__, - ep->inlist.count); - return; - } - - dma_cache_wback_inv((unsigned long)pkt->payload, pkt->size); - - /* - * make sure FIFO is empty - */ - flush_write_fifo(ep); - - cs = au_readl(ep->reg->ctrl_stat) & USBDEV_CS_STALL; - cs |= (pkt->size << USBDEV_CS_TSIZE_BIT); - au_writel(cs, ep->reg->ctrl_stat); - - if (get_dma_active_buffer(ep->indma) == 1) { - set_dma_count1(ep->indma, pkt->size); - set_dma_addr1(ep->indma, virt_to_phys(pkt->payload)); - enable_dma_buffer1(ep->indma); // reenable - } else { - set_dma_count0(ep->indma, pkt->size); - set_dma_addr0(ep->indma, virt_to_phys(pkt->payload)); - enable_dma_buffer0(ep->indma); // reenable - } - if (dma_halted(ep->indma)) - start_dma(ep->indma); -} - - -/* - * This routine is called when a packet in the inlist has been - * completed. Frees the completed packet and starts sending the - * next. EP spinlock must be held when calling. - */ -static usbdev_pkt_t * -send_packet_complete(endpoint_t * ep) -{ - usbdev_pkt_t *pkt = unlink_head(&ep->inlist); - - if (pkt) { - pkt->status = - (au_readl(ep->reg->ctrl_stat) & USBDEV_CS_NAK) ? - PKT_STATUS_NAK : PKT_STATUS_ACK; - - vdbg("%s: ep%d, %s pkt=%p, list count=%d", __FUNCTION__, - ep->address, (pkt->status & PKT_STATUS_NAK) ? - "NAK" : "ACK", pkt, ep->inlist.count); - } - - /* - * The write fifo should already be drained if things are - * working right, but flush it anyway just in case. - */ - flush_write_fifo(ep); - - // begin transmitting next packet in the inlist - if (ep->inlist.count) { - kickstart_send_packet(ep); - } - - return pkt; -} - -/* - * Add a new packet to the tail of the given ep's packet - * inlist. The transmit complete interrupt frees packets from - * the head of this list. EP spinlock must be held when calling. - */ -static int -send_packet(struct usb_dev* dev, usbdev_pkt_t *pkt, int async) -{ - pkt_list_t *list; - endpoint_t* ep; - - if (!pkt || !(ep = epaddr_to_ep(dev, pkt->ep_addr))) - return -EINVAL; - - if (!pkt->size) - return 0; - - list = &ep->inlist; - - if (!async && list->count) { - halt_dma(ep->indma); - flush_pkt_list(list); - } - - link_tail(ep, list, pkt); - - vdbg("%s: ep%d, pkt=%p, size=%d, list count=%d", __FUNCTION__, - ep->address, pkt, pkt->size, list->count); - - if (list->count == 1) { - /* - * if the packet count is one, it means the list was empty, - * and no more data will go out this ep until we kick-start - * it again. - */ - kickstart_send_packet(ep); - } - - return pkt->size; -} - -/* - * This routine is called to restart reception of a packet. - * EP spinlock must be held when calling. - */ -static void -kickstart_receive_packet(endpoint_t * ep) -{ - usbdev_pkt_t *pkt; - - // get and link a new packet for next reception - if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) { - err("%s: could not alloc new packet", __FUNCTION__); - return; - } - - if (get_dma_active_buffer(ep->outdma) == 1) { - clear_dma_done1(ep->outdma); - set_dma_count1(ep->outdma, ep->max_pkt_size); - set_dma_count0(ep->outdma, 0); - set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload)); - enable_dma_buffer1(ep->outdma); // reenable - } else { - clear_dma_done0(ep->outdma); - set_dma_count0(ep->outdma, ep->max_pkt_size); - set_dma_count1(ep->outdma, 0); - set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload)); - enable_dma_buffer0(ep->outdma); // reenable - } - if (dma_halted(ep->outdma)) - start_dma(ep->outdma); -} - - -/* - * This routine is called when a packet in the outlist has been - * completed (received) and we need to prepare for a new packet - * to be received. Halts DMA and computes the packet size from the - * remaining DMA counter. Then prepares a new packet for reception - * and restarts DMA. FIXME: what if another packet comes in - * on top of the completed packet? Counter would be wrong. - * EP spinlock must be held when calling. - */ -static usbdev_pkt_t * -receive_packet_complete(endpoint_t * ep) -{ - usbdev_pkt_t *pkt = ep->outlist.tail; - u32 cs; - - halt_dma(ep->outdma); - - cs = au_readl(ep->reg->ctrl_stat); - - if (!pkt) - return NULL; - - pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma); - if (pkt->size) - dma_cache_inv((unsigned long)pkt->payload, pkt->size); - /* - * need to pull out any remaining bytes in the FIFO. - */ - endpoint_fifo_read(ep); - /* - * should be drained now, but flush anyway just in case. - */ - flush_read_fifo(ep); - - pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK; - if (ep->address == 0 && (cs & USBDEV_CS_SU)) - pkt->status |= PKT_STATUS_SU; - - vdbg("%s: ep%d, %s pkt=%p, size=%d", __FUNCTION__, - ep->address, (pkt->status & PKT_STATUS_NAK) ? - "NAK" : "ACK", pkt, pkt->size); - - kickstart_receive_packet(ep); - - return pkt; -} - - -/* - **************************************************************************** - * Here starts the standard device request handlers. They are - * all called by do_setup() via a table of function pointers. - **************************************************************************** - */ - -static ep0_stage_t -do_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - switch (setup->bRequestType) { - case 0x80: // Device - // FIXME: send device status - break; - case 0x81: // Interface - // FIXME: send interface status - break; - case 0x82: // End Point - // FIXME: send endpoint status - break; - default: - // Invalid Command - endpoint_stall(&dev->ep[0]); // Stall End Point 0 - break; - } - - return STATUS_STAGE; -} - -static ep0_stage_t -do_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - switch (setup->bRequestType) { - case 0x00: // Device - if ((le16_to_cpu(setup->wValue) & 0xff) == 1) - dev->remote_wakeup_en = 0; - else - endpoint_stall(&dev->ep[0]); - break; - case 0x02: // End Point - if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { - endpoint_t *ep = - epaddr_to_ep(dev, - le16_to_cpu(setup->wIndex) & 0xff); - - endpoint_unstall(ep); - endpoint_reset_datatoggle(ep); - } else - endpoint_stall(&dev->ep[0]); - break; - } - - return SETUP_STAGE; -} - -static ep0_stage_t -do_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - // Invalid request, stall End Point 0 - endpoint_stall(&dev->ep[0]); - return SETUP_STAGE; -} - -static ep0_stage_t -do_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - switch (setup->bRequestType) { - case 0x00: // Device - if ((le16_to_cpu(setup->wValue) & 0xff) == 1) - dev->remote_wakeup_en = 1; - else - endpoint_stall(&dev->ep[0]); - break; - case 0x02: // End Point - if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { - endpoint_t *ep = - epaddr_to_ep(dev, - le16_to_cpu(setup->wIndex) & 0xff); - - endpoint_stall(ep); - } else - endpoint_stall(&dev->ep[0]); - break; - } - - return SETUP_STAGE; -} - -static ep0_stage_t -do_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - int new_state = dev->state; - int new_addr = le16_to_cpu(setup->wValue); - - dbg("%s: our address=%d", __FUNCTION__, new_addr); - - if (new_addr > 127) { - // usb spec doesn't tell us what to do, so just go to - // default state - new_state = DEFAULT; - dev->address = 0; - } else if (dev->address != new_addr) { - dev->address = new_addr; - new_state = ADDRESS; - } - - if (dev->state != new_state) { - dev->state = new_state; - /* inform function layer of usbdev state change */ - dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); - } - - return SETUP_STAGE; -} - -static ep0_stage_t -do_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - int strnum, desc_len = le16_to_cpu(setup->wLength); - - switch (le16_to_cpu(setup->wValue) >> 8) { - case USB_DT_DEVICE: - // send device descriptor! - desc_len = desc_len > dev->dev_desc->bLength ? - dev->dev_desc->bLength : desc_len; - dbg("sending device desc, size=%d", desc_len); - send_packet(dev, alloc_packet(&dev->ep[0], desc_len, - dev->dev_desc), 0); - break; - case USB_DT_CONFIG: - // If the config descr index in low-byte of - // setup->wValue is valid, send config descr, - // otherwise stall ep0. - if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { - // send config descriptor! - if (desc_len <= USB_DT_CONFIG_SIZE) { - dbg("sending partial config desc, size=%d", - desc_len); - send_packet(dev, - alloc_packet(&dev->ep[0], - desc_len, - dev->conf_desc), - 0); - } else { - int len = le16_to_cpu(dev->conf_desc->wTotalLength); - dbg("sending whole config desc," - " size=%d, our size=%d", desc_len, len); - desc_len = desc_len > len ? len : desc_len; - send_packet(dev, - alloc_packet(&dev->ep[0], - desc_len, - dev->full_conf_desc), - 0); - } - } else - endpoint_stall(&dev->ep[0]); - break; - case USB_DT_STRING: - // If the string descr index in low-byte of setup->wValue - // is valid, send string descr, otherwise stall ep0. - strnum = le16_to_cpu(setup->wValue) & 0xff; - if (strnum >= 0 && strnum < 6) { - struct usb_string_descriptor *desc = - dev->str_desc[strnum]; - desc_len = desc_len > desc->bLength ? - desc->bLength : desc_len; - dbg("sending string desc %d", strnum); - send_packet(dev, - alloc_packet(&dev->ep[0], desc_len, - desc), 0); - } else - endpoint_stall(&dev->ep[0]); - break; - default: - // Invalid request - err("invalid get desc=%d, stalled", - le16_to_cpu(setup->wValue) >> 8); - endpoint_stall(&dev->ep[0]); // Stall endpoint 0 - break; - } - - return STATUS_STAGE; -} - -static ep0_stage_t -do_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - // TODO: implement - // there will be an OUT data stage (the descriptor to set) - return DATA_STAGE; -} - -static ep0_stage_t -do_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - // send dev->configuration - dbg("sending config"); - send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration), - 0); - return STATUS_STAGE; -} - -static ep0_stage_t -do_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - // set active config to low-byte of setup->wValue - dev->configuration = le16_to_cpu(setup->wValue) & 0xff; - dbg("set config, config=%d", dev->configuration); - if (!dev->configuration && dev->state > DEFAULT) { - dev->state = ADDRESS; - /* inform function layer of usbdev state change */ - dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); - } else if (dev->configuration == 1) { - dev->state = CONFIGURED; - /* inform function layer of usbdev state change */ - dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); - } else { - // FIXME: "respond with request error" - how? - } - - return SETUP_STAGE; -} - -static ep0_stage_t -do_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - // interface must be zero. - if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) { - // FIXME: respond with "request error". how? - } else if (dev->state == CONFIGURED) { - // send dev->alternate_setting - dbg("sending alt setting"); - send_packet(dev, alloc_packet(&dev->ep[0], 1, - &dev->alternate_setting), 0); - } - - return STATUS_STAGE; - -} - -static ep0_stage_t -do_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - if (dev->state == ADDRESS) { - // FIXME: respond with "request error". how? - } else if (dev->state == CONFIGURED) { - dev->interface = le16_to_cpu(setup->wIndex) & 0xff; - dev->alternate_setting = - le16_to_cpu(setup->wValue) & 0xff; - // interface and alternate_setting must be zero - if (dev->interface || dev->alternate_setting) { - // FIXME: respond with "request error". how? - } - } - - return SETUP_STAGE; -} - -static ep0_stage_t -do_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - // TODO - return SETUP_STAGE; -} - -typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev, - struct usb_ctrlrequest* setup); - - -/* Table of the standard device request handlers */ -static const req_method_t req_method[] = { - do_get_status, - do_clear_feature, - do_reserved, - do_set_feature, - do_reserved, - do_set_address, - do_get_descriptor, - do_set_descriptor, - do_get_configuration, - do_set_configuration, - do_get_interface, - do_set_interface, - do_synch_frame -}; - - -// SETUP packet request dispatcher -static void -do_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup) -{ - req_method_t m; - - dbg("%s: req %d %s", __FUNCTION__, setup->bRequestType, - get_std_req_name(setup->bRequestType)); - - if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD || - (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) { - err("%s: invalid requesttype 0x%02x", __FUNCTION__, - setup->bRequestType); - return; - } - - if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength) - dbg("%s: OUT phase! length=%d", __FUNCTION__, setup->wLength); - - if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t)) - m = req_method[setup->bRequestType]; - else - m = do_reserved; - - dev->ep0_stage = (*m)(dev, setup); -} - -/* - * A SETUP, DATA0, or DATA1 packet has been received - * on the default control endpoint's fifo. - */ -static void -process_ep0_receive (struct usb_dev* dev) -{ - endpoint_t *ep0 = &dev->ep[0]; - usbdev_pkt_t *pkt; - - spin_lock(&ep0->lock); - - // complete packet and prepare a new packet - pkt = receive_packet_complete(ep0); - if (!pkt) { - // FIXME: should put a warn/err here. - spin_unlock(&ep0->lock); - return; - } - - // unlink immediately from endpoint. - unlink_head(&ep0->outlist); - - // override current stage if h/w says it's a setup packet - if (pkt->status & PKT_STATUS_SU) - dev->ep0_stage = SETUP_STAGE; - - switch (dev->ep0_stage) { - case SETUP_STAGE: - vdbg("SU bit is %s in setup stage", - (pkt->status & PKT_STATUS_SU) ? "set" : "not set"); - - if (pkt->size == sizeof(struct usb_ctrlrequest)) { -#ifdef VDEBUG - if (pkt->status & PKT_STATUS_ACK) - vdbg("received SETUP"); - else - vdbg("received NAK SETUP"); -#endif - do_setup(dev, (struct usb_ctrlrequest*)pkt->payload); - } else - err("%s: wrong size SETUP received", __FUNCTION__); - break; - case DATA_STAGE: - /* - * this setup has an OUT data stage. Of the standard - * device requests, only set_descriptor has this stage, - * so this packet is that descriptor. TODO: drop it for - * now, set_descriptor not implemented. - * - * Need to place a byte in the write FIFO here, to prepare - * to send a zero-length DATA ack packet to the host in the - * STATUS stage. - */ - au_writel(0, ep0->reg->write_fifo); - dbg("received OUT stage DATAx on EP0, size=%d", pkt->size); - dev->ep0_stage = SETUP_STAGE; - break; - case STATUS_STAGE: - // this setup had an IN data stage, and host is ACK'ing - // the packet we sent during that stage. - if (pkt->size != 0) - warn("received non-zero ACK on EP0??"); -#ifdef VDEBUG - else - vdbg("received ACK on EP0"); -#endif - dev->ep0_stage = SETUP_STAGE; - break; - } - - spin_unlock(&ep0->lock); - // we're done processing the packet, free it - kfree(pkt); -} - - -/* - * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5) - */ -static void -process_ep_receive (struct usb_dev* dev, endpoint_t *ep) -{ - usbdev_pkt_t *pkt; - - spin_lock(&ep->lock); - pkt = receive_packet_complete(ep); - spin_unlock(&ep->lock); - - dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data); -} - - - -/* This ISR handles the receive complete and suspend events */ -static void req_sus_intr (int irq, void *dev_id) -{ - struct usb_dev *dev = (struct usb_dev *) dev_id; - u32 status; - - status = au_readl(USBD_INTSTAT); - au_writel(status, USBD_INTSTAT); // ack'em - - if (status & (1<<0)) - process_ep0_receive(dev); - if (status & (1<<4)) - process_ep_receive(dev, &dev->ep[4]); - if (status & (1<<5)) - process_ep_receive(dev, &dev->ep[5]); -} - - -/* This ISR handles the DMA done events on EP0 */ -static void dma_done_ep0_intr(int irq, void *dev_id) -{ - struct usb_dev *dev = (struct usb_dev *) dev_id; - usbdev_pkt_t* pkt; - endpoint_t *ep0 = &dev->ep[0]; - u32 cs0, buff_done; - - spin_lock(&ep0->lock); - cs0 = au_readl(ep0->reg->ctrl_stat); - - // first check packet transmit done - if ((buff_done = get_dma_buffer_done(ep0->indma)) != 0) { - // transmitted a DATAx packet during DATA stage - // on control endpoint 0 - // clear DMA done bit - if (buff_done & DMA_D0) - clear_dma_done0(ep0->indma); - if (buff_done & DMA_D1) - clear_dma_done1(ep0->indma); - - pkt = send_packet_complete(ep0); - kfree(pkt); - } - - /* - * Now check packet receive done. Shouldn't get these, - * the receive packet complete intr should happen - * before the DMA done intr occurs. - */ - if ((buff_done = get_dma_buffer_done(ep0->outdma)) != 0) { - // clear DMA done bit - if (buff_done & DMA_D0) - clear_dma_done0(ep0->outdma); - if (buff_done & DMA_D1) - clear_dma_done1(ep0->outdma); - - //process_ep0_receive(dev); - } - - spin_unlock(&ep0->lock); -} - -/* This ISR handles the DMA done events on endpoints 2,3,4,5 */ -static void dma_done_ep_intr(int irq, void *dev_id) -{ - struct usb_dev *dev = (struct usb_dev *) dev_id; - int i; - - for (i = 2; i < 6; i++) { - u32 buff_done; - usbdev_pkt_t* pkt; - endpoint_t *ep = &dev->ep[i]; - - if (!ep->active) continue; - - spin_lock(&ep->lock); - - if (ep->direction == USB_DIR_IN) { - buff_done = get_dma_buffer_done(ep->indma); - if (buff_done != 0) { - // transmitted a DATAx pkt on the IN ep - // clear DMA done bit - if (buff_done & DMA_D0) - clear_dma_done0(ep->indma); - if (buff_done & DMA_D1) - clear_dma_done1(ep->indma); - - pkt = send_packet_complete(ep); - - spin_unlock(&ep->lock); - dev->func_cb(CB_PKT_COMPLETE, - (unsigned long)pkt, - dev->cb_data); - spin_lock(&ep->lock); - } - } else { - /* - * Check packet receive done (OUT ep). Shouldn't get - * these, the rx packet complete intr should happen - * before the DMA done intr occurs. - */ - buff_done = get_dma_buffer_done(ep->outdma); - if (buff_done != 0) { - // received a DATAx pkt on the OUT ep - // clear DMA done bit - if (buff_done & DMA_D0) - clear_dma_done0(ep->outdma); - if (buff_done & DMA_D1) - clear_dma_done1(ep->outdma); - - //process_ep_receive(dev, ep); - } - } - - spin_unlock(&ep->lock); - } -} - - -/*************************************************************************** - * Here begins the external interface functions - *************************************************************************** - */ - -/* - * allocate a new packet - */ -int -usbdev_alloc_packet(int ep_addr, int data_size, usbdev_pkt_t** pkt) -{ - endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr); - usbdev_pkt_t* lpkt = NULL; - - if (!ep || !ep->active || ep->address < 2) - return -ENODEV; - if (data_size > ep->max_pkt_size) - return -EINVAL; - - lpkt = *pkt = alloc_packet(ep, data_size, NULL); - if (!lpkt) - return -ENOMEM; - return 0; -} - - -/* - * packet send - */ -int -usbdev_send_packet(int ep_addr, usbdev_pkt_t * pkt) -{ - unsigned long flags; - int count; - endpoint_t * ep; - - if (!pkt || !(ep = epaddr_to_ep(&usbdev, pkt->ep_addr)) || - !ep->active || ep->address < 2) - return -ENODEV; - if (ep->direction != USB_DIR_IN) - return -EINVAL; - - spin_lock_irqsave(&ep->lock, flags); - count = send_packet(&usbdev, pkt, 1); - spin_unlock_irqrestore(&ep->lock, flags); - - return count; -} - -/* - * packet receive - */ -int -usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt) -{ - unsigned long flags; - usbdev_pkt_t* lpkt = NULL; - endpoint_t *ep = epaddr_to_ep(&usbdev, ep_addr); - - if (!ep || !ep->active || ep->address < 2) - return -ENODEV; - if (ep->direction != USB_DIR_OUT) - return -EINVAL; - - spin_lock_irqsave(&ep->lock, flags); - if (ep->outlist.count > 1) - lpkt = unlink_head(&ep->outlist); - spin_unlock_irqrestore(&ep->lock, flags); - - if (!lpkt) { - /* no packet available */ - *pkt = NULL; - return -ENODATA; - } - - *pkt = lpkt; - - return lpkt->size; -} - - -/* - * return total queued byte count on the endpoint. - */ -int -usbdev_get_byte_count(int ep_addr) -{ - unsigned long flags; - pkt_list_t *list; - usbdev_pkt_t *scan; - int count = 0; - endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr); - - if (!ep || !ep->active || ep->address < 2) - return -ENODEV; - - if (ep->direction == USB_DIR_IN) { - list = &ep->inlist; - - spin_lock_irqsave(&ep->lock, flags); - for (scan = list->head; scan; scan = scan->next) - count += scan->size; - spin_unlock_irqrestore(&ep->lock, flags); - } else { - list = &ep->outlist; - - spin_lock_irqsave(&ep->lock, flags); - if (list->count > 1) { - for (scan = list->head; scan != list->tail; - scan = scan->next) - count += scan->size; - } - spin_unlock_irqrestore(&ep->lock, flags); - } - - return count; -} - - -void -usbdev_exit(void) -{ - endpoint_t *ep; - int i; - - au_writel(0, USBD_INTEN); // disable usb dev ints - au_writel(0, USBD_ENABLE); // disable usb dev - - free_irq(AU1000_USB_DEV_REQ_INT, &usbdev); - free_irq(AU1000_USB_DEV_SUS_INT, &usbdev); - - // free all control endpoint resources - ep = &usbdev.ep[0]; - free_au1000_dma(ep->indma); - free_au1000_dma(ep->outdma); - endpoint_flush(ep); - - // free ep resources - for (i = 2; i < 6; i++) { - ep = &usbdev.ep[i]; - if (!ep->active) continue; - - if (ep->direction == USB_DIR_IN) { - free_au1000_dma(ep->indma); - } else { - free_au1000_dma(ep->outdma); - } - endpoint_flush(ep); - } - - kfree(usbdev.full_conf_desc); -} - -int -usbdev_init(struct usb_device_descriptor* dev_desc, - struct usb_config_descriptor* config_desc, - struct usb_interface_descriptor* if_desc, - struct usb_endpoint_descriptor* ep_desc, - struct usb_string_descriptor* str_desc[], - void (*cb)(usbdev_cb_type_t, unsigned long, void *), - void* cb_data) -{ - endpoint_t *ep0; - int i, ret=0; - u8* fcd; - - if (dev_desc->bNumConfigurations > 1 || - config_desc->bNumInterfaces > 1 || - if_desc->bNumEndpoints > 4) { - err("Only one config, one i/f, and no more " - "than 4 ep's allowed"); - ret = -EINVAL; - goto out; - } - - if (!cb) { - err("Function-layer callback required"); - ret = -EINVAL; - goto out; - } - - if (dev_desc->bMaxPacketSize0 != USBDEV_EP0_MAX_PACKET_SIZE) { - warn("EP0 Max Packet size must be %d", - USBDEV_EP0_MAX_PACKET_SIZE); - dev_desc->bMaxPacketSize0 = USBDEV_EP0_MAX_PACKET_SIZE; - } - - memset(&usbdev, 0, sizeof(struct usb_dev)); - - usbdev.state = DEFAULT; - usbdev.dev_desc = dev_desc; - usbdev.if_desc = if_desc; - usbdev.conf_desc = config_desc; - for (i=0; i<6; i++) - usbdev.str_desc[i] = str_desc[i]; - usbdev.func_cb = cb; - usbdev.cb_data = cb_data; - - /* Initialize default control endpoint */ - ep0 = &usbdev.ep[0]; - ep0->active = 1; - ep0->type = CONTROL_EP; - ep0->max_pkt_size = USBDEV_EP0_MAX_PACKET_SIZE; - spin_lock_init(&ep0->lock); - ep0->desc = NULL; // ep0 has no descriptor - ep0->address = 0; - ep0->direction = 0; - ep0->reg = &ep_reg[0]; - - /* Initialize the other requested endpoints */ - for (i = 0; i < if_desc->bNumEndpoints; i++) { - struct usb_endpoint_descriptor* epd = &ep_desc[i]; - endpoint_t *ep; - - if ((epd->bEndpointAddress & 0x80) == USB_DIR_IN) { - ep = &usbdev.ep[2]; - ep->address = 2; - if (ep->active) { - ep = &usbdev.ep[3]; - ep->address = 3; - if (ep->active) { - err("too many IN ep's requested"); - ret = -ENODEV; - goto out; - } - } - } else { - ep = &usbdev.ep[4]; - ep->address = 4; - if (ep->active) { - ep = &usbdev.ep[5]; - ep->address = 5; - if (ep->active) { - err("too many OUT ep's requested"); - ret = -ENODEV; - goto out; - } - } - } - - ep->active = 1; - epd->bEndpointAddress &= ~0x0f; - epd->bEndpointAddress |= (u8)ep->address; - ep->direction = epd->bEndpointAddress & 0x80; - ep->type = epd->bmAttributes & 0x03; - ep->max_pkt_size = le16_to_cpu(epd->wMaxPacketSize); - spin_lock_init(&ep->lock); - ep->desc = epd; - ep->reg = &ep_reg[ep->address]; - } - - /* - * initialize the full config descriptor - */ - usbdev.full_conf_desc = fcd = kmalloc(le16_to_cpu(config_desc->wTotalLength), - ALLOC_FLAGS); - if (!fcd) { - err("failed to alloc full config descriptor"); - ret = -ENOMEM; - goto out; - } - - memcpy(fcd, config_desc, USB_DT_CONFIG_SIZE); - fcd += USB_DT_CONFIG_SIZE; - memcpy(fcd, if_desc, USB_DT_INTERFACE_SIZE); - fcd += USB_DT_INTERFACE_SIZE; - for (i = 0; i < if_desc->bNumEndpoints; i++) { - memcpy(fcd, &ep_desc[i], USB_DT_ENDPOINT_SIZE); - fcd += USB_DT_ENDPOINT_SIZE; - } - - /* Now we're ready to enable the controller */ - au_writel(0x0002, USBD_ENABLE); - udelay(100); - au_writel(0x0003, USBD_ENABLE); - udelay(100); - - /* build and send config table based on ep descriptors */ - for (i = 0; i < 6; i++) { - endpoint_t *ep; - if (i == 1) - continue; // skip dummy ep - ep = &usbdev.ep[i]; - if (ep->active) { - au_writel((ep->address << 4) | 0x04, USBD_CONFIG); - au_writel(((ep->max_pkt_size & 0x380) >> 7) | - (ep->direction >> 4) | (ep->type << 4), - USBD_CONFIG); - au_writel((ep->max_pkt_size & 0x7f) << 1, USBD_CONFIG); - au_writel(0x00, USBD_CONFIG); - au_writel(ep->address, USBD_CONFIG); - } else { - u8 dir = (i==2 || i==3) ? DIR_IN : DIR_OUT; - au_writel((i << 4) | 0x04, USBD_CONFIG); - au_writel(((16 & 0x380) >> 7) | dir | - (BULK_EP << 4), USBD_CONFIG); - au_writel((16 & 0x7f) << 1, USBD_CONFIG); - au_writel(0x00, USBD_CONFIG); - au_writel(i, USBD_CONFIG); - } - } - - /* - * Enable Receive FIFO Complete interrupts only. Transmit - * complete is being handled by the DMA done interrupts. - */ - au_writel(0x31, USBD_INTEN); - - /* - * Controller is now enabled, request DMA and IRQ - * resources. - */ - - /* request the USB device transfer complete interrupt */ - if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, IRQF_DISABLED, - "USBdev req", &usbdev)) { - err("Can't get device request intr"); - ret = -ENXIO; - goto out; - } - /* request the USB device suspend interrupt */ - if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, IRQF_DISABLED, - "USBdev sus", &usbdev)) { - err("Can't get device suspend intr"); - ret = -ENXIO; - goto out; - } - - /* Request EP0 DMA and IRQ */ - if ((ep0->indma = request_au1000_dma(ep_dma_id[0].id, - ep_dma_id[0].str, - dma_done_ep0_intr, - IRQF_DISABLED, - &usbdev)) < 0) { - err("Can't get %s DMA", ep_dma_id[0].str); - ret = -ENXIO; - goto out; - } - if ((ep0->outdma = request_au1000_dma(ep_dma_id[1].id, - ep_dma_id[1].str, - NULL, 0, NULL)) < 0) { - err("Can't get %s DMA", ep_dma_id[1].str); - ret = -ENXIO; - goto out; - } - - // Flush the ep0 buffers and FIFOs - endpoint_flush(ep0); - // start packet reception on ep0 - kickstart_receive_packet(ep0); - - /* Request DMA and IRQ for the other endpoints */ - for (i = 2; i < 6; i++) { - endpoint_t *ep = &usbdev.ep[i]; - if (!ep->active) - continue; - - // Flush the endpoint buffers and FIFOs - endpoint_flush(ep); - - if (ep->direction == USB_DIR_IN) { - ep->indma = - request_au1000_dma(ep_dma_id[ep->address].id, - ep_dma_id[ep->address].str, - dma_done_ep_intr, - IRQF_DISABLED, - &usbdev); - if (ep->indma < 0) { - err("Can't get %s DMA", - ep_dma_id[ep->address].str); - ret = -ENXIO; - goto out; - } - } else { - ep->outdma = - request_au1000_dma(ep_dma_id[ep->address].id, - ep_dma_id[ep->address].str, - NULL, 0, NULL); - if (ep->outdma < 0) { - err("Can't get %s DMA", - ep_dma_id[ep->address].str); - ret = -ENXIO; - goto out; - } - - // start packet reception on OUT endpoint - kickstart_receive_packet(ep); - } - } - - out: - if (ret) - usbdev_exit(); - return ret; -} - -EXPORT_SYMBOL(usbdev_init); -EXPORT_SYMBOL(usbdev_exit); -EXPORT_SYMBOL(usbdev_alloc_packet); -EXPORT_SYMBOL(usbdev_receive_packet); -EXPORT_SYMBOL(usbdev_send_packet); -EXPORT_SYMBOL(usbdev_get_byte_count); diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c index 7a79293f852..8b08edb977b 100644 --- a/arch/mips/au1000/db1x00/board_setup.c +++ b/arch/mips/au1000/db1x00/board_setup.c @@ -58,11 +58,6 @@ void __init board_setup(void) pin_func = 0; /* not valid for 1550 */ -#ifdef CONFIG_AU1X00_USB_DEVICE - // 2nd USB port is USB device - pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); - au_writel(pin_func, SYS_PINFUNC); -#endif #if defined(CONFIG_IRDA) && (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100)) /* set IRFIRSEL instead of GPIO15 */ diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c index e917e54fc68..13f9bf5f91a 100644 --- a/arch/mips/au1000/mtx-1/board_setup.c +++ b/arch/mips/au1000/mtx-1/board_setup.c @@ -51,15 +51,11 @@ void board_reset (void) void __init board_setup(void) { -#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) -#ifdef CONFIG_AU1X00_USB_DEVICE - // 2nd USB port is USB device - au_writel(au_readl(SYS_PINFUNC) & (u32)(~0x8000), SYS_PINFUNC); -#endif +#ifdef CONFIG_USB_OHCI // enable USB power switch au_writel( au_readl(GPIO2_DIR) | 0x10, GPIO2_DIR ); au_writel( 0x100000, GPIO2_OUTPUT ); -#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#endif // defined (CONFIG_USB_OHCI) #ifdef CONFIG_PCI #if defined(__MIPSEB__) diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c index 1cf18e16ab5..824cfafaff9 100644 --- a/arch/mips/au1000/pb1000/board_setup.c +++ b/arch/mips/au1000/pb1000/board_setup.c @@ -54,7 +54,7 @@ void __init board_setup(void) au_writel(0, SYS_PINSTATERD); udelay(100); -#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#ifdef CONFIG_USB_OHCI /* zero and disable FREQ2 */ sys_freqctrl = au_readl(SYS_FREQCTRL0); sys_freqctrl &= ~0xFFF00000; @@ -104,23 +104,19 @@ void __init board_setup(void) */ #ifdef CONFIG_USB_OHCI sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); -#endif -#ifdef CONFIG_AU1X00_USB_DEVICE - sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); #endif au_writel(sys_clksrc, SYS_CLKSRC); // configure pins GPIO[14:9] as GPIO pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080); -#ifndef CONFIG_AU1X00_USB_DEVICE // 2nd USB port is USB host pin_func |= 0x8000; -#endif + au_writel(pin_func, SYS_PINFUNC); au_writel(0x2800, SYS_TRIOUTCLR); au_writel(0x0030, SYS_OUTPUTCLR); -#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#endif // defined (CONFIG_USB_OHCI) // make gpio 15 an input (for interrupt line) pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x100); diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c index db27b9331ff..2d1533f116c 100644 --- a/arch/mips/au1000/pb1100/board_setup.c +++ b/arch/mips/au1000/pb1100/board_setup.c @@ -55,7 +55,7 @@ void __init board_setup(void) au_writel(0, SYS_PININPUTEN); udelay(100); -#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#ifdef CONFIG_USB_OHCI // configure pins GPIO[14:9] as GPIO pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80); @@ -92,12 +92,10 @@ void __init board_setup(void) // get USB Functionality pin state (device vs host drive pins) pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); -#ifndef CONFIG_AU1X00_USB_DEVICE // 2nd USB port is USB host pin_func |= 0x8000; -#endif au_writel(pin_func, SYS_PINFUNC); -#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#endif // defined (CONFIG_USB_OHCI) /* Enable sys bus clock divider when IDLE state or no bus activity. */ au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c index 1a9a293de6a..0ffdb4fd575 100644 --- a/arch/mips/au1000/pb1500/board_setup.c +++ b/arch/mips/au1000/pb1500/board_setup.c @@ -56,7 +56,7 @@ void __init board_setup(void) au_writel(0, SYS_PINSTATERD); udelay(100); -#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#ifdef CONFIG_USB_OHCI /* GPIO201 is input for PCMCIA card detect */ /* GPIO203 is input for PCMCIA interrupt request */ @@ -87,20 +87,15 @@ void __init board_setup(void) */ #ifdef CONFIG_USB_OHCI sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); -#endif -#ifdef CONFIG_AU1X00_USB_DEVICE - sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); #endif au_writel(sys_clksrc, SYS_CLKSRC); pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); -#ifndef CONFIG_AU1X00_USB_DEVICE // 2nd USB port is USB host pin_func |= 0x8000; -#endif au_writel(pin_func, SYS_PINFUNC); -#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#endif // defined (CONFIG_USB_OHCI) diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 741f8258075..9e672f63a0a 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -76,7 +76,6 @@ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y CONFIG_SOC_AU1100=y CONFIG_SOC_AU1X00=y CONFIG_SWAP_IO_SPACE=y -# CONFIG_AU1X00_USB_DEVICE is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 # diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 8576340714d..d0c0f4af1bf 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -75,7 +75,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y CONFIG_SOC_AU1500=y CONFIG_SOC_AU1X00=y -# CONFIG_AU1X00_USB_DEVICE is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 # diff --git a/include/asm-mips/mach-au1x00/au1000_usbdev.h b/include/asm-mips/mach-au1x00/au1000_usbdev.h deleted file mode 100644 index 05bc74bed0b..00000000000 --- a/include/asm-mips/mach-au1x00/au1000_usbdev.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Au1000 USB Device-Side 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. - */ - -#define USBDEV_REV 0x0110 // BCD -#define USBDEV_EP0_MAX_PACKET_SIZE 64 - -typedef enum { - ATTACHED = 0, - POWERED, - DEFAULT, - ADDRESS, - CONFIGURED -} usbdev_state_t; - -typedef enum { - CB_NEW_STATE = 0, - CB_PKT_COMPLETE -} usbdev_cb_type_t; - - -typedef struct usbdev_pkt { - int ep_addr; // ep addr this packet routed to - int size; // size of payload in bytes - unsigned status; // packet status - struct usbdev_pkt* next; // function layer can't touch this - u8 payload[0]; // the payload -} usbdev_pkt_t; - -#define PKT_STATUS_ACK (1<<0) -#define PKT_STATUS_NAK (1<<1) -#define PKT_STATUS_SU (1<<2) - -extern int usbdev_init(struct usb_device_descriptor* dev_desc, - struct usb_config_descriptor* config_desc, - struct usb_interface_descriptor* if_desc, - struct usb_endpoint_descriptor* ep_desc, - struct usb_string_descriptor* str_desc[], - void (*cb)(usbdev_cb_type_t, unsigned long, void *), - void* cb_data); - -extern void usbdev_exit(void); - -extern int usbdev_alloc_packet (int ep_addr, int data_size, - usbdev_pkt_t** pkt); -extern int usbdev_send_packet (int ep_addr, usbdev_pkt_t* pkt); -extern int usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt); -extern int usbdev_get_byte_count(int ep_addr); -- GitLab From f5c70dd7f384db4c524c35288d9be3ed61ac41a9 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Sun, 20 Aug 2006 22:55:52 +0900 Subject: [PATCH 0836/1619] [MIPS] Fix build errors related to wbflush.h on tx4927/tx4938. TX49 CPUs have a SYNC instruction so that CONFIG_CPU_HAS_WB is no longer needed. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/tx4927/common/tx4927_setup.c | 10 ---------- .../toshiba_rbtx4927/toshiba_rbtx4927_irq.c | 1 + arch/mips/tx4938/common/irq.c | 1 + arch/mips/tx4938/common/setup.c | 19 ------------------- arch/mips/tx4938/toshiba_rbtx4938/irq.c | 1 + 5 files changed, 3 insertions(+), 29 deletions(-) diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c index 3ace4037343..4658b2ae483 100644 --- a/arch/mips/tx4927/common/tx4927_setup.c +++ b/arch/mips/tx4927/common/tx4927_setup.c @@ -53,19 +53,9 @@ void __init tx4927_time_init(void); void dump_cp0(char *key); -void (*__wbflush) (void); - -static void tx4927_write_buffer_flush(void) -{ - __asm__ __volatile__ - ("sync\n\t" "nop\n\t" "loop: bc0f loop\n\t" "nop\n\t"); -} - - void __init plat_mem_setup(void) { board_time_init = tx4927_time_init; - __wbflush = tx4927_write_buffer_flush; #ifdef CONFIG_TOSHIBA_RBTX4927 { diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 3e24413d4c0..0c3c3f66823 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -129,6 +129,7 @@ JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthB #include #include #include +#include #include #include #ifdef CONFIG_RTC_DS1742 diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c index b6024749b8f..77fe2454f5b 100644 --- a/arch/mips/tx4938/common/irq.c +++ b/arch/mips/tx4938/common/irq.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /**********************************************************************************/ diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c index 71859c4fee8..f415a1f18fb 100644 --- a/arch/mips/tx4938/common/setup.c +++ b/arch/mips/tx4938/common/setup.c @@ -41,29 +41,10 @@ void __init tx4938_setup(void); void __init tx4938_time_init(void); void dump_cp0(char *key); -void (*__wbflush) (void); - -static void -tx4938_write_buffer_flush(void) -{ - mmiowb(); - - __asm__ __volatile__( - ".set push\n\t" - ".set noreorder\n\t" - "lw $0,%0\n\t" - "nop\n\t" - ".set pop" - : /* no output */ - : "m" (*(int *)KSEG1) - : "memory"); -} - void __init plat_mem_setup(void) { board_time_init = tx4938_time_init; - __wbflush = tx4938_write_buffer_flush; toshiba_rbtx4938_setup(); } diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index bbb3390e98f..102e473c10a 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c @@ -83,6 +83,7 @@ IRQ Device #include #include #include +#include #include #include -- GitLab From e04582b7bc70b40c57287cdc24f81964ee88f565 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 9 Oct 2006 00:10:01 +0900 Subject: [PATCH 0837/1619] [MIPS] Make sure cpu_has_fpu is used only in atomic context Make sure cpu_has_fpu (which uses smp_processor_id()) is used only in atomic context. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 2 +- arch/mips/kernel/process.c | 2 +- arch/mips/kernel/ptrace.c | 18 ++++++++++-------- arch/mips/kernel/ptrace32.c | 3 ++- arch/mips/kernel/traps.c | 16 +++++++++------- arch/mips/math-emu/cp1emu.c | 7 +++---- include/asm-mips/fpu.h | 6 ++++-- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 46ee5a68ab1..4ed37ba1973 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -107,7 +107,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", - cpu_has_fpu ? " FPU V%d.%d" : ""); + cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ? cpu_data[n].cputype : CPU_UNKNOWN], (version >> 4) & 0x0f, version & 0x0f, diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 045d987bc68..9f307eb1a31 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -115,7 +115,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) status |= KU_USER; regs->cp0_status = status; clear_used_math(); - lose_fpu(); + clear_fpu_owner(); if (cpu_has_dsp) __init_dsp(); regs->cp0_epc = pc; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 362d1728e53..258d74fd0b6 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -106,6 +106,7 @@ int ptrace_setregs (struct task_struct *child, __s64 __user *data) int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) { int i; + unsigned int tmp; if (!access_ok(VERIFY_WRITE, data, 33 * 8)) return -EIO; @@ -121,10 +122,10 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) __put_user (child->thread.fpu.fcr31, data + 64); + preempt_disable(); if (cpu_has_fpu) { - unsigned int flags, tmp; + unsigned int flags; - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); @@ -138,11 +139,11 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); write_c0_status(flags); } - preempt_enable(); - __put_user (tmp, data + 65); } else { - __put_user ((__u32) 0, data + 65); + tmp = 0; } + preempt_enable(); + __put_user (tmp, data + 65); return 0; } @@ -245,16 +246,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned int mtflags; #endif /* CONFIG_MIPS_MT_SMTC */ - if (!cpu_has_fpu) + preempt_disable(); + if (!cpu_has_fpu) { + preempt_enable(); break; + } #ifdef CONFIG_MIPS_MT_SMTC /* Read-modify-write of Status must be atomic */ local_irq_save(irqflags); mtflags = dmt(); #endif /* CONFIG_MIPS_MT_SMTC */ - - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index f40ecd8be05..d9a39c16945 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -175,7 +175,9 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) unsigned int mtflags; #endif /* CONFIG_MIPS_MT_SMTC */ + preempt_disable(); if (!cpu_has_fpu) { + preempt_enable(); tmp = 0; break; } @@ -186,7 +188,6 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) mtflags = dmt(); #endif /* CONFIG_MIPS_MT_SMTC */ - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b7292a56d4c..cce8313ec27 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -66,7 +66,7 @@ extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, - struct mips_fpu_struct *ctx); + struct mips_fpu_struct *ctx, int has_fpu); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); @@ -641,7 +641,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_enable(); /* Run the emulator */ - sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu); + sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); preempt_disable(); @@ -791,11 +791,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) set_used_math(); } - preempt_enable(); - - if (!cpu_has_fpu) { - int sig = fpu_emulator_cop1Handler(regs, - ¤t->thread.fpu); + if (cpu_has_fpu) { + preempt_enable(); + } else { + int sig; + preempt_enable(); + sig = fpu_emulator_cop1Handler(regs, + ¤t->thread.fpu, 0); if (sig) force_sig(sig, current); #ifdef CONFIG_MIPS_MT_FPAFF diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 3f0d5d26d50..80531b35cd6 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -38,8 +38,6 @@ #include #include -#include -#include #include #include #include @@ -1233,7 +1231,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return 0; } -int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx) +int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + int has_fpu) { unsigned long oldepc, prevepc; mips_instruction insn; @@ -1263,7 +1262,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx) ieee754_csr.rm = mips_rm[ieee754_csr.rm]; } - if (cpu_has_fpu) + if (has_fpu) break; if (sig) break; diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h index 58c561a9ec6..efef843b93f 100644 --- a/include/asm-mips/fpu.h +++ b/include/asm-mips/fpu.h @@ -134,9 +134,11 @@ static inline void restore_fp(struct task_struct *tsk) static inline fpureg_t *get_fpu_regs(struct task_struct *tsk) { - if (cpu_has_fpu) { - if ((tsk == current) && __is_fpu_owner()) + if (tsk == current) { + preempt_disable(); + if (is_fpu_owner()) _save_fp(current); + preempt_enable(); } return tsk->thread.fpu.fpr; -- GitLab From b0ac3f50b8f2cd992ffd36d22c82eabdf075e9c4 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 9 Oct 2006 19:13:51 -0400 Subject: [PATCH 0838/1619] [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 diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c index 89d702de486..0f5b30dc60d 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 0cea42a8053..bb9acbb9817 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 a7348213508..fb2f92bcd77 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 aea43597038..0afe6bfe371 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 479ffb0a22d..00000000000 --- 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 -- GitLab From 99ae1c83b5107cd91e45d4d3c7bf096cdff0cf06 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 Oct 2006 17:31:00 -0700 Subject: [PATCH 0839/1619] [SPARC64]: Update MAINTAINERS entry. ultralinux@vger is deprecated, folks should use sparclinux@vger for both sparc ports. Eddie, Anton, and Jakub haven't been active in sparc64 maintainence for years, so best to remove them as reports do nothing more than fill up their mailboxes :) Signed-off-by: David S. Miller --- MAINTAINERS | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 50fb3ae5f31..931e6e40c08 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2780,14 +2780,7 @@ S: Maintained UltraSPARC (sparc64): P: David S. Miller M: davem@davemloft.net -P: Eddie C. Dost -M: ecd@brainaid.de -P: Jakub Jelinek -M: jj@sunsite.ms.mff.cuni.cz -P: Anton Blanchard -M: anton@samba.org L: sparclinux@vger.kernel.org -L: ultralinux@vger.kernel.org T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git S: Maintained -- GitLab From 4b75eb2bd30707c1af76145fd3a4ec2d890e1870 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 5 Oct 2006 02:07:32 -0700 Subject: [PATCH 0840/1619] [SPARC64]: Fix of_device bus_id settings. They have to be unique system-wide, so use "NAME@NODE" as the string pattern of the non-root nodes. Thanks to Andrew Morton for fixing the error value checking in bus_add_device() which made this problem finally noticable. Signed-off-by: David S. Miller --- arch/sparc64/kernel/of_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 7f920453577..d822c7c18e1 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -841,7 +841,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, if (!parent) strcpy(op->dev.bus_id, "root"); else - strcpy(op->dev.bus_id, dp->path_component_name); + sprintf(op->dev.bus_id, "%s@%08x", dp->name, dp->node); if (of_device_register(op)) { printk("%s: Could not register of device.\n", -- GitLab From 79bf06248b69b937f3a917281b4a8520a66c7582 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 5 Oct 2006 02:08:59 -0700 Subject: [PATCH 0841/1619] [SPARC64]: Update defconfig. Signed-off-by: David S. Miller --- arch/sparc64/defconfig | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index f54ab375464..dcae559879a 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18 -# Mon Oct 2 14:24:40 2006 +# Linux kernel version: 2.6.19-rc1 +# Thu Oct 5 02:08:41 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -197,6 +197,7 @@ CONFIG_INET_XFRM_TUNNEL=y CONFIG_INET_TUNNEL=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -214,6 +215,7 @@ CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m CONFIG_INET6_XFRM_MODE_TRANSPORT=m CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set CONFIG_IPV6_TUNNEL=m # CONFIG_IPV6_SUBTREES is not set @@ -373,6 +375,7 @@ CONFIG_BLK_DEV_ALI15X3=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_IT821X is not set @@ -449,10 +452,10 @@ CONFIG_ISCSI_TCP=m # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLOGICPTI is not set # CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -478,6 +481,7 @@ CONFIG_MD_RAID456=m CONFIG_MD_MULTIPATH=m # CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m @@ -840,12 +844,12 @@ CONFIG_HWMON=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -858,6 +862,7 @@ CONFIG_VIDEO_V4L2=y # # CONFIG_FIRMWARE_EDID is not set CONFIG_FB=y +CONFIG_FB_DDC=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y @@ -1236,6 +1241,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -1279,6 +1285,7 @@ CONFIG_RAMFS=y # # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set @@ -1354,6 +1361,10 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set +# +# Distributed Lock Manager +# + # # Instrumentation Support # -- GitLab From 078830eaa8abccd1e95d3effce5b29273bb5ed09 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Mon, 9 Oct 2006 18:10:16 -0700 Subject: [PATCH 0842/1619] [SPARC32]: Fix prom.c build warning Fix these 2.6.19-rc1 build warnings: CC arch/sparc/kernel/prom.o arch/sparc/kernel/prom.c: In function `of_set_property': arch/sparc/kernel/prom.c:246: warning: passing arg 2 of `prom_setprop' discards qualifiers from pointer target type arch/sparc/kernel/prom.c: In function `build_one_prop': arch/sparc/kernel/prom.c:446: warning: unused variable `len' arch/sparc/kernel/prom.c:480: warning: ignoring return value of `prom_getproperty', declared with attribute warn_unused_result Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 4ca9e5fc97f..2cc302b6bec 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -243,7 +243,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len void *old_val = prop->value; int ret; - ret = prom_setprop(dp->node, name, val, len); + ret = prom_setprop(dp->node, (char *) name, val, len); err = -EINVAL; if (ret >= 0) { prop->value = new_val; @@ -477,7 +477,10 @@ static struct property * __init build_one_prop(phandle node, char *prev, char *s p->length = 0; } else { p->value = prom_early_alloc(p->length + 1); - prom_getproperty(node, p->name, p->value, p->length); + len = prom_getproperty(node, p->name, p->value, + p->length); + if (len <= 0) + p->length = 0; ((unsigned char *)p->value)[p->length] = '\0'; } } -- GitLab From f583ffce1aac783fd16d5d75cd69ac5ebb8f4933 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 10 Oct 2006 11:47:07 +1000 Subject: [PATCH 0843/1619] [POWERPC] Fix xmon IRQ handler for pt_regs removal Signed-off-by: Paul Mackerras --- arch/powerpc/xmon/xmon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 5a854f36383..f56ffef4def 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include @@ -521,13 +522,12 @@ int xmon(struct pt_regs *excp) } EXPORT_SYMBOL(xmon); -irqreturn_t -xmon_irq(int irq, void *d, struct pt_regs *regs) +irqreturn_t xmon_irq(int irq, void *d) { unsigned long flags; local_irq_save(flags); printf("Keyboard interrupt\n"); - xmon(regs); + xmon(get_irq_regs()); local_irq_restore(flags); return IRQ_HANDLED; } -- GitLab From dcf9065122660f4e3df02a47a75dc702d5531244 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 30 Sep 2006 11:54:09 +1000 Subject: [PATCH 0844/1619] [POWERPC] Fix boot wrapper invocation if CROSS_COMPILE contains spaces My CROSS_COMPILE is "ccache /opt/compilers/blah", which confuses the boot wrapper script. Quote CROSS_COMPILE and CROSS32_COMPILE so they can safely contain spaces. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 003520b5630..bfd17b14580 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -105,10 +105,10 @@ wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff) # Bits for building various flavours of zImage ifneq ($(CROSS32_COMPILE),) -CROSSWRAP := -C $(CROSS32_COMPILE) +CROSSWRAP := -C "$(CROSS32_COMPILE)" else ifneq ($(CROSS_COMPILE),) -CROSSWRAP := -C $(CROSS_COMPILE) +CROSSWRAP := -C "$(CROSS_COMPILE)" endif endif -- GitLab From 020533ef24309803789ab8b325b1a6463388decf Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 7 Oct 2006 15:33:53 -0700 Subject: [PATCH 0845/1619] [POWERPC] cell: fix default zImage build target Change CONFIG_PPC_CELL to CONFIG_PPC_IBM_CELL_BLADE in the powerpc boot makefile. CONFIG_PPC_CELL is used to build the generic cell processor support, and is not an indication of platform. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index bfd17b14580..37ddfcab000 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -151,12 +151,12 @@ $(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits) $(obj)/uImage: vmlinux $(wrapperbits) $(call cmd,wrap,uboot) -image-$(CONFIG_PPC_PSERIES) += zImage.pseries -image-$(CONFIG_PPC_MAPLE) += zImage.pseries -image-$(CONFIG_PPC_CELL) += zImage.pseries -image-$(CONFIG_PPC_CHRP) += zImage.chrp -image-$(CONFIG_PPC_PMAC) += zImage.pmac -image-$(CONFIG_DEFAULT_UIMAGE) += uImage +image-$(CONFIG_PPC_PSERIES) += zImage.pseries +image-$(CONFIG_PPC_MAPLE) += zImage.pseries +image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries +image-$(CONFIG_PPC_CHRP) += zImage.chrp +image-$(CONFIG_PPC_PMAC) += zImage.pmac +image-$(CONFIG_DEFAULT_UIMAGE) += uImage # For 32-bit powermacs, build the COFF and miboot images # as well as the ELF images. -- GitLab From c10af8c38da7a0bc9010d6609237c1ab6d2da12c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 9 Oct 2006 13:25:15 +1000 Subject: [PATCH 0846/1619] [POWERPC] Make U4 PCIe work on maple The Maple support code was missing code for U4/CPC945 PCIe. This adds it, enabling it to work on tigerwood boards, and possibly also js21 using SLOF. Also disable an obsolete firmware workaround. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/maple/pci.c | 176 +++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 1b827618e05..8debae3aa3c 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -8,7 +8,7 @@ * 2 of the License, or (at your option) any later version. */ -#define DEBUG +#undef DEBUG #include #include @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,7 @@ #define DBG(x...) #endif -static struct pci_controller *u3_agp, *u3_ht; +static struct pci_controller *u3_agp, *u3_ht, *u4_pcie; static int __init fixup_one_level_bus_range(struct device_node *node, int higher) { @@ -287,6 +288,114 @@ static struct pci_ops u3_ht_pci_ops = u3_ht_write_config }; +static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off) +{ + return (1 << PCI_SLOT(devfn)) | + (PCI_FUNC(devfn) << 8) | + ((off >> 8) << 28) | + (off & 0xfcu); +} + +static unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn, + unsigned int off) +{ + return (bus << 16) | + (devfn << 8) | + ((off >> 8) << 28) | + (off & 0xfcu) | 1u; +} + +static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, + u8 bus, u8 dev_fn, int offset) +{ + unsigned int caddr; + + if (bus == hose->first_busno) + caddr = u4_pcie_cfa0(dev_fn, offset); + else + caddr = u4_pcie_cfa1(bus, dev_fn, offset); + + /* Uninorth will return garbage if we don't read back the value ! */ + do { + out_le32(hose->cfg_addr, caddr); + } while (in_le32(hose->cfg_addr) != caddr); + + offset &= 0x03; + return hose->cfg_data + offset; +} + +static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose; + volatile void __iomem *addr; + + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset >= 0x1000) + return PCIBIOS_BAD_REGISTER_NUMBER; + addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8(addr); + break; + case 2: + *val = in_le16(addr); + break; + default: + *val = in_le32(addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} +static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose; + volatile void __iomem *addr; + + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset >= 0x1000) + return PCIBIOS_BAD_REGISTER_NUMBER; + addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8(addr, val); + (void) in_8(addr); + break; + case 2: + out_le16(addr, val); + (void) in_le16(addr); + break; + default: + out_le32(addr, val); + (void) in_le32(addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops u4_pcie_pci_ops = +{ + u4_pcie_read_config, + u4_pcie_write_config +}; + static void __init setup_u3_agp(struct pci_controller* hose) { /* On G5, we move AGP up to high bus number so we don't need @@ -307,6 +416,26 @@ static void __init setup_u3_agp(struct pci_controller* hose) u3_agp = hose; } +static void __init setup_u4_pcie(struct pci_controller* hose) +{ + /* We currently only implement the "non-atomic" config space, to + * be optimised later. + */ + hose->ops = &u4_pcie_pci_ops; + hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); + hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); + + /* The bus contains a bridge from root -> device, we need to + * make it visible on bus 0 so that we pick the right type + * of config cycles. If we didn't, we would have to force all + * config cycles to be type 1. So we override the "bus-range" + * property here + */ + hose->first_busno = 0x00; + hose->last_busno = 0xff; + u4_pcie = hose; +} + static void __init setup_u3_ht(struct pci_controller* hose) { hose->ops = &u3_ht_pci_ops; @@ -354,6 +483,10 @@ static int __init add_bridge(struct device_node *dev) setup_u3_ht(hose); disp_name = "U3-HT"; primary = 1; + } else if (device_is_compatible(dev, "u4-pcie")) { + setup_u4_pcie(hose); + disp_name = "U4-PCIE"; + primary = 0; } printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", disp_name, hose->first_busno, hose->last_busno); @@ -361,7 +494,6 @@ static int __init add_bridge(struct device_node *dev) /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ pci_process_bridge_OF_ranges(hose, dev, primary); - pci_setup_phb_io(hose, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); @@ -376,8 +508,17 @@ void __init maple_pcibios_fixup(void) DBG(" -> maple_pcibios_fixup\n"); - for_each_pci_dev(dev) - pci_read_irq_line(dev); + for_each_pci_dev(dev) { + /* Fixup IRQ for PCIe host */ + if (u4_pcie != NULL && dev->bus->number == 0 && + pci_bus_to_host(dev->bus) == u4_pcie) { + printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n"); + dev->irq = irq_create_mapping(NULL, 1); + if (dev->irq != NO_IRQ) + set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); + } else + pci_read_irq_line(dev); + } DBG(" <- maple_pcibios_fixup\n"); } @@ -388,8 +529,10 @@ static void __init maple_fixup_phb_resources(void) list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; + hose->io_resource.start += offset; hose->io_resource.end += offset; + printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n", hose->global_number, (unsigned long long)hose->io_resource.start, @@ -431,6 +574,19 @@ void __init maple_pci_init(void) if (ht && add_bridge(ht) != 0) of_node_put(ht); + /* + * We need to call pci_setup_phb_io for the HT bridge first + * so it gets the I/O port numbers starting at 0, and we + * need to call it for the AGP bridge after that so it gets + * small positive I/O port numbers. + */ + if (u3_ht) + pci_setup_phb_io(u3_ht, 1); + if (u3_agp) + pci_setup_phb_io(u3_agp, 0); + if (u4_pcie) + pci_setup_phb_io(u4_pcie, 0); + /* Fixup the IO resources on our host bridges as the common code * does it only for childs of the host bridges */ @@ -465,8 +621,11 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) return defirq; np = pci_device_to_OF_node(pdev); - if (np == NULL) + if (np == NULL) { + printk("Failed to locate OF node for IDE %s\n", + pci_name(pdev)); return defirq; + } irq = irq_of_parse_and_map(np, channel & 0x1); if (irq == NO_IRQ) { printk("Failed to map onboard IDE interrupt for channel %d\n", @@ -479,6 +638,9 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) /* XXX: To remove once all firmwares are ok */ static void fixup_maple_ide(struct pci_dev* dev) { + if (!machine_is(maple)) + return; + #if 0 /* Enable this to enable IDE port 0 */ { u8 v; @@ -495,7 +657,7 @@ static void fixup_maple_ide(struct pci_dev* dev) dev->resource[4].start = 0xcc00; dev->resource[4].end = 0xcc10; #endif -#if 1 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */ +#if 0 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */ { struct pci_dev *apicdev; u32 v; -- GitLab From 1e1b20a119ac45a290bbc6261f69a2a6a2cc064a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 9 Oct 2006 13:27:28 +1000 Subject: [PATCH 0847/1619] [POWERPC] Fix Maple secondary IDE interrupt The IDE driver will pick up the PCI IRQ for both channels on Maple despite the fact that it's in legacy mode. This works around it by "hiding" the PCI IRQ of the AMD8111 IDE controller when it's configured in legacy mode on the Maple platform, thus causing the driver to call pci_get_legacy_ide_irq() which will return the correct interrupts for both channels. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/maple/pci.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 8debae3aa3c..63b4d1bff35 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -516,8 +516,21 @@ void __init maple_pcibios_fixup(void) dev->irq = irq_create_mapping(NULL, 1); if (dev->irq != NO_IRQ) set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); - } else - pci_read_irq_line(dev); + continue; + } + + /* Hide AMD8111 IDE interrupt when in legacy mode so + * the driver calls pci_get_legacy_ide_irq() + */ + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_8111_IDE && + (dev->class & 5) != 5) { + dev->irq = NO_IRQ; + continue; + } + + /* For all others, map the interrupt from the device-tree */ + pci_read_irq_line(dev); } DBG(" <- maple_pcibios_fixup\n"); -- GitLab From 8de242e60a441f177dd51b323894b17d3d63e9f2 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 9 Oct 2006 13:28:59 +1000 Subject: [PATCH 0848/1619] [POWERPC] Update maple defconfig This updates the Maple defconfig to 4 CPUs (along with current defaults) to support the "tigerwood" 970MP evaluation board. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/configs/maple_defconfig | 56 +++++++++++++++++++++------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig index 62ba66091a1..ae96a5b2f00 100644 --- a/arch/powerpc/configs/maple_defconfig +++ b/arch/powerpc/configs/maple_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc6 -# Sun Sep 10 10:24:55 2006 +# Linux kernel version: 2.6.18 +# Mon Oct 9 11:59:34 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_PPC_OF=y CONFIG_PPC_UDBG_16550=y CONFIG_GENERIC_TBSYNC=y +CONFIG_AUDIT_ARCH=y # CONFIG_DEFAULT_UIMAGE is not set # @@ -34,7 +35,7 @@ CONFIG_PPC_FPU=y CONFIG_PPC_STD_MMU=y CONFIG_VIRT_CPU_ACCOUNTING=y CONFIG_SMP=y -CONFIG_NR_CPUS=2 +CONFIG_NR_CPUS=4 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -51,10 +52,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -CONFIG_SYSCTL=y +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -62,7 +64,9 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -71,12 +75,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -95,6 +99,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_BLK_DEV_IO_TRACE is not set # @@ -114,16 +119,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # Platform support # CONFIG_PPC_MULTIPLATFORM=y -# CONFIG_PPC_ISERIES is not set # CONFIG_EMBEDDED6xx is not set # CONFIG_APUS is not set # CONFIG_PPC_PSERIES is not set +# CONFIG_PPC_ISERIES is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_MAPLE=y +# CONFIG_PPC_PASEMI is not set # CONFIG_PPC_CELL is not set # CONFIG_PPC_CELL_NATIVE is not set # CONFIG_PPC_IBM_CELL_BLADE is not set -# CONFIG_UDBG_RTAS_CONSOLE is not set CONFIG_U3_DART=y # CONFIG_PPC_RTAS is not set # CONFIG_MMIO_NVRAM is not set @@ -157,6 +162,7 @@ CONFIG_IRQ_ALL_CPUS=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -184,6 +190,7 @@ CONFIG_GENERIC_ISA_DMA=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # @@ -211,6 +218,7 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_XFRM=y CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -232,10 +240,12 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -265,7 +275,6 @@ CONFIG_TCP_CONG_BIC=y # 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 @@ -377,6 +386,7 @@ CONFIG_BLK_DEV_AMD74XX=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_IT821X is not set @@ -399,6 +409,12 @@ CONFIG_IDEDMA_AUTO=y # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set # # Multi-device support (RAID and LVM) @@ -498,7 +514,7 @@ CONFIG_E1000=y # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=y # CONFIG_BNX2 is not set -# CONFIG_MV643XX_ETH is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -545,6 +561,7 @@ CONFIG_TIGON3=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -704,6 +721,7 @@ CONFIG_I2C_AMD8111=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices @@ -779,7 +797,6 @@ CONFIG_USB_UHCI_HCD=y # # may also be needed; see USB_STORAGE Help for more information # -# CONFIG_USB_STORAGE is not set # CONFIG_USB_LIBUSUAL is not set # @@ -802,6 +819,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set # # USB Imaging devices @@ -828,6 +846,7 @@ CONFIG_USB_MON=y CONFIG_USB_SERIAL=y # CONFIG_USB_SERIAL_CONSOLE is not set CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_AIRCABLE is not set # CONFIG_USB_SERIAL_AIRPRIME is not set # CONFIG_USB_SERIAL_ARK3116 is not set # CONFIG_USB_SERIAL_BELKIN is not set @@ -862,6 +881,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y # CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_KOBIL_SCT is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set # CONFIG_USB_SERIAL_NAVMAN is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_HP4X is not set @@ -879,6 +899,7 @@ CONFIG_USB_EZUSB=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set @@ -886,9 +907,9 @@ CONFIG_USB_EZUSB=y # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGETKIT is not set -# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set @@ -995,8 +1016,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y @@ -1129,6 +1152,7 @@ CONFIG_PLIST=y # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y @@ -1148,6 +1172,7 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FORCED_INLINING is not set # CONFIG_RCU_TORTURE_TEST is not set CONFIG_DEBUG_STACKOVERFLOW=y @@ -1169,6 +1194,9 @@ CONFIG_BOOTX_TEXT=y # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_MANAGER=m # CONFIG_CRYPTO_HMAC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set @@ -1178,6 +1206,8 @@ CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set -- GitLab From 39e3eb7265b8698e5f607a317af13c9478274736 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Oct 2006 12:48:42 +0100 Subject: [PATCH 0849/1619] [POWERPC] ARCH=ppc pt_regs fixes Signed-off-by: Al Viro Signed-off-by: Paul Mackerras --- arch/ppc/4xx_io/serial_sicc.c | 8 ++++---- arch/ppc/8260_io/enet.c | 4 ++-- arch/ppc/8260_io/fcc_enet.c | 6 +++--- arch/ppc/8xx_io/commproc.c | 19 +++++++++---------- arch/ppc/8xx_io/cs4218_tdm.c | 4 ++-- arch/ppc/8xx_io/enet.c | 4 ++-- arch/ppc/8xx_io/fec.c | 7 +++---- arch/ppc/kernel/smp.c | 4 ++-- arch/ppc/platforms/apus_setup.c | 2 +- arch/ppc/platforms/hdpu.c | 22 ++++++++++------------ arch/ppc/platforms/radstone_ppc7d.c | 10 +++++----- arch/ppc/platforms/sbc82xx.c | 4 ++-- arch/ppc/syslib/cpc700.h | 2 +- arch/ppc/syslib/cpc700_pic.c | 2 +- arch/ppc/syslib/cpm2_pic.c | 2 +- arch/ppc/syslib/cpm2_pic.h | 2 +- arch/ppc/syslib/gt64260_pic.c | 9 +++------ arch/ppc/syslib/ibm440gx_common.c | 2 +- arch/ppc/syslib/ipic.c | 2 +- arch/ppc/syslib/m82xx_pci.c | 4 ++-- arch/ppc/syslib/m8xx_setup.c | 2 +- arch/ppc/syslib/m8xx_wdt.c | 4 ++-- arch/ppc/syslib/mpc52xx_pic.c | 2 +- arch/ppc/syslib/mv64360_pic.c | 18 +++++++----------- arch/ppc/syslib/open_pic2.c | 2 +- arch/ppc/syslib/ppc403_pic.c | 2 +- arch/ppc/syslib/ppc4xx_pic.c | 8 ++++---- arch/ppc/syslib/ppc85xx_rio.c | 9 +++------ arch/ppc/syslib/ppc8xx_pic.c | 4 ++-- arch/ppc/syslib/xilinx_pic.c | 2 +- include/asm-ppc/commproc.h | 3 +-- include/asm-ppc/gt64260.h | 2 +- include/asm-ppc/mpc52xx.h | 2 +- include/asm-ppc/mv64x60.h | 4 ++-- 34 files changed, 84 insertions(+), 99 deletions(-) diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c index 080a20531f8..e35483961b9 100644 --- a/arch/ppc/4xx_io/serial_sicc.c +++ b/arch/ppc/4xx_io/serial_sicc.c @@ -414,7 +414,7 @@ static void siccuart_event(struct SICC_info *info, int event) } static void -siccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs) +siccuart_rx_chars(struct SICC_info *info) { struct tty_struct *tty = info->tty; unsigned int status, ch, rsr, flg, ignored = 0; @@ -553,15 +553,15 @@ static void siccuart_tx_chars(struct SICC_info *info) } -static irqreturn_t siccuart_int_rx(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t siccuart_int_rx(int irq, void *dev_id) { struct SICC_info *info = dev_id; - siccuart_rx_chars(info, regs); + siccuart_rx_chars(info) return IRQ_HANDLED; } -static irqreturn_t siccuart_int_tx(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t siccuart_int_tx(int irq, void *dev_id) { struct SICC_info *info = dev_id; siccuart_tx_chars(info); diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c index ac6d55fe223..a6056c29cf0 100644 --- a/arch/ppc/8260_io/enet.c +++ b/arch/ppc/8260_io/enet.c @@ -122,7 +122,7 @@ struct scc_enet_private { static int scc_enet_open(struct net_device *dev); static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static int scc_enet_rx(struct net_device *dev); -static irqreturn_t scc_enet_interrupt(int irq, void *dev_id, struct pt_regs *); +static irqreturn_t scc_enet_interrupt(int irq, void *dev_id); static int scc_enet_close(struct net_device *dev); static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -273,7 +273,7 @@ scc_enet_timeout(struct net_device *dev) * This is called from the CPM handler, not the MPC core interrupt. */ static irqreturn_t -scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +scc_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; volatile struct scc_enet_private *cep; diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index e347fe88316..2e1943e2781 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -140,7 +140,7 @@ typedef struct { static int fcc_enet_open(struct net_device *dev); static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static int fcc_enet_rx(struct net_device *dev); -static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id, struct pt_regs *); +static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id); static int fcc_enet_close(struct net_device *dev); static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev); /* static void set_multicast_list(struct net_device *dev); */ @@ -524,7 +524,7 @@ fcc_enet_timeout(struct net_device *dev) /* The interrupt handler. */ static irqreturn_t -fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +fcc_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; volatile struct fcc_enet_private *cep; @@ -1563,7 +1563,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) #ifdef PHY_INTERRUPT /* This interrupt occurs when the PHY detects a link change. */ static irqreturn_t -mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +mii_link_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; struct fcc_enet_private *fep = dev->priv; diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 9b3ace26280..3b23bcb35b7 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -47,12 +47,12 @@ cpm8xx_t *cpmp; /* Pointer to comm processor space */ /* CPM interrupt vector functions. */ struct cpm_action { - void (*handler)(void *, struct pt_regs * regs); + void (*handler)(void *); void *dev_id; }; static struct cpm_action cpm_vecs[CPMVEC_NR]; -static irqreturn_t cpm_interrupt(int irq, void * dev, struct pt_regs * regs); -static irqreturn_t cpm_error_interrupt(int irq, void *dev, struct pt_regs * regs); +static irqreturn_t cpm_interrupt(int irq, void * dev); +static irqreturn_t cpm_error_interrupt(int irq, void *dev); static void alloc_host_memory(void); /* Define a table of names to identify CPM interrupt handlers in * /proc/interrupts. @@ -205,7 +205,7 @@ cpm_interrupt_init(void) * Get the CPM interrupt vector. */ int -cpm_get_irq(struct pt_regs *regs) +cpm_get_irq(void) { int cpm_vec; @@ -222,7 +222,7 @@ cpm_get_irq(struct pt_regs *regs) /* CPM interrupt controller cascade interrupt. */ static irqreturn_t -cpm_interrupt(int irq, void * dev, struct pt_regs * regs) +cpm_interrupt(int irq, void * dev) { /* This interrupt handler never actually gets called. It is * installed only to unmask the CPM cascade interrupt in the SIU @@ -237,7 +237,7 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs) * tests in the interrupt handler. */ static irqreturn_t -cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs) +cpm_error_interrupt(int irq, void *dev) { return IRQ_HANDLED; } @@ -246,11 +246,11 @@ cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs) * request_irq() to the handler prototype required by cpm_install_handler(). */ static irqreturn_t -cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs) +cpm_handler_helper(int irq, void *dev_id) { int cpm_vec = irq - CPM_IRQ_OFFSET; - (*cpm_vecs[cpm_vec].handler)(dev_id, regs); + (*cpm_vecs[cpm_vec].handler)(dev_id); return IRQ_HANDLED; } @@ -267,8 +267,7 @@ cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs) * request_irq() or cpm_install_handler(). */ void -cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs), - void *dev_id) +cpm_install_handler(int cpm_vec, void (*handler)(void *), void *dev_id) { int err; diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c index f5f300fc213..959d31c26cb 100644 --- a/arch/ppc/8xx_io/cs4218_tdm.c +++ b/arch/ppc/8xx_io/cs4218_tdm.c @@ -331,7 +331,7 @@ static int CS_SetFormat(int format); static int CS_SetVolume(int volume); static void cs4218_tdm_tx_intr(void *devid); static void cs4218_tdm_rx_intr(void *devid); -static void cs4218_intr(void *devid, struct pt_regs *regs); +static void cs4218_intr(void *devid); static int cs_get_volume(uint reg); static int cs_volume_setter(int volume, int mute); static int cs_get_gain(uint reg); @@ -2646,7 +2646,7 @@ int __init tdm8xx_sound_init(void) * full duplex operation. */ static void -cs4218_intr(void *dev_id, struct pt_regs *regs) +cs4218_intr(void *dev_id) { volatile smc_t *sp; volatile cpm8xx_t *cp; diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index a695375c3e4..b23c45bc151 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -149,7 +149,7 @@ struct scc_enet_private { static int scc_enet_open(struct net_device *dev); static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static int scc_enet_rx(struct net_device *dev); -static void scc_enet_interrupt(void *dev_id, struct pt_regs *regs); +static void scc_enet_interrupt(void *dev_id); static int scc_enet_close(struct net_device *dev); static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -305,7 +305,7 @@ scc_enet_timeout(struct net_device *dev) * This is called from the CPM handler, not the MPC core interrupt. */ static void -scc_enet_interrupt(void *dev_id, struct pt_regs *regs) +scc_enet_interrupt(void *dev_id) { struct net_device *dev = dev_id; volatile struct scc_enet_private *cep; diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index 8b6295bbb56..2f9fa9e3d33 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -198,8 +198,7 @@ static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); #ifdef CONFIG_USE_MDIO static void fec_enet_mii(struct net_device *dev); #endif /* CONFIG_USE_MDIO */ -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); #ifdef CONFIG_FEC_PACKETHOOK static void fec_enet_tx(struct net_device *dev, __u32 regval); static void fec_enet_rx(struct net_device *dev, __u32 regval); @@ -472,7 +471,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; @@ -1408,7 +1407,7 @@ static #ifdef CONFIG_RPXCLASSIC void mii_link_interrupt(void *dev_id) #else -irqreturn_t mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +irqreturn_t mii_link_interrupt(int irq, void * dev_id) #endif { #ifdef CONFIG_USE_MDIO diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index ca57e896a36..96a55972b98 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -84,7 +84,7 @@ smp_message_pass(int target, int msg) /* * Common functions */ -void smp_message_recv(int msg, struct pt_regs *regs) +void smp_message_recv(int msg) { atomic_inc(&ipi_recv); @@ -100,7 +100,7 @@ void smp_message_recv(int msg, struct pt_regs *regs) break; #ifdef CONFIG_XMON case PPC_MSG_XMON_BREAK: - xmon(regs); + xmon(get_irq_regs()); break; #endif /* CONFIG_XMON */ default: diff --git a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c index 1d034ead2c9..063274d2c50 100644 --- a/arch/ppc/platforms/apus_setup.c +++ b/arch/ppc/platforms/apus_setup.c @@ -492,7 +492,7 @@ apus_halt(void) static unsigned char last_ipl[8]; -int apus_get_irq(struct pt_regs* regs) +int apus_get_irq(void) { unsigned char ipl_emu, mask; unsigned int level; diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c index e0f112a1fd0..d809e17aa53 100644 --- a/arch/ppc/platforms/hdpu.c +++ b/arch/ppc/platforms/hdpu.c @@ -659,8 +659,7 @@ static void __init hdpu_map_io(void) char hdpu_smp0[] = "SMP Cpu #0"; char hdpu_smp1[] = "SMP Cpu #1"; -static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id) { volatile unsigned int doorbell; @@ -670,22 +669,21 @@ static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id, mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, doorbell); if (doorbell & 1) { - smp_message_recv(0, regs); + smp_message_recv(0); } if (doorbell & 2) { - smp_message_recv(1, regs); + smp_message_recv(1); } if (doorbell & 4) { - smp_message_recv(2, regs); + smp_message_recv(2); } if (doorbell & 8) { - smp_message_recv(3, regs); + smp_message_recv(3); } return IRQ_HANDLED; } -static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id) { volatile unsigned int doorbell; @@ -695,16 +693,16 @@ static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id, mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, doorbell); if (doorbell & 1) { - smp_message_recv(0, regs); + smp_message_recv(0); } if (doorbell & 2) { - smp_message_recv(1, regs); + smp_message_recv(1); } if (doorbell & 4) { - smp_message_recv(2, regs); + smp_message_recv(2); } if (doorbell & 8) { - smp_message_recv(3, regs); + smp_message_recv(3); } return IRQ_HANDLED; } diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index 3bb530af029..13d70ab50bf 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -451,11 +451,11 @@ static void __init ppc7d_calibrate_decr(void) * Interrupt stuff *****************************************************************************/ -static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id) { u32 temp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE); if (temp & (1 << 28)) { - i8259_irq(regs); + i8259_irq(); mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, temp & (~(1 << 28))); return IRQ_HANDLED; } @@ -536,13 +536,13 @@ static u32 ppc7d_irq_canonicalize(u32 irq) return irq; } -static int ppc7d_get_irq(struct pt_regs *regs) +static int ppc7d_get_irq(void) { int irq; - irq = mv64360_get_irq(regs); + irq = mv64360_get_irq(); if (irq == (mv64360_irq_base + MV64x60_IRQ_GPP28)) - irq = i8259_irq(regs); + irq = i8259_irq(); return irq; } diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c index 60b769c7f3f..cc0935ccab7 100644 --- a/arch/ppc/platforms/sbc82xx.c +++ b/arch/ppc/platforms/sbc82xx.c @@ -121,7 +121,7 @@ struct hw_interrupt_type sbc82xx_i8259_ic = { .end = sbc82xx_i8259_end_irq, }; -static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id) { spin_lock(&sbc82xx_i8259_lock); @@ -139,7 +139,7 @@ static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *re return IRQ_HANDLED; } } - __do_IRQ(NR_SIU_INTS + irq, regs); + __do_IRQ(NR_SIU_INTS + irq); return IRQ_HANDLED; } diff --git a/arch/ppc/syslib/cpc700.h b/arch/ppc/syslib/cpc700.h index 0a8a5d84390..987e9aa0dd4 100644 --- a/arch/ppc/syslib/cpc700.h +++ b/arch/ppc/syslib/cpc700.h @@ -91,6 +91,6 @@ extern struct hw_interrupt_type cpc700_pic; extern unsigned int cpc700_irq_assigns[32][2]; extern void __init cpc700_init_IRQ(void); -extern int cpc700_get_irq(struct pt_regs *); +extern int cpc700_get_irq(void); #endif /* __PPC_SYSLIB_CPC700_H__ */ diff --git a/arch/ppc/syslib/cpc700_pic.c b/arch/ppc/syslib/cpc700_pic.c index 172aa215fdb..d48e8f45c05 100644 --- a/arch/ppc/syslib/cpc700_pic.c +++ b/arch/ppc/syslib/cpc700_pic.c @@ -158,7 +158,7 @@ cpc700_init_IRQ(void) * Find the highest IRQ that generating an interrupt, if any. */ int -cpc700_get_irq(struct pt_regs *regs) +cpc700_get_irq(void) { int irq = 0; u_int irq_status, irq_test = 1; diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c index c0fee0beb81..fb2d5842641 100644 --- a/arch/ppc/syslib/cpm2_pic.c +++ b/arch/ppc/syslib/cpm2_pic.c @@ -123,7 +123,7 @@ static struct hw_interrupt_type cpm2_pic = { .end = cpm2_end_irq, }; -int cpm2_get_irq(struct pt_regs *regs) +int cpm2_get_irq(void) { int irq; unsigned long bits; diff --git a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h index 97cab8f13a1..467339337a7 100644 --- a/arch/ppc/syslib/cpm2_pic.h +++ b/arch/ppc/syslib/cpm2_pic.h @@ -1,7 +1,7 @@ #ifndef _PPC_KERNEL_CPM2_H #define _PPC_KERNEL_CPM2_H -extern int cpm2_get_irq(struct pt_regs *regs); +extern int cpm2_get_irq(void); extern void cpm2_init_IRQ(void); diff --git a/arch/ppc/syslib/gt64260_pic.c b/arch/ppc/syslib/gt64260_pic.c index 7fd550a7d58..e84d432c065 100644 --- a/arch/ppc/syslib/gt64260_pic.c +++ b/arch/ppc/syslib/gt64260_pic.c @@ -110,9 +110,6 @@ gt64260_init_irq(void) * This function returns the lowest interrupt number of all interrupts that * are currently asserted. * - * Input Variable(s): - * struct pt_regs* not used - * * Output Variable(s): * None. * @@ -120,7 +117,7 @@ gt64260_init_irq(void) * int or -2 (bogus interrupt) */ int -gt64260_get_irq(struct pt_regs *regs) +gt64260_get_irq(void) { int irq; int irq_gpp; @@ -229,7 +226,7 @@ gt64260_mask_irq(unsigned int irq) } static irqreturn_t -gt64260_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) +gt64260_cpu_error_int_handler(int irq, void *dev_id) { printk(KERN_ERR "gt64260_cpu_error_int_handler: %s 0x%08x\n", "Error on CPU interface - Cause regiser", @@ -250,7 +247,7 @@ gt64260_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) } static irqreturn_t -gt64260_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) +gt64260_pci_error_int_handler(int irq, void *dev_id) { u32 val; unsigned int pci_bus = (unsigned int)dev_id; diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c index 4b77e6c8c87..6ad52f4a26e 100644 --- a/arch/ppc/syslib/ibm440gx_common.c +++ b/arch/ppc/syslib/ibm440gx_common.c @@ -119,7 +119,7 @@ static inline u32 l2c_diag(u32 addr) return mfdcr(DCRN_L2C0_DATA); } -static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs) +static irqreturn_t l2c_error_handler(int irq, void* dev) { u32 sr = mfdcr(DCRN_L2C0_SR); if (sr & L2C_SR_CPE){ diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c index 46801f5ec03..10659c24b1b 100644 --- a/arch/ppc/syslib/ipic.c +++ b/arch/ppc/syslib/ipic.c @@ -601,7 +601,7 @@ void ipic_clear_mcp_status(u32 mask) } /* Return an interrupt vector or -1 if no interrupt is pending. */ -int ipic_get_irq(struct pt_regs *regs) +int ipic_get_irq(void) { int irq; diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c index d3fa264e179..e3b586b1ede 100644 --- a/arch/ppc/syslib/m82xx_pci.c +++ b/arch/ppc/syslib/m82xx_pci.c @@ -117,7 +117,7 @@ struct hw_interrupt_type pq2pci_ic = { }; static irqreturn_t -pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs) +pq2pci_irq_demux(int irq, void *dev_id) { unsigned long stat, mask, pend; int bit; @@ -130,7 +130,7 @@ pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs) break; for (bit = 0; pend != 0; ++bit, pend <<= 1) { if (pend & 0x80000000) - __do_IRQ(NR_CPM_INTS + bit, regs); + __do_IRQ(NR_CPM_INTS + bit); } } diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index 54303a7b4e6..d8d299bd1a1 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -169,7 +169,7 @@ abort(void) } /* A place holder for time base interrupts, if they are ever enabled. */ -irqreturn_t timebase_interrupt(int irq, void * dev, struct pt_regs * regs) +irqreturn_t timebase_interrupt(int irq, void * dev) { printk ("timebase_interrupt()\n"); diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c index ac11d7bab44..fffac8cbeb5 100644 --- a/arch/ppc/syslib/m8xx_wdt.c +++ b/arch/ppc/syslib/m8xx_wdt.c @@ -21,7 +21,7 @@ static int wdt_timeout; int m8xx_has_internal_rtc = 0; -static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *); +static irqreturn_t m8xx_wdt_interrupt(int, void *); static struct irqaction m8xx_wdt_irqaction = { .handler = m8xx_wdt_interrupt, .name = "watchdog", @@ -35,7 +35,7 @@ void m8xx_wdt_reset(void) out_be16(&imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ } -static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev) { volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c index 6425b5cee7d..af35a316544 100644 --- a/arch/ppc/syslib/mpc52xx_pic.c +++ b/arch/ppc/syslib/mpc52xx_pic.c @@ -220,7 +220,7 @@ mpc52xx_init_irq(void) } int -mpc52xx_get_irq(struct pt_regs *regs) +mpc52xx_get_irq(void) { u32 status; int irq = -1; diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c index 5104386601e..4b7a3338e12 100644 --- a/arch/ppc/syslib/mv64360_pic.c +++ b/arch/ppc/syslib/mv64360_pic.c @@ -55,10 +55,9 @@ static void mv64360_unmask_irq(unsigned int); static void mv64360_mask_irq(unsigned int); -static irqreturn_t mv64360_cpu_error_int_handler(int, void *, struct pt_regs *); -static irqreturn_t mv64360_sram_error_int_handler(int, void *, - struct pt_regs *); -static irqreturn_t mv64360_pci_error_int_handler(int, void *, struct pt_regs *); +static irqreturn_t mv64360_cpu_error_int_handler(int, void *); +static irqreturn_t mv64360_sram_error_int_handler(int, void *); +static irqreturn_t mv64360_pci_error_int_handler(int, void *); /* ========================== local declarations =========================== */ @@ -131,9 +130,6 @@ mv64360_init_irq(void) * This function returns the lowest interrupt number of all interrupts that * are currently asserted. * - * Input Variable(s): - * struct pt_regs* not used - * * Output Variable(s): * None. * @@ -142,7 +138,7 @@ mv64360_init_irq(void) * */ int -mv64360_get_irq(struct pt_regs *regs) +mv64360_get_irq(void) { int irq; int irq_gpp; @@ -283,7 +279,7 @@ mv64360_mask_irq(unsigned int irq) } static irqreturn_t -mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) +mv64360_cpu_error_int_handler(int irq, void *dev_id) { printk(KERN_ERR "mv64360_cpu_error_int_handler: %s 0x%08x\n", "Error on CPU interface - Cause regiser", @@ -304,7 +300,7 @@ mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) } static irqreturn_t -mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) +mv64360_sram_error_int_handler(int irq, void *dev_id) { printk(KERN_ERR "mv64360_sram_error_int_handler: %s 0x%08x\n", "Error in internal SRAM - Cause register", @@ -325,7 +321,7 @@ mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) } static irqreturn_t -mv64360_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) +mv64360_pci_error_int_handler(int irq, void *dev_id) { u32 val; unsigned int pci_bus = (unsigned int)dev_id; diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index e1ff971539e..d585207f9f7 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -529,7 +529,7 @@ static void openpic2_end_irq(unsigned int irq_nr) } int -openpic2_get_irq(struct pt_regs *regs) +openpic2_get_irq(void) { int irq = openpic2_irq(); diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c index 1584c8b1229..607ebd111d4 100644 --- a/arch/ppc/syslib/ppc403_pic.c +++ b/arch/ppc/syslib/ppc403_pic.c @@ -42,7 +42,7 @@ static struct hw_interrupt_type ppc403_aic = { }; int -ppc403_pic_get_irq(struct pt_regs *regs) +ppc403_pic_get_irq(void) { int irq; unsigned long bits; diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c index 745685df598..ee0da4b4b99 100644 --- a/arch/ppc/syslib/ppc4xx_pic.c +++ b/arch/ppc/syslib/ppc4xx_pic.c @@ -96,7 +96,7 @@ UIC_HANDLERS(1); UIC_HANDLERS(2); UIC_HANDLERS(3); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); if (uic0 & UIC0_UIC1NC) @@ -125,7 +125,7 @@ UIC_HANDLERS(0); UIC_HANDLERS(1); UIC_HANDLERS(2); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uicb = mfdcr(DCRN_UIC_MSR(UICB)); if (uicb & UICB_UIC0NC) @@ -158,7 +158,7 @@ static void __init ppc4xx_pic_impl_init(void) UIC_HANDLERS(0); UIC_HANDLERS(1); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); if (uic0 & UIC0_UIC1NC) @@ -179,7 +179,7 @@ static void __init ppc4xx_pic_impl_init(void) #define ACK_UIC0_PARENT UIC_HANDLERS(0); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); return uic0 ? 32 - ffs(uic0) : -1; diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c index d9b471b4d69..05b0e941508 100644 --- a/arch/ppc/syslib/ppc85xx_rio.c +++ b/arch/ppc/syslib/ppc85xx_rio.c @@ -349,13 +349,12 @@ EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler * @irq: Linux interrupt number * @dev_instance: Pointer to interrupt-specific data - * @regs: Register context * * Handles outbound message interrupts. Executes a register outbound * mailbox event handler and acks the interrupt occurence. */ static irqreturn_t -mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs *regs) +mpc85xx_rio_tx_handler(int irq, void *dev_instance) { int osr; struct rio_mport *port = (struct rio_mport *)dev_instance; @@ -517,13 +516,12 @@ void rio_close_outb_mbox(struct rio_mport *mport, int mbox) * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler * @irq: Linux interrupt number * @dev_instance: Pointer to interrupt-specific data - * @regs: Register context * * Handles inbound message interrupts. Executes a registered inbound * mailbox event handler and acks the interrupt occurence. */ static irqreturn_t -mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs) +mpc85xx_rio_rx_handler(int irq, void *dev_instance) { int isr; struct rio_mport *port = (struct rio_mport *)dev_instance; @@ -736,13 +734,12 @@ EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler * @irq: Linux interrupt number * @dev_instance: Pointer to interrupt-specific data - * @regs: Register context * * Handles doorbell interrupts. Parses a list of registered * doorbell event handlers and executes a matching event handler. */ static irqreturn_t -mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *regs) +mpc85xx_rio_dbell_handler(int irq, void *dev_instance) { int dsr; struct rio_mport *port = (struct rio_mport *)dev_instance; diff --git a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c index d6c25fe2501..e8619c75073 100644 --- a/arch/ppc/syslib/ppc8xx_pic.c +++ b/arch/ppc/syslib/ppc8xx_pic.c @@ -10,7 +10,7 @@ #include #include "ppc8xx_pic.h" -extern int cpm_get_irq(struct pt_regs *regs); +extern int cpm_get_irq(void); /* The 8xx internal interrupt controller. It is usually * the only interrupt controller. Some boards, like the MBX and @@ -96,7 +96,7 @@ m8xx_get_irq(struct pt_regs *regs) * get back SIU_LEVEL7. In this case, return -1 */ if (irq == CPM_INTERRUPT) - irq = CPM_IRQ_OFFSET + cpm_get_irq(regs); + irq = CPM_IRQ_OFFSET + cpm_get_irq(); #if defined(CONFIG_PCI) else if (irq == ISA_BRIDGE_INT) { int isa_irq; diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c index 39a93dc6375..6fd4cdbada7 100644 --- a/arch/ppc/syslib/xilinx_pic.c +++ b/arch/ppc/syslib/xilinx_pic.c @@ -86,7 +86,7 @@ static struct hw_interrupt_type xilinx_intc = { }; int -xilinx_pic_get_irq(struct pt_regs *regs) +xilinx_pic_get_irq(void) { int irq; diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h index 3247bea5fc2..7b06b4e6bf3 100644 --- a/include/asm-ppc/commproc.h +++ b/include/asm-ppc/commproc.h @@ -690,8 +690,7 @@ typedef struct risc_timer_pram { #define CICR_IEN ((uint)0x00000080) /* Int. enable */ #define CICR_SPS ((uint)0x00000001) /* SCC Spread */ -extern void cpm_install_handler(int vec, - void (*handler)(void *, struct pt_regs *regs), void *dev_id); +extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); extern void cpm_free_handler(int vec); #endif /* __CPM_8XX__ */ diff --git a/include/asm-ppc/gt64260.h b/include/asm-ppc/gt64260.h index cd0ef644943..9e63b3cfffc 100644 --- a/include/asm-ppc/gt64260.h +++ b/include/asm-ppc/gt64260.h @@ -315,7 +315,7 @@ int gt64260_get_base(u32 *base); int gt64260_pci_exclude_device(u8 bus, u8 devfn); void gt64260_init_irq(void); -int gt64260_get_irq(struct pt_regs *regs); +int gt64260_get_irq(void); void gt64260_mpsc_progress(char *s, unsigned short hex); diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h index 7e9842805a2..64c8874618d 100644 --- a/include/asm-ppc/mpc52xx.h +++ b/include/asm-ppc/mpc52xx.h @@ -415,7 +415,7 @@ struct mpc52xx_cdm { #ifndef __ASSEMBLY__ extern void mpc52xx_init_irq(void); -extern int mpc52xx_get_irq(struct pt_regs *regs); +extern int mpc52xx_get_irq(void); extern unsigned long mpc52xx_find_end_of_memory(void); extern void mpc52xx_set_bat(void); diff --git a/include/asm-ppc/mv64x60.h b/include/asm-ppc/mv64x60.h index 663edbee3e9..db3776f1819 100644 --- a/include/asm-ppc/mv64x60.h +++ b/include/asm-ppc/mv64x60.h @@ -336,9 +336,9 @@ int mv64x60_pci_exclude_device(u8 bus, u8 devfn); void gt64260_init_irq(void); -int gt64260_get_irq(struct pt_regs *regs); +int gt64260_get_irq(void); void mv64360_init_irq(void); -int mv64360_get_irq(struct pt_regs *regs); +int mv64360_get_irq(void); u32 mv64x60_mask(u32 val, u32 num_bits); u32 mv64x60_shift_left(u32 val, u32 num_bits); -- GitLab From ebf7a227dd1d810203a19642655d2fa293f395dd Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Tue, 10 Oct 2006 04:36:54 +0200 Subject: [PATCH 0850/1619] [PATCH] mm: bug in set_page_dirty_buffers This was triggered, but not the fault of, the dirty page accounting patches. Suitable for -stable as well, after it goes upstream. Unable to handle kernel NULL pointer dereference at virtual address 0000004c EIP is at _spin_lock+0x12/0x66 Call Trace: [<401766e7>] __set_page_dirty_buffers+0x15/0xc0 [<401401e7>] set_page_dirty+0x2c/0x51 [<40140db2>] set_page_dirty_balance+0xb/0x3b [<40145d29>] __do_fault+0x1d8/0x279 [<40147059>] __handle_mm_fault+0x125/0x951 [<401133f1>] do_page_fault+0x440/0x59f [<4034d0c1>] error_code+0x39/0x40 [<08048a33>] 0x8048a33 Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds --- fs/buffer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/buffer.c b/fs/buffer.c index 16cfbcd254f..eeb8ac1aa85 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -701,7 +701,10 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode); */ int __set_page_dirty_buffers(struct page *page) { - struct address_space * const mapping = page->mapping; + struct address_space * const mapping = page_mapping(page); + + if (unlikely(!mapping)) + return !TestSetPageDirty(page); spin_lock(&mapping->private_lock); if (page_has_buffers(page)) { -- GitLab From d6a29252ad120457cd544d44b2fbea46a00734a7 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 10 Oct 2006 13:51:00 +1000 Subject: [PATCH 0851/1619] [POWERPC] Fix secondary CPU startup on old "powersurge" SMP powermacs On the old "powersurge" SMP powermacs, the second CPU is started up by sending it an IPI, which has the side effect of stopping the timebase clock (so the secondary CPU's timebase can be synchronized with the primary's). The routine that did this used udelay, which will hang forever when the timebase is stopped, since udelay now spins until the timebase reaches a certain value. The end result is that the kernel would hang when bringing up the second CPU. This fixes it by using a simple loop which just does a fixed number of iterations to generate the delay. These old systems were all clocked at around 200 MHz or so, so a fixed number of iterations is acceptable. Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/smp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 574cd205b30..eeb2ae5ffc5 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -328,6 +328,7 @@ static void __init smp_psurge_kick_cpu(int nr) { unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; unsigned long a; + int i; /* may need to flush here if secondary bats aren't setup */ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) @@ -340,7 +341,11 @@ static void __init smp_psurge_kick_cpu(int nr) mb(); psurge_set_ipi(nr); - udelay(10); + /* + * We can't use udelay here because the timebase is now frozen. + */ + for (i = 0; i < 2000; ++i) + barrier(); psurge_clr_ipi(nr); if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); -- GitLab From 9f2545c11869868fd3cde7098d99e690891e442c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 10 Oct 2006 11:45:45 +1000 Subject: [PATCH 0852/1619] [POWERPC] Fix i2c-powermac platform device usage i2c-powermac was written & merged right after Russell King's changes adding platform_driver... which I missed. Thus it still used struct device, causing crashes when hitting sleep/wakeup callbacks (it happened to work by luck so far, until early/late callbacks got added). This causes crashes on sleep/wakeup on PowerBooks with 2.6.19. The patch fixes it by using a proper platform_driver. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/i2c/busses/i2c-powermac.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index a508cb962d2..648d55533d8 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -182,9 +182,9 @@ static const struct i2c_algorithm i2c_powermac_algorithm = { }; -static int i2c_powermac_remove(struct device *dev) +static int i2c_powermac_remove(struct platform_device *dev) { - struct i2c_adapter *adapter = dev_get_drvdata(dev); + struct i2c_adapter *adapter = platform_get_drvdata(dev); struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter); int rc; @@ -195,16 +195,16 @@ static int i2c_powermac_remove(struct device *dev) if (rc) printk("i2c-powermac.c: Failed to remove bus %s !\n", adapter->name); - dev_set_drvdata(dev, NULL); + platform_set_drvdata(dev, NULL); kfree(adapter); return 0; } -static int i2c_powermac_probe(struct device *dev) +static int __devexit i2c_powermac_probe(struct platform_device *dev) { - struct pmac_i2c_bus *bus = dev->platform_data; + struct pmac_i2c_bus *bus = dev->dev.platform_data; struct device_node *parent = NULL; struct i2c_adapter *adapter; char name[32]; @@ -246,11 +246,11 @@ static int i2c_powermac_probe(struct device *dev) printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n"); return -ENOMEM; } - dev_set_drvdata(dev, adapter); + platform_set_drvdata(dev, adapter); strcpy(adapter->name, name); adapter->algo = &i2c_powermac_algorithm; i2c_set_adapdata(adapter, bus); - adapter->dev.parent = dev; + adapter->dev.parent = &dev->dev; pmac_i2c_attach_adapter(bus, adapter); rc = i2c_add_adapter(adapter); if (rc) { @@ -265,23 +265,25 @@ static int i2c_powermac_probe(struct device *dev) } -static struct device_driver i2c_powermac_driver = { - .name = "i2c-powermac", - .bus = &platform_bus_type, +static struct platform_driver i2c_powermac_driver = { .probe = i2c_powermac_probe, - .remove = i2c_powermac_remove, + .remove = __devexit_p(i2c_powermac_remove), + .driver = { + .name = "i2c-powermac", + .bus = &platform_bus_type, + }, }; static int __init i2c_powermac_init(void) { - driver_register(&i2c_powermac_driver); + platform_driver_register(&i2c_powermac_driver); return 0; } static void __exit i2c_powermac_cleanup(void) { - driver_unregister(&i2c_powermac_driver); + platform_driver_unregister(&i2c_powermac_driver); } module_init(i2c_powermac_init); -- GitLab From 10270613fb4d5a44c335cfa13e9626bf5743c01d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 10 Oct 2006 11:47:31 +1000 Subject: [PATCH 0853/1619] [POWERPC] Fix windfarm platform device usage The windfarm code uses a struct device_driver instead of platform_driver, which can cause crashes if any of the callbacks are called (like on module removal). This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/windfarm_pm112.c | 18 ++++++++++-------- drivers/macintosh/windfarm_pm81.c | 24 ++++++++++-------------- drivers/macintosh/windfarm_pm91.c | 24 ++++++++++-------------- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index ef66bf2778e..fa4b13f8936 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -650,24 +650,26 @@ static struct notifier_block pm112_events = { .notifier_call = pm112_wf_notify, }; -static int wf_pm112_probe(struct device *dev) +static int wf_pm112_probe(struct platform_device *dev) { wf_register_client(&pm112_events); return 0; } -static int wf_pm112_remove(struct device *dev) +static int __devexit wf_pm112_remove(struct platform_device *dev) { wf_unregister_client(&pm112_events); /* should release all sensors and controls */ return 0; } -static struct device_driver wf_pm112_driver = { - .name = "windfarm", - .bus = &platform_bus_type, +static struct platform_driver wf_pm112_driver = { .probe = wf_pm112_probe, - .remove = wf_pm112_remove, + .remove = __devexit_p(wf_pm112_remove), + .driver = { + .name = "windfarm", + .bus = &platform_bus_type, + }, }; static int __init wf_pm112_init(void) @@ -683,13 +685,13 @@ static int __init wf_pm112_init(void) ++nr_cores; printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n"); - driver_register(&wf_pm112_driver); + platform_driver_register(&wf_pm112_driver); return 0; } static void __exit wf_pm112_exit(void) { - driver_unregister(&wf_pm112_driver); + platform_driver_unregister(&wf_pm112_driver); } module_init(wf_pm112_init); diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 2ff546e4c92..2a944851b8e 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -131,8 +131,6 @@ static int wf_smu_mach_model; /* machine model id */ -static struct device *wf_smu_dev; - /* Controls & sensors */ static struct wf_sensor *sensor_cpu_power; static struct wf_sensor *sensor_cpu_temp; @@ -717,16 +715,14 @@ static int wf_init_pm(void) return 0; } -static int wf_smu_probe(struct device *ddev) +static int wf_smu_probe(struct platform_device *ddev) { - wf_smu_dev = ddev; - wf_register_client(&wf_smu_events); return 0; } -static int wf_smu_remove(struct device *ddev) +static int __devexit wf_smu_remove(struct platform_device *ddev) { wf_unregister_client(&wf_smu_events); @@ -766,16 +762,16 @@ static int wf_smu_remove(struct device *ddev) if (wf_smu_cpu_fans) kfree(wf_smu_cpu_fans); - wf_smu_dev = NULL; - return 0; } -static struct device_driver wf_smu_driver = { - .name = "windfarm", - .bus = &platform_bus_type, +static struct platform_driver wf_smu_driver = { .probe = wf_smu_probe, - .remove = wf_smu_remove, + .remove = __devexit_p(wf_smu_remove), + .driver = { + .name = "windfarm", + .bus = &platform_bus_type, + }, }; @@ -794,7 +790,7 @@ static int __init wf_smu_init(void) request_module("windfarm_lm75_sensor"); #endif /* MODULE */ - driver_register(&wf_smu_driver); + platform_driver_register(&wf_smu_driver); } return rc; @@ -803,7 +799,7 @@ static int __init wf_smu_init(void) static void __exit wf_smu_exit(void) { - driver_unregister(&wf_smu_driver); + platform_driver_unregister(&wf_smu_driver); } diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 59e9ffe37c3..9961a67b4f8 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -63,8 +63,6 @@ */ #undef HACKED_OVERTEMP -static struct device *wf_smu_dev; - /* Controls & sensors */ static struct wf_sensor *sensor_cpu_power; static struct wf_sensor *sensor_cpu_temp; @@ -641,16 +639,14 @@ static int wf_init_pm(void) return 0; } -static int wf_smu_probe(struct device *ddev) +static int wf_smu_probe(struct platform_device *ddev) { - wf_smu_dev = ddev; - wf_register_client(&wf_smu_events); return 0; } -static int wf_smu_remove(struct device *ddev) +static int __devexit wf_smu_remove(struct platform_device *ddev) { wf_unregister_client(&wf_smu_events); @@ -698,16 +694,16 @@ static int wf_smu_remove(struct device *ddev) if (wf_smu_cpu_fans) kfree(wf_smu_cpu_fans); - wf_smu_dev = NULL; - return 0; } -static struct device_driver wf_smu_driver = { - .name = "windfarm", - .bus = &platform_bus_type, +static struct platform_driver wf_smu_driver = { .probe = wf_smu_probe, - .remove = wf_smu_remove, + .remove = __devexit_p(wf_smu_remove), + .driver = { + .name = "windfarm", + .bus = &platform_bus_type, + }, }; @@ -725,7 +721,7 @@ static int __init wf_smu_init(void) request_module("windfarm_lm75_sensor"); #endif /* MODULE */ - driver_register(&wf_smu_driver); + platform_driver_register(&wf_smu_driver); } return rc; @@ -734,7 +730,7 @@ static int __init wf_smu_init(void) static void __exit wf_smu_exit(void) { - driver_unregister(&wf_smu_driver); + platform_driver_unregister(&wf_smu_driver); } -- GitLab From 833abf7fe011c3dfe9bcab405856b73deab17062 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 10 Oct 2006 18:33:10 +0900 Subject: [PATCH 0854/1619] sh: Zero-out coherent buffer in consistent_alloc(). Be sure to zero out the buffer, this was causing occasional problems under heavier PCI tests. Signed-off-by: Paul Mundt --- arch/sh/mm/consistent.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index c81e6b67ad3..38c82d890ff 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -28,6 +28,7 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle) split_page(page, order); ret = page_address(page); + memset(ret, 0, size); *handle = virt_to_phys(ret); /* -- GitLab From e52e6080ca10e0a8ce2a35c86965945cdfa8ed7e Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Tue, 3 Oct 2006 09:46:41 -0500 Subject: [PATCH 0855/1619] RDMA/amso1100: Add spinlocks to serialize ib_post_send/ib_post_recv The AMSO driver was not thread-safe in the post WR code and had code that would sleep if the WR post FIFO was full. Since these functions can be called on interrupt level I changed the sleep to a udelay. Signed-off-by: Tom Tucker Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2_qp.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c index 12261132b07..5bcf697aa33 100644 --- a/drivers/infiniband/hw/amso1100/c2_qp.c +++ b/drivers/infiniband/hw/amso1100/c2_qp.c @@ -35,6 +35,8 @@ * */ +#include + #include "c2.h" #include "c2_vq.h" #include "c2_status.h" @@ -705,10 +707,8 @@ static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared) * cannot get on the bus and the card and system hang in a * deadlock -- thus the need for this code. [TOT] */ - while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(0); - } + while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000) + udelay(10); __raw_writel(C2_HINT_MAKE(mq_index, shared), c2dev->regs + PCI_BAR0_ADAPTER_HINT); @@ -766,6 +766,7 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, struct c2_dev *c2dev = to_c2dev(ibqp->device); struct c2_qp *qp = to_c2qp(ibqp); union c2wr wr; + unsigned long lock_flags; int err = 0; u32 flags; @@ -881,8 +882,10 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, /* * Post the puppy! */ + spin_lock_irqsave(&qp->lock, lock_flags); err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size); if (err) { + spin_unlock_irqrestore(&qp->lock, lock_flags); break; } @@ -890,6 +893,7 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, * Enqueue mq index to activity FIFO. */ c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count); + spin_unlock_irqrestore(&qp->lock, lock_flags); ib_wr = ib_wr->next; } @@ -905,6 +909,7 @@ int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, struct c2_dev *c2dev = to_c2dev(ibqp->device); struct c2_qp *qp = to_c2qp(ibqp); union c2wr wr; + unsigned long lock_flags; int err = 0; if (qp->state > IB_QPS_RTS) @@ -945,8 +950,10 @@ int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, break; } + spin_lock_irqsave(&qp->lock, lock_flags); err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size); if (err) { + spin_unlock_irqrestore(&qp->lock, lock_flags); break; } @@ -954,6 +961,7 @@ int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, * Enqueue mq index to activity FIFO */ c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count); + spin_unlock_irqrestore(&qp->lock, lock_flags); ib_wr = ib_wr->next; } -- GitLab From 9b0af401aae336975e620fccdd294bb763424f3f Mon Sep 17 00:00:00 2001 From: Ishai Rabinovitz Date: Tue, 10 Oct 2006 09:51:14 -0700 Subject: [PATCH 0856/1619] IB/srp: Remove redundant memset() scsi_host_alloc() already allocates with kzalloc(), so the struct Scsi_Host is zeroed out, including the private data portion. Remove the redundant memset that zeros this out again in the SRP initiator. Signed-off-by: Ishai Rabinovitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 44b9e5be668..f1b7a0f2bee 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1708,7 +1708,6 @@ static ssize_t srp_create_target(struct class_device *class_dev, target_host->max_lun = SRP_MAX_LUN; target = host_to_target(target_host); - memset(target, 0, sizeof *target); target->io_class = SRP_REV16A_IB_IO_CLASS; target->scsi_host = target_host; -- GitLab From 01cb9bcbd34b7ba768a7f05375faf43becdb8a60 Mon Sep 17 00:00:00 2001 From: Ishai Rabinovitz Date: Wed, 4 Oct 2006 15:28:56 +0200 Subject: [PATCH 0857/1619] IB/srp: Enable multiple connections to the same target Enable multiple concurrent connections to the same SRP target: 1) Use port GUID instead of node GUID in the initiator port identifier. This allows connections to be made from multiple HCA ports at the same time. 2) Let the user specify the identifier extention when adding the device. This allows userspace to make multiple connections even from the same port, if it wants too. Without this, only one connection can be made from any given HCA, even if it has multiple ports, because we don't use multi-channel mode, so targets will only allow one connection from a given initiator port ID. Signed-off-by: Ishai Rabinovitz Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 26 +++++++++++++++++--------- drivers/infiniband/ulp/srp/ib_srp.h | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index f1b7a0f2bee..4b09147f438 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -343,29 +343,32 @@ static int srp_send_req(struct srp_target_port *target) */ if (target->io_class == SRP_REV10_IB_IO_CLASS) { memcpy(req->priv.initiator_port_id, - target->srp_host->initiator_port_id + 8, 8); + &target->path.sgid.global.interface_id, 8); memcpy(req->priv.initiator_port_id + 8, - target->srp_host->initiator_port_id, 8); + &target->initiator_ext, 8); memcpy(req->priv.target_port_id, &target->ioc_guid, 8); memcpy(req->priv.target_port_id + 8, &target->id_ext, 8); } else { memcpy(req->priv.initiator_port_id, - target->srp_host->initiator_port_id, 16); + &target->initiator_ext, 8); + memcpy(req->priv.initiator_port_id + 8, + &target->path.sgid.global.interface_id, 8); memcpy(req->priv.target_port_id, &target->id_ext, 8); memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); } /* * Topspin/Cisco SRP targets will reject our login unless we - * zero out the first 8 bytes of our initiator port ID. The - * second 8 bytes must be our local node GUID, but we always - * use that anyway. + * zero out the first 8 bytes of our initiator port ID and set + * the second 8 bytes to the local node GUID. */ if (topspin_workarounds && !memcmp(&target->ioc_guid, topspin_oui, 3)) { printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround " "activated for target GUID %016llx\n", (unsigned long long) be64_to_cpu(target->ioc_guid)); memset(req->priv.initiator_port_id, 0, 8); + memcpy(req->priv.initiator_port_id + 8, + &target->srp_host->dev->dev->node_guid, 8); } status = ib_send_cm_req(target->cm_id, &req->param); @@ -1553,6 +1556,7 @@ enum { SRP_OPT_MAX_SECT = 1 << 5, SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, SRP_OPT_IO_CLASS = 1 << 7, + SRP_OPT_INITIATOR_EXT = 1 << 8, SRP_OPT_ALL = (SRP_OPT_ID_EXT | SRP_OPT_IOC_GUID | SRP_OPT_DGID | @@ -1569,6 +1573,7 @@ static match_table_t srp_opt_tokens = { { SRP_OPT_MAX_SECT, "max_sect=%d" }, { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, { SRP_OPT_IO_CLASS, "io_class=%x" }, + { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, { SRP_OPT_ERR, NULL } }; @@ -1668,6 +1673,12 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) target->io_class = token; break; + case SRP_OPT_INITIATOR_EXT: + p = match_strdup(args); + target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); + kfree(p); + break; + default: printk(KERN_WARNING PFX "unknown parameter or missing value " "'%s' in target creation request\n", p); @@ -1814,9 +1825,6 @@ static struct srp_host *srp_add_port(struct srp_device *device, u8 port) host->dev = device; host->port = port; - host->initiator_port_id[7] = port; - memcpy(host->initiator_port_id + 8, &device->dev->node_guid, 8); - host->class_dev.class = &srp_class; host->class_dev.dev = device->dev->dma_device; snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d", diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 5b581fb8eb0..d4e35ef5137 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -91,7 +91,6 @@ struct srp_device { }; struct srp_host { - u8 initiator_port_id[16]; struct srp_device *dev; u8 port; struct class_device class_dev; @@ -122,6 +121,7 @@ struct srp_target_port { __be64 id_ext; __be64 ioc_guid; __be64 service_id; + __be64 initiator_ext; u16 io_class; struct srp_host *srp_host; struct Scsi_Host *scsi_host; -- GitLab From a8bf4e7717142b0688a726dd07501a6a7783792a Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 4 Oct 2006 13:56:34 +0200 Subject: [PATCH 0858/1619] IB/mthca: Query port fix Fill in "max_vl_num" (encoded according to VLCap field in the PortInfo MAD) and "init_type_reply" values in the ib_query_port() verb. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_provider.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 981fe2eebdf..fc67f780581 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -179,6 +179,8 @@ static int mthca_query_port(struct ib_device *ibdev, props->max_mtu = out_mad->data[41] & 0xf; props->active_mtu = out_mad->data[36] >> 4; props->subnet_timeout = out_mad->data[51] & 0x1f; + props->max_vl_num = out_mad->data[37] >> 4; + props->init_type_reply = out_mad->data[41] >> 4; out: kfree(in_mad); -- GitLab From 8575329d4f8596519d86830f622d2c30601f3ef3 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 4 Oct 2006 11:29:59 -0700 Subject: [PATCH 0859/1619] IB/cm: Fix timewait crash after module unload If the ib_cm module is unloaded while id's are still in timewait, the CM will destroy the work queue used to process timewait. Once the id's exit timewait, their timers will fire, leading to a crash trying to access the destroyed work queue. We need to track id's that are in timewait, and cancel their deferred work on module unload. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 54 ++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index f35fcc4c063..470c482f288 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -75,6 +75,7 @@ static struct ib_cm { struct rb_root remote_sidr_table; struct idr local_id_table; __be32 random_id_operand; + struct list_head timewait_list; struct workqueue_struct *wq; } cm; @@ -112,6 +113,7 @@ struct cm_work { struct cm_timewait_info { struct cm_work work; /* Must be first. */ + struct list_head list; struct rb_node remote_qp_node; struct rb_node remote_id_node; __be64 remote_ca_guid; @@ -647,13 +649,6 @@ static inline int cm_convert_to_ms(int iba_time) static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info) { - unsigned long flags; - - if (!timewait_info->inserted_remote_id && - !timewait_info->inserted_remote_qp) - return; - - spin_lock_irqsave(&cm.lock, flags); if (timewait_info->inserted_remote_id) { rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table); timewait_info->inserted_remote_id = 0; @@ -663,7 +658,6 @@ static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info) rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table); timewait_info->inserted_remote_qp = 0; } - spin_unlock_irqrestore(&cm.lock, flags); } static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) @@ -684,8 +678,12 @@ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) static void cm_enter_timewait(struct cm_id_private *cm_id_priv) { int wait_time; + unsigned long flags; + spin_lock_irqsave(&cm.lock, flags); cm_cleanup_timewait(cm_id_priv->timewait_info); + list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list); + spin_unlock_irqrestore(&cm.lock, flags); /* * The cm_id could be destroyed by the user before we exit timewait. @@ -701,9 +699,13 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv) static void cm_reset_to_idle(struct cm_id_private *cm_id_priv) { + unsigned long flags; + cm_id_priv->id.state = IB_CM_IDLE; if (cm_id_priv->timewait_info) { + spin_lock_irqsave(&cm.lock, flags); cm_cleanup_timewait(cm_id_priv->timewait_info); + spin_unlock_irqrestore(&cm.lock, flags); kfree(cm_id_priv->timewait_info); cm_id_priv->timewait_info = NULL; } @@ -1307,6 +1309,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, if (timewait_info) { cur_cm_id_priv = cm_get_id(timewait_info->work.local_id, timewait_info->work.remote_id); + cm_cleanup_timewait(cm_id_priv->timewait_info); spin_unlock_irqrestore(&cm.lock, flags); if (cur_cm_id_priv) { cm_dup_req_handler(work, cur_cm_id_priv); @@ -1315,7 +1318,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, cm_issue_rej(work->port, work->mad_recv_wc, IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ, NULL, 0); - goto error; + listen_cm_id_priv = NULL; + goto out; } /* Find matching listen request. */ @@ -1323,21 +1327,20 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, req_msg->service_id, req_msg->private_data); if (!listen_cm_id_priv) { + cm_cleanup_timewait(cm_id_priv->timewait_info); spin_unlock_irqrestore(&cm.lock, flags); cm_issue_rej(work->port, work->mad_recv_wc, IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ, NULL, 0); - goto error; + goto out; } atomic_inc(&listen_cm_id_priv->refcount); atomic_inc(&cm_id_priv->refcount); cm_id_priv->id.state = IB_CM_REQ_RCVD; atomic_inc(&cm_id_priv->work_count); spin_unlock_irqrestore(&cm.lock, flags); +out: return listen_cm_id_priv; - -error: cm_cleanup_timewait(cm_id_priv->timewait_info); - return NULL; } static int cm_req_handler(struct cm_work *work) @@ -2601,28 +2604,29 @@ static int cm_timewait_handler(struct cm_work *work) { struct cm_timewait_info *timewait_info; struct cm_id_private *cm_id_priv; - unsigned long flags; int ret; timewait_info = (struct cm_timewait_info *)work; - cm_cleanup_timewait(timewait_info); + spin_lock_irq(&cm.lock); + list_del(&timewait_info->list); + spin_unlock_irq(&cm.lock); cm_id_priv = cm_acquire_id(timewait_info->work.local_id, timewait_info->work.remote_id); if (!cm_id_priv) return -EINVAL; - spin_lock_irqsave(&cm_id_priv->lock, flags); + spin_lock_irq(&cm_id_priv->lock); if (cm_id_priv->id.state != IB_CM_TIMEWAIT || cm_id_priv->remote_qpn != timewait_info->remote_qpn) { - spin_unlock_irqrestore(&cm_id_priv->lock, flags); + spin_unlock_irq(&cm_id_priv->lock); goto out; } cm_id_priv->id.state = IB_CM_IDLE; ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); - spin_unlock_irqrestore(&cm_id_priv->lock, flags); + spin_unlock_irq(&cm_id_priv->lock); if (ret) cm_process_work(cm_id_priv, work); @@ -3374,6 +3378,7 @@ static int __init ib_cm_init(void) idr_init(&cm.local_id_table); get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand); idr_pre_get(&cm.local_id_table, GFP_KERNEL); + INIT_LIST_HEAD(&cm.timewait_list); cm.wq = create_workqueue("ib_cm"); if (!cm.wq) @@ -3391,7 +3396,20 @@ error: static void __exit ib_cm_cleanup(void) { + struct cm_timewait_info *timewait_info, *tmp; + + spin_lock_irq(&cm.lock); + list_for_each_entry(timewait_info, &cm.timewait_list, list) + cancel_delayed_work(&timewait_info->work.work); + spin_unlock_irq(&cm.lock); + destroy_workqueue(cm.wq); + + list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) { + list_del(&timewait_info->list); + kfree(timewait_info); + } + ib_unregister_client(&cm_client); idr_destroy(&cm.local_id_table); } -- GitLab From 82a9c16a10521a0ceadbd27a549f6e8d5e70e0ab Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 4 Oct 2006 11:37:25 -0700 Subject: [PATCH 0860/1619] IB/cm: Send DREP in response to unmatched DREQ Currently a DREP is only sent in response to a DREQ if a connection has been found matching the DREQ, and it is in the proper state. Once a DREP is sent, the local connection moves into timewait. Duplicate DREQs received while in this state result in re-sending the DREP. However, it's likely that the local connection will enter and exit timewait before the remote side times out a lost DREP and resends a DREQ. To handle this, we send a DREP in response to a DREQ, even if a local connection is not found. This avoids maintaining disconnected id's in timewait states for excessively long times, just to handle a lost DREP. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 470c482f288..25b1018a476 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1902,6 +1902,32 @@ out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); } EXPORT_SYMBOL(ib_send_cm_drep); +static int cm_issue_drep(struct cm_port *port, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_send_buf *msg = NULL; + struct cm_dreq_msg *dreq_msg; + struct cm_drep_msg *drep_msg; + int ret; + + ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); + if (ret) + return ret; + + dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad; + drep_msg = (struct cm_drep_msg *) msg->mad; + + cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid); + drep_msg->remote_comm_id = dreq_msg->local_comm_id; + drep_msg->local_comm_id = dreq_msg->remote_comm_id; + + ret = ib_post_send_mad(msg, NULL); + if (ret) + cm_free_msg(msg); + + return ret; +} + static int cm_dreq_handler(struct cm_work *work) { struct cm_id_private *cm_id_priv; @@ -1913,8 +1939,10 @@ static int cm_dreq_handler(struct cm_work *work) dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad; cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, dreq_msg->local_comm_id); - if (!cm_id_priv) + if (!cm_id_priv) { + cm_issue_drep(work->port, work->mad_recv_wc); return -EINVAL; + } work->cm_event.private_data = &dreq_msg->private_data; -- GitLab From 1031bfb93adf641436b2192170525b76e2eb25bd Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 10 Oct 2006 12:50:38 -0700 Subject: [PATCH 0861/1619] RDMA/amso1100: Fix build with debugging off Since pr_debug() has changed from a macro to an inline function when DEBUG is not defined, its arguments now need to be defined even when debugging is off. Therefore to_event_str() and to_qp_state_str() need to be moved out of #ifdef DEBUG. The compiler will throw the definitions away if DEBUG is not defined, but it needs to be able to see that the functions exist. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2_ae.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c index 3aae4978e1c..a31439bd3b6 100644 --- a/drivers/infiniband/hw/amso1100/c2_ae.c +++ b/drivers/infiniband/hw/amso1100/c2_ae.c @@ -66,7 +66,6 @@ static int c2_convert_cm_status(u32 c2_status) } } -#ifdef DEBUG static const char* to_event_str(int event) { static const char* event_str[] = { @@ -144,7 +143,6 @@ static const char *to_qp_state_str(int state) return ""; }; } -#endif void c2_ae_event(struct c2_dev *c2dev, u32 mq_index) { -- GitLab From 73fbe8be73512b8a3ffa3d20c9d7f531af99679c Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 10 Oct 2006 12:50:38 -0700 Subject: [PATCH 0862/1619] IPoIB: Check for DMA mapping error for TX packets Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index f426a69d9a4..8bf5e9ec7c9 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -355,6 +355,11 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, tx_req->skb = skb; addr = dma_map_single(priv->ca->dma_device, skb->data, skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(addr))) { + ++priv->stats.tx_errors; + dev_kfree_skb_any(skb); + return; + } pci_unmap_addr_set(tx_req, mapping, addr); if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), -- GitLab From 2cbe19d48af198f0070470a2d836828de24fe163 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 9 Oct 2006 18:06:32 +0200 Subject: [PATCH 0863/1619] IB/mthca: Fix off-by-one in mthca SRQ creation All HCAs (not just mem-free) need a spare SRQ entry, so bump srq->max by 1 in all cases. Noted by Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_srq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 0f316c87bf6..92a72f52152 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -201,6 +201,8 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, if (mthca_is_memfree(dev)) srq->max = roundup_pow_of_two(srq->max + 1); + else + srq->max = srq->max + 1; ds = max(64UL, roundup_pow_of_two(sizeof (struct mthca_next_seg) + @@ -277,7 +279,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, srq->first_free = 0; srq->last_free = srq->max - 1; - attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max; + attr->max_wr = srq->max - 1; attr->max_sge = srq->max_gs; return 0; @@ -413,7 +415,7 @@ int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark); } - srq_attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max; + srq_attr->max_wr = srq->max - 1; srq_attr->max_sge = srq->max_gs; out: -- GitLab From 1e0dbafd30b2e1cd17fd141f4cfd633078524e8c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:07 +0100 Subject: [PATCH 0864/1619] [PATCH] advansys __iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/scsi/advansys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 83695416b2c..587eac92079 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -3881,7 +3881,7 @@ typedef struct asc_board { /* * The following fields are used only for Wide Boards. */ - void *ioremap_addr; /* I/O Memory remap address. */ + void __iomem *ioremap_addr; /* I/O Memory remap address. */ ushort ioport; /* I/O Port address. */ ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */ adv_req_t *orig_reqp; /* adv_req_t memory block. */ -- GitLab From 90cbad65911b5952a03111423347a6ab38236e0b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:17 +0100 Subject: [PATCH 0865/1619] [PATCH] more fs/compat.c __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/compat.c b/fs/compat.c index 4d3fbcb2ddb..50624d4a70c 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1316,7 +1316,7 @@ compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, unsigned int nr_segs, unsigned int flags) { unsigned i; - struct iovec *iov; + struct iovec __user *iov; if (nr_segs > UIO_MAXIOV) return -EINVAL; iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); -- GitLab From 6aae8738473b7447284fe370d4e6816c02b4511b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:27 +0100 Subject: [PATCH 0866/1619] [PATCH] drivers/s390 misc sparse annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/s390/scsi/zfcp_erp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 862a411a4aa..c88babce9bc 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1987,7 +1987,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) sbale = &(adapter->response_queue.buffer[i]->element[0]); sbale->length = 0; sbale->flags = SBAL_FLAGS_LAST_ENTRY; - sbale->addr = 0; + sbale->addr = NULL; } ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " -- GitLab From 1acc04cd4c0b54ada85d0dd5d7c5efc3441261bf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:37 +0100 Subject: [PATCH 0867/1619] [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(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index d6f4ec467a4..53553c99cad 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; }; -- GitLab From 48343273e846d2612b7977f2503fd97503996fa0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:47 +0100 Subject: [PATCH 0868/1619] [PATCH] __iomem annotations in sunzilog Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- drivers/serial/sunzilog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index b11f6dea270..73dd2eedaaa 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1057,7 +1057,7 @@ static void sunzilog_free_tables(void) static void sunzilog_putchar(struct uart_port *port, int ch) { - struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); int loops = ZS_PUT_CHAR_MAX_DELAY; /* This is a timed polling loop so do not switch the explicit -- GitLab From aa7677d40072a97a861390f0ed1a8c25ce312201 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:57 +0100 Subject: [PATCH 0869/1619] [PATCH] NULL noise removal: advansys Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/scsi/advansys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 587eac92079..2b344356a29 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -3951,7 +3951,7 @@ typedef struct _PCI_CONFIG_SPACE_ /* Number of boards detected in system. */ STATIC int asc_board_count = 0; -STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; +STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL }; /* Overrun buffer used by all narrow boards. */ STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; @@ -6621,7 +6621,7 @@ adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp, dma_map_single(dev, scp->request_buffer, scp->request_bufflen, scp->sc_data_direction); } else { - scsiqp->vdata_addr = 0; + scsiqp->vdata_addr = NULL; scp->SCp.dma_handle = 0; } scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle); -- GitLab From 98ae6ccd8e15aeac1c624615c044deecf46a359a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:45:07 +0100 Subject: [PATCH 0870/1619] [PATCH] fix misannotations in loop.c Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d6bb8da955a..19a09a18727 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -295,7 +295,7 @@ fail: * and do_lo_send_write(). */ static int __do_lo_send_write(struct file *file, - u8 __user *buf, const int len, loff_t pos) + u8 *buf, const int len, loff_t pos) { ssize_t bw; mm_segment_t old_fs = get_fs(); @@ -324,7 +324,7 @@ static int do_lo_send_direct_write(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos, struct page *page) { ssize_t bw = __do_lo_send_write(lo->lo_backing_file, - (u8 __user *)kmap(bvec->bv_page) + bvec->bv_offset, + kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len, pos); kunmap(bvec->bv_page); cond_resched(); @@ -351,7 +351,7 @@ static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec, bvec->bv_offset, bvec->bv_len, pos >> 9); if (likely(!ret)) return __do_lo_send_write(lo->lo_backing_file, - (u8 __user *)page_address(page), bvec->bv_len, + page_address(page), bvec->bv_len, pos); printk(KERN_ERR "loop: Transfer error at byte offset %llu, " "length %i.\n", (unsigned long long)pos, bvec->bv_len); -- GitLab From 04b1add1ab9121898b7d63570aad2a9c7ee9cfa3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:45:17 +0100 Subject: [PATCH 0871/1619] [PATCH] misc sata __iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/ata/sata_sil.c | 2 +- drivers/ata/sata_svw.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index ae5edb80ea9..ca8d9931247 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -349,7 +349,7 @@ 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) { - void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 84025a2fd5b..db32d15b7fa 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -177,7 +177,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 dmactl; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ mb(); /* make sure PRD table writes are visible to controller */ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); @@ -205,7 +205,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void *mmio = (void *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; u8 dmactl; /* start host DMA transaction */ -- GitLab From cb04e6b61985d7fafcb9529e5fcff4689f0961d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:45:27 +0100 Subject: [PATCH 0872/1619] [PATCH] hwdep_compat missed __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- sound/core/hwdep_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c index 938f7758096..3827c0ceec8 100644 --- a/sound/core/hwdep_compat.c +++ b/sound/core/hwdep_compat.c @@ -33,7 +33,7 @@ struct snd_hwdep_dsp_image32 { static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw, struct snd_hwdep_dsp_image32 __user *src) { - struct snd_hwdep_dsp_image *dst; + struct snd_hwdep_dsp_image __user *dst; compat_caddr_t ptr; u32 val; -- GitLab From c714de5dcf41cee869c4a74e8783c6d9be459ef6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:45:37 +0100 Subject: [PATCH 0873/1619] [PATCH] devio __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/core/devio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2c9c9462d89..724822cac2b 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1216,7 +1216,7 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; - if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) + if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg)) return -EFAULT; return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg); @@ -1251,7 +1251,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) } free_async(as); - if (put_user((u32)(u64)addr, (u32 __user *)arg)) + if (put_user(ptr_to_compat(addr), (u32 __user *)arg)) return -EFAULT; return 0; } @@ -1520,7 +1520,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd case USBDEVFS_IOCTL32: snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); - ret = proc_ioctl_compat(ps, (compat_uptr_t)(long)p); + ret = proc_ioctl_compat(ps, ptr_to_compat(p)); break; #endif -- GitLab From 47b16539e1072afd2c964b97be4a95b5cf2ff801 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:45:47 +0100 Subject: [PATCH 0874/1619] [PATCH] drivers/dma trivial annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/dma/ioatdma.c | 4 ++-- drivers/dma/ioatdma.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c index f3bf1e230bc..0358419a0e4 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioatdma.c @@ -80,7 +80,7 @@ static int enumerate_dma_channels(struct ioat_device *device) static struct ioat_desc_sw *ioat_dma_alloc_descriptor( struct ioat_dma_chan *ioat_chan, - int flags) + gfp_t flags) { struct ioat_dma_descriptor *desc; struct ioat_desc_sw *desc_sw; @@ -686,7 +686,7 @@ static int __devinit ioat_probe(struct pci_dev *pdev, { int err; unsigned long mmio_start, mmio_len; - void *reg_base; + void __iomem *reg_base; struct ioat_device *device; err = pci_enable_device(pdev); diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h index a5d3b364416..62b26a9be4c 100644 --- a/drivers/dma/ioatdma.h +++ b/drivers/dma/ioatdma.h @@ -44,7 +44,7 @@ extern struct list_head dma_client_list; struct ioat_device { struct pci_dev *pdev; - void *reg_base; + void __iomem *reg_base; struct pci_pool *dma_pool; struct pci_pool *completion_pool; @@ -73,7 +73,7 @@ struct ioat_device { struct ioat_dma_chan { - void *reg_base; + void __iomem *reg_base; dma_cookie_t completed_cookie; unsigned long last_completion; -- GitLab From 28c4dadd3a7221f5b9cd5c7d03c499788b193353 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:45:57 +0100 Subject: [PATCH 0875/1619] [PATCH] tipc __user annotations Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- net/tipc/socket.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 32d778448a0..acfb852e7c9 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -941,7 +941,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, int sz_to_copy; int sz_copied = 0; int needed; - char *crs = m->msg_iov->iov_base; + char __user *crs = m->msg_iov->iov_base; unsigned char *buf_crs; u32 err; int res; @@ -1496,7 +1496,7 @@ static int setsockopt(struct socket *sock, return -ENOPROTOOPT; if (ol < sizeof(value)) return -EINVAL; - if ((res = get_user(value, (u32 *)ov))) + if ((res = get_user(value, (u32 __user *)ov))) return res; if (down_interruptible(&tsock->sem)) @@ -1541,7 +1541,7 @@ static int setsockopt(struct socket *sock, */ static int getsockopt(struct socket *sock, - int lvl, int opt, char __user *ov, int *ol) + int lvl, int opt, char __user *ov, int __user *ol) { struct tipc_sock *tsock = tipc_sk(sock->sk); int len; -- GitLab From ba46df984b8e8114c3cf19c51670fab084bd4196 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:07 +0100 Subject: [PATCH 0876/1619] [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(-) diff --git a/include/linux/compat.h b/include/linux/compat.h index ef5cd192784..f4ebf96f530 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 3efcfc7e9c6..b0ace3fd7eb 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 4aaf91951a4..b364e002619 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 c5cca3f65cb..50f24eea6cd 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) -- GitLab From cfa7fd72ca03ac2324e8e469bd4b9ecc6f53394c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:17 +0100 Subject: [PATCH 0877/1619] [PATCH] ia64/hp NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ia64/hp/sim/simeth.c | 2 +- arch/ia64/hp/sim/simscsi.c | 2 +- arch/ia64/hp/sim/simserial.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index be769ef326a..424e9257c9a 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -87,7 +87,7 @@ static int simeth_debug; /* set to 1 to get debug information */ */ static struct notifier_block simeth_dev_notifier = { simeth_device_event, - 0 + NULL }; diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index 8f0a16a79a6..bb87682bbb1 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c @@ -103,7 +103,7 @@ simscsi_interrupt (unsigned long val) while ((sc = queue[rd].sc) != 0) { atomic_dec(&num_reqs); - queue[rd].sc = 0; + queue[rd].sc = NULL; if (DBG) printk("simscsi_interrupt: done with %ld\n", sc->serial_number); (*sc->scsi_done)(sc); diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 5095778be53..caab986af70 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -92,7 +92,7 @@ static struct serial_uart_config uart_config[] = { { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, - { 0, 0} + { NULL, 0} }; struct tty_driver *hp_simserial_driver; @@ -555,7 +555,7 @@ static void shutdown(struct async_struct * info) if (info->xmit.buf) { free_page((unsigned long) info->xmit.buf); - info->xmit.buf = 0; + info->xmit.buf = NULL; } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -628,7 +628,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); info->event = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { if (info->close_delay) schedule_timeout_interruptible(info->close_delay); @@ -668,7 +668,7 @@ static void rs_hangup(struct tty_struct *tty) info->event = 0; state->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -769,7 +769,7 @@ startup(struct async_struct *info) /* * Insert serial port into IRQ chain. */ - info->prev_port = 0; + info->prev_port = NULL; info->next_port = IRQ_ports[state->irq]; if (info->next_port) info->next_port->prev_port = info; -- GitLab From a9f627c9df2b6a242cdc25d46f87191941cd0844 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:27 +0100 Subject: [PATCH 0878/1619] [PATCH] ia64/sn __iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/ia64/sn/pci/pcibr/pcibr_ate.c | 2 +- arch/ia64/sn/pci/tioce_provider.c | 42 ++++++++++++++-------------- include/asm-ia64/sn/pcibr_provider.h | 2 +- include/asm-ia64/sn/tioca_provider.h | 4 +-- include/asm-ia64/sn/tioce_provider.h | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c index 5eb1e1e078b..935029fc400 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c @@ -126,7 +126,7 @@ int pcibr_ate_alloc(struct pcibus_info *pcibus_info, int count) * Setup an Address Translation Entry as specified. Use either the Bridge * internal maps or the external map RAM, as appropriate. */ -static inline u64 *pcibr_ate_addr(struct pcibus_info *pcibus_info, +static inline u64 __iomem *pcibr_ate_addr(struct pcibus_info *pcibus_info, int ate_index) { if (ate_index < pcibus_info->pbi_int_ate_size) { diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index 0e81f68aaf8..46e16dcf597 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c @@ -53,7 +53,7 @@ */ static void inline -tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr) +tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr) { u64 mmr_base; u64 mmr_offset; @@ -62,7 +62,7 @@ tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr) return; mmr_base = kern->ce_common->ce_pcibus.bs_base; - mmr_offset = (u64)mmr_addr - mmr_base; + mmr_offset = (unsigned long)mmr_addr - mmr_base; if (mmr_offset < 0x45000) { u64 mmr_war_offset; @@ -79,7 +79,7 @@ tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr) } static void inline -tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) +tioce_mmr_war_post(struct tioce_kernel *kern, void __iomem *mmr_addr) { u64 mmr_base; u64 mmr_offset; @@ -88,7 +88,7 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) return; mmr_base = kern->ce_common->ce_pcibus.bs_base; - mmr_offset = (u64)mmr_addr - mmr_base; + mmr_offset = (unsigned long)mmr_addr - mmr_base; if (mmr_offset < 0x45000) { if (mmr_offset == 0x100) @@ -223,7 +223,7 @@ tioce_dma_d64(unsigned long ct_addr, int dma_flags) * @pci_dev. */ static inline void -pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base, +pcidev_to_tioce(struct pci_dev *pdev, struct tioce __iomem **base, struct tioce_kernel **kernel, int *port) { struct pcidev_info *pcidev_info; @@ -235,7 +235,7 @@ pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base, ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private; if (base) - *base = (struct tioce *)ce_common->ce_pcibus.bs_base; + *base = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base; if (kernel) *kernel = ce_kernel; @@ -275,13 +275,13 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, u64 pagesize; int msi_capable, msi_wanted; u64 *ate_shadow; - u64 *ate_reg; + u64 __iomem *ate_reg; u64 addr; - struct tioce *ce_mmr; + struct tioce __iomem *ce_mmr; u64 bus_base; struct tioce_dmamap *map; - ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base; + ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base; switch (type) { case TIOCE_ATE_M32: @@ -386,7 +386,7 @@ tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags) { int dma_ok; int port; - struct tioce *ce_mmr; + struct tioce __iomem *ce_mmr; struct tioce_kernel *ce_kern; u64 ct_upper; u64 ct_lower; @@ -461,7 +461,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) int i; int port; struct tioce_kernel *ce_kern; - struct tioce *ce_mmr; + struct tioce __iomem *ce_mmr; unsigned long flags; bus_addr = tioce_dma_barrier(bus_addr, 0); @@ -700,9 +700,9 @@ static void tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit) { int ate_index, last_ate, ps; - struct tioce *ce_mmr; + struct tioce __iomem *ce_mmr; - ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base; + ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base; ps = ce_kern->ce_ate3240_pagesize; ate_index = ATE_PAGE(base, ps); last_ate = ate_index + ATE_NPAGES(base, limit-base+1, ps) - 1; @@ -736,7 +736,7 @@ tioce_kern_init(struct tioce_common *tioce_common) int dev; u32 tmp; unsigned int seg, bus; - struct tioce *tioce_mmr; + struct tioce __iomem *tioce_mmr; struct tioce_kernel *tioce_kern; tioce_kern = kzalloc(sizeof(struct tioce_kernel), GFP_KERNEL); @@ -767,7 +767,7 @@ tioce_kern_init(struct tioce_common *tioce_common) * the ate's. */ - tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base; + tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base; tioce_mmr_clri(tioce_kern, &tioce_mmr->ce_ure_page_map, CE_URE_PAGESIZE_MASK); tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_ure_page_map, @@ -858,7 +858,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info) struct pcidev_info *pcidev_info; struct tioce_common *ce_common; struct tioce_kernel *ce_kern; - struct tioce *ce_mmr; + struct tioce __iomem *ce_mmr; u64 force_int_val; if (!sn_irq_info->irq_bridge) @@ -872,7 +872,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info) return; ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; - ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base; + ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base; ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private; /* @@ -953,7 +953,7 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) struct pcidev_info *pcidev_info; struct tioce_common *ce_common; struct tioce_kernel *ce_kern; - struct tioce *ce_mmr; + struct tioce __iomem *ce_mmr; int bit; u64 vector; @@ -962,7 +962,7 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) return; ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; - ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base; + ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base; ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private; bit = sn_irq_info->irq_int_bit; @@ -994,7 +994,7 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont cnodeid_t my_cnode, mem_cnode; struct tioce_common *tioce_common; struct tioce_kernel *tioce_kern; - struct tioce *tioce_mmr; + struct tioce __iomem *tioce_mmr; /* * Allocate kernel bus soft and copy from prom. @@ -1018,7 +1018,7 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont * interrupt handler. */ - tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base; + tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base; tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL); tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias, ~0ULL); diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h index e3b0c3fe5ee..da3eade0cae 100644 --- a/include/asm-ia64/sn/pcibr_provider.h +++ b/include/asm-ia64/sn/pcibr_provider.h @@ -135,7 +135,7 @@ extern void pcireg_intr_addr_addr_set(struct pcibus_info *, int, u64 extern void pcireg_force_intr_set(struct pcibus_info *, int); extern u64 pcireg_wrb_flush_get(struct pcibus_info *, int); extern void pcireg_int_ate_set(struct pcibus_info *, int, u64); -extern u64 * pcireg_int_ate_addr(struct pcibus_info *, int); +extern u64 __iomem * pcireg_int_ate_addr(struct pcibus_info *, int); extern void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info); extern void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info); extern int pcibr_ate_alloc(struct pcibus_info *, int); diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h index 65cdd73c2a5..9a820ac61be 100644 --- a/include/asm-ia64/sn/tioca_provider.h +++ b/include/asm-ia64/sn/tioca_provider.h @@ -162,11 +162,11 @@ static inline void tioca_tlbflush(struct tioca_kernel *tioca_kernel) { volatile u64 tmp; - volatile struct tioca *ca_base; + volatile struct tioca __iomem *ca_base; struct tioca_common *tioca_common; tioca_common = tioca_kernel->ca_common; - ca_base = (struct tioca *)tioca_common->ca_common.bs_base; + ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base; /* * Explicit flushes not needed if GART is in cached mode diff --git a/include/asm-ia64/sn/tioce_provider.h b/include/asm-ia64/sn/tioce_provider.h index 6d62b13f7ae..32c32f30b09 100644 --- a/include/asm-ia64/sn/tioce_provider.h +++ b/include/asm-ia64/sn/tioce_provider.h @@ -53,7 +53,7 @@ struct tioce_dmamap { u64 ct_start; /* coretalk start address */ u64 pci_start; /* bus start address */ - u64 *ate_hw; /* hw ptr of first ate in map */ + u64 __iomem *ate_hw;/* hw ptr of first ate in map */ u64 *ate_shadow; /* shadow ptr of firat ate */ u16 ate_count; /* # ate's in the map */ }; -- GitLab From afc12d30a74415a49a6ce36d89f82641b46c499b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:37 +0100 Subject: [PATCH 0879/1619] [PATCH] mtd: remove several bogus casts to void * in iounmap() argument Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/mtd/maps/physmap.c | 2 +- drivers/mtd/nand/cs553x_nand.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index bc7cc71788b..d1717763f71 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -62,7 +62,7 @@ static int physmap_flash_remove(struct platform_device *dev) } if (info->map.virt != NULL) - iounmap((void *)info->map.virt); + iounmap(info->map.virt); if (info->res != NULL) { release_resource(info->res); diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index e0a1d386e58..94924d52a9b 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -249,7 +249,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out; out_ior: - iounmap((void *)this->IO_ADDR_R); + iounmap(this->IO_ADDR_R); out_mtd: kfree(new_mtd); out: -- GitLab From fb136e97840872638cb08588c4c9b9fff7f7c456 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:47 +0100 Subject: [PATCH 0880/1619] [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(-) diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h index de73a3289cc..51e2b9fb637 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; -- GitLab From ba2397efe10ba728c7ff22b179e218c292227c13 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:57 +0100 Subject: [PATCH 0881/1619] [PATCH] make kernel/relay.c __user-clean Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- kernel/relay.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/kernel/relay.c b/kernel/relay.c index 1d63ecddfa7..f04bbdb56ac 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -887,7 +887,7 @@ static int subbuf_read_actor(size_t read_start, from = buf->start + read_start; ret = avail; - if (copy_to_user(desc->arg.data, from, avail)) { + if (copy_to_user(desc->arg.buf, from, avail)) { desc->error = -EFAULT; ret = 0; } @@ -946,24 +946,17 @@ typedef int (*subbuf_actor_t) (size_t read_start, */ static inline ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos, - size_t count, subbuf_actor_t subbuf_actor, read_actor_t actor, - void *target) + read_descriptor_t *desc) { struct rchan_buf *buf = filp->private_data; size_t read_start, avail; - read_descriptor_t desc; int ret; - if (!count) + if (!desc->count) return 0; - desc.written = 0; - desc.count = count; - desc.arg.data = target; - desc.error = 0; - mutex_lock(&filp->f_dentry->d_inode->i_mutex); do { if (!relay_file_read_avail(buf, *ppos)) @@ -974,19 +967,19 @@ static inline ssize_t relay_file_read_subbufs(struct file *filp, if (!avail) break; - avail = min(desc.count, avail); - ret = subbuf_actor(read_start, buf, avail, &desc, actor); - if (desc.error < 0) + avail = min(desc->count, avail); + ret = subbuf_actor(read_start, buf, avail, desc, actor); + if (desc->error < 0) break; if (ret) { relay_file_read_consume(buf, read_start, ret); *ppos = relay_file_read_end_pos(buf, read_start, ret); } - } while (desc.count && ret); + } while (desc->count && ret); mutex_unlock(&filp->f_dentry->d_inode->i_mutex); - return desc.written; + return desc->written; } static ssize_t relay_file_read(struct file *filp, @@ -994,8 +987,13 @@ static ssize_t relay_file_read(struct file *filp, size_t count, loff_t *ppos) { - return relay_file_read_subbufs(filp, ppos, count, subbuf_read_actor, - NULL, buffer); + read_descriptor_t desc; + desc.written = 0; + desc.count = count; + desc.arg.buf = buffer; + desc.error = 0; + return relay_file_read_subbufs(filp, ppos, subbuf_read_actor, + NULL, &desc); } static ssize_t relay_file_sendfile(struct file *filp, @@ -1004,8 +1002,13 @@ static ssize_t relay_file_sendfile(struct file *filp, read_actor_t actor, void *target) { - return relay_file_read_subbufs(filp, ppos, count, subbuf_send_actor, - actor, target); + read_descriptor_t desc; + desc.written = 0; + desc.count = count; + desc.arg.data = target; + desc.error = 0; + return relay_file_read_subbufs(filp, ppos, subbuf_send_actor, + actor, &desc); } struct file_operations relay_file_operations = { -- GitLab From e4cad1b5a4851c90c1bcf460062074a2fa10815b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:07 +0100 Subject: [PATCH 0882/1619] [PATCH] passing pointer to setup_timer() should be via unsigned long Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/mmc/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 6d024342b2f..9a7d39b7cdb 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -1329,7 +1329,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) tasklet_init(&host->finish_tasklet, sdhci_tasklet_finish, (unsigned long)host); - setup_timer(&host->timer, sdhci_timeout_timer, (long)host); + setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, host->slot_descr, host); -- GitLab From 4370df9782a8456039cf85d2b833c2c2097f3ded Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:17 +0100 Subject: [PATCH 0883/1619] [PATCH] acpi NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/acpi/cm_sbs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index a01ce6700bf..4a9b7bf6f44 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -67,7 +67,7 @@ void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param) lock_ac_dir_cnt--; if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) { remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); - acpi_ac_dir = 0; + acpi_ac_dir = NULL; } mutex_unlock(&cm_sbs_mutex); } @@ -99,7 +99,7 @@ void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param) if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param && acpi_battery_dir) { remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); - acpi_battery_dir = 0; + acpi_battery_dir = NULL; } mutex_unlock(&cm_sbs_mutex); return; -- GitLab From 29756fa3287ff702535e459e7ca8c6038f6e9ae3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:27 +0100 Subject: [PATCH 0884/1619] [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(-) diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index d6e031542c6..ffdf9df1a67 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 1f996621bc9..b55e2a03560 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]; -- GitLab From 86f93336543314ffc46787845b631029cf11d6f8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:37 +0100 Subject: [PATCH 0885/1619] [PATCH] ptrace32 trivial __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/x86_64/ia32/ptrace32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index d18198ed636..3a7561d4703 100644 --- a/arch/x86_64/ia32/ptrace32.c +++ b/arch/x86_64/ia32/ptrace32.c @@ -205,9 +205,9 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val) static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data) { int ret; - compat_siginfo_t *si32 = (compat_siginfo_t *)compat_ptr(data); + compat_siginfo_t __user *si32 = compat_ptr(data); siginfo_t ssi; - siginfo_t *si = compat_alloc_user_space(sizeof(siginfo_t)); + siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t)); if (request == PTRACE_SETSIGINFO) { memset(&ssi, 0, sizeof(siginfo_t)); ret = copy_siginfo_from_user32(&ssi, si32); -- GitLab From fa1f5ea860af34d74c1475eddde3364e71fac15d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:47 +0100 Subject: [PATCH 0886/1619] [PATCH] gfp annotations: scsi_error Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/scsi/scsi_error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 3d355d05461..aff1b0cfd4b 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -495,7 +495,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, memcpy(scmd->cmnd, cmnd, cmnd_size); if (copy_sense) { - int gfp_mask = GFP_ATOMIC; + gfp_t gfp_mask = GFP_ATOMIC; if (shost->hostt->unchecked_isa_dma) gfp_mask |= __GFP_DMA; -- GitLab From 20241ad409fbc42d9e7f92f5fdb4783b7f1b36eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:57 +0100 Subject: [PATCH 0887/1619] [PATCH] gfp annotations: radix_tree_root struct radix_tree_root has unused upper bits of ->gfp_mask reused for tags bitmap. Annotated. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- lib/radix-tree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 637d55608de..aa9bfd0bdbd 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -160,13 +160,13 @@ static inline int tag_get(struct radix_tree_node *node, unsigned int tag, static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) { - root->gfp_mask |= (1 << (tag + __GFP_BITS_SHIFT)); + root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT)); } static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) { - root->gfp_mask &= ~(1 << (tag + __GFP_BITS_SHIFT)); + root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT)); } static inline void root_tag_clear_all(struct radix_tree_root *root) @@ -176,7 +176,7 @@ static inline void root_tag_clear_all(struct radix_tree_root *root) static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) { - return root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); + return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); } /* -- GitLab From 03dc55064117508ad474f3eede3a77bf9fbb636f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:48:07 +0100 Subject: [PATCH 0888/1619] [PATCH] trivial iomem annotations: sata_promise Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/ata/sata_promise.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index d636ede064a..8bcdfa64667 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -360,7 +360,7 @@ static void pdc_sata_phy_reset(struct ata_port *ap) static void pdc_pata_cbl_detect(struct ata_port *ap) { u8 tmp; - void __iomem *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; tmp = readb(mmio); -- GitLab From a6ded1b0605376e18a17cb01977819bcf2677cdc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:48:17 +0100 Subject: [PATCH 0889/1619] [PATCH] openprom NULL noise removal Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- drivers/sbus/char/openprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 2f698763ba5..81ba2d71cee 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -630,7 +630,7 @@ static int openprom_ioctl(struct inode * inode, struct file * file, case OPROMPATH2NODE: if ((file->f_mode & FMODE_READ) == 0) return -EPERM; - return openprom_sunos_ioctl(inode, file, cmd, arg, 0); + return openprom_sunos_ioctl(inode, file, cmd, arg, NULL); case OPIOCGET: case OPIOCNEXTPROP: -- GitLab From ba674cfcbdb93cb560a4ae4d2c8b53cfbddc2d22 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:48:27 +0100 Subject: [PATCH 0890/1619] [PATCH] __user annotations: loop.c Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 19a09a18727..beab6d2643c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1187,7 +1187,7 @@ struct compat_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, +loop_info64_from_compat(const struct compat_loop_info __user *arg, struct loop_info64 *info64) { struct compat_loop_info info; -- GitLab From 663d1ba2f1f66db43ab95350f965c1d9f2e3e5bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:48:37 +0100 Subject: [PATCH 0891/1619] [PATCH] em28xx NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/media/video/em28xx/em28xx-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 20df657b70c..2a461dde480 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -174,7 +174,7 @@ static void em28xx_config_i2c(struct em28xx *dev) route.input = INPUT(dev->ctl_input)->vmux; route.output = 0; - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0); + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); -- GitLab From e6c6e640b8b258dc7f60533e81f050d15fc0a9af Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:48:47 +0100 Subject: [PATCH 0892/1619] [PATCH] fs/inode.c NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/inode.c b/fs/inode.c index bf6bec4e54f..d9a21d12292 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -162,7 +162,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; } - inode->i_private = 0; + inode->i_private = NULL; inode->i_mapping = mapping; } return inode; -- GitLab From 1af9892811ad3bf2abb31566bfb2ec0b5070a66a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:48:57 +0100 Subject: [PATCH 0893/1619] [PATCH] cpuset ANSI prototype Signed-off-by: Al Viro Acked-by: Paul Jackson Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 9d850ae13b1..6313c38c930 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2137,7 +2137,7 @@ static int cpuset_handle_cpuhp(struct notifier_block *nb, * See also the previous routine cpuset_handle_cpuhp(). */ -void cpuset_track_online_nodes() +void cpuset_track_online_nodes(void) { common_cpu_mem_hotplug_unplug(); } -- GitLab From 5e7ddac75deaa2887e2b03441f9bed67ea8648d8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:49:07 +0100 Subject: [PATCH 0894/1619] [PATCH] ptrdiff_t is %t, not %z Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- net/ipv4/ipvs/ip_vs_ftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c index e433cb0ff89..6d398f10aa9 100644 --- a/net/ipv4/ipvs/ip_vs_ftp.c +++ b/net/ipv4/ipvs/ip_vs_ftp.c @@ -274,7 +274,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, while (data <= data_limit - 6) { if (strnicmp(data, "PASV\r\n", 6) == 0) { /* Passive mode on */ - IP_VS_DBG(7, "got PASV at %zd of %zd\n", + IP_VS_DBG(7, "got PASV at %td of %td\n", data - data_start, data_limit - data_start); cp->app_data = &ip_vs_ftp_pasv; -- GitLab From 86b95c12139785a0f4c17cb7b4cb865e7084cd34 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:49:17 +0100 Subject: [PATCH 0895/1619] [PATCH] strndup() would better take size_t, not int Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- net/irda/irias_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c index a154b1d71c0..56292ab7d65 100644 --- a/net/irda/irias_object.c +++ b/net/irda/irias_object.c @@ -43,7 +43,7 @@ struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}}; * * Faster, check boundary... Jean II */ -static char *strndup(char *str, int max) +static char *strndup(char *str, size_t max) { char *new_str; int len; -- GitLab From cfbdbab0634cafae2c43371396e5443cf4d5d7bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:49:27 +0100 Subject: [PATCH 0896/1619] [PATCH] net/sunrpc/auth_gss/svcauth_gss.c endianness regression Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- net/sunrpc/auth_gss/svcauth_gss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 447d9aef460..1f0f079ffa6 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1146,10 +1146,11 @@ out: return ret; } -u32 * +static __be32 * svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd) { - u32 *p, verf_len; + __be32 *p; + u32 verf_len; p = gsd->verf_start; gsd->verf_start = NULL; -- GitLab From 59bd59842617565b27acb0b55388363211123b9c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:49:37 +0100 Subject: [PATCH 0897/1619] [PATCH] missed const in prototype Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/um/drivers/pcap_user.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h index 58f9f6a1420..96b80b565ee 100644 --- a/arch/um/drivers/pcap_user.h +++ b/arch/um/drivers/pcap_user.h @@ -15,7 +15,7 @@ struct pcap_data { void *dev; }; -extern struct net_user_info pcap_user_info; +extern const struct net_user_info pcap_user_info; extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri); -- GitLab From 3c5c6658d2f1385cf06cdc00db9f7f124a35fb25 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:49:47 +0100 Subject: [PATCH 0898/1619] [PATCH] use %zu for size_t Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/scsi/dc395x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 23f5e418ab5..e95b367d09e 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1219,7 +1219,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb, srb, srb->cmd, srb->cmd->pid, srb->cmd->cmnd[0], srb->cmd->device->id, srb->cmd->device->lun); - printk(" sglist=%p cnt=%i idx=%i len=%Zd\n", + printk(" sglist=%p cnt=%i idx=%i len=%zu\n", srb->segment_x, srb->sg_count, srb->sg_index, srb->total_xfer_length); printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", -- GitLab From 70f38912935fd4aa3fea1ddf87ed1cee63109cc5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:49:57 +0100 Subject: [PATCH 0899/1619] [PATCH] use %p for pointers Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- drivers/sbus/char/uctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index ddc0681ac75..b30372f17f1 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -400,7 +400,7 @@ static int __init ts102_uctrl_init(void) } driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; - printk("uctrl: 0x%x (irq %d)\n", driver->regs, driver->irq); + printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); uctrl_get_event_status(); uctrl_get_external_status(); return 0; -- GitLab From 56052d525a05ba9e53d4f11be2d5deee64924514 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 1 Dec 2005 17:10:40 -0500 Subject: [PATCH 0900/1619] [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(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 2a0c50d84fc..7ea0f48f8fa 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 3c9b0bc0512..bbbe7b4da0b 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; -- GitLab From d08f74e58cad8f1844f6e01636a76dd52d41bb0f Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 23 Dec 2005 01:12:25 +0300 Subject: [PATCH 0901/1619] [PATCH] serpent: fix endian warnings Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- crypto/serpent.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crypto/serpent.c b/crypto/serpent.c index 465d091cd3e..2b0a19a44ec 100644 --- a/crypto/serpent.c +++ b/crypto/serpent.c @@ -364,10 +364,10 @@ static void serpent_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct serpent_ctx *ctx = crypto_tfm_ctx(tfm); const u32 - *k = ctx->expkey, - *s = (const u32 *)src; - u32 *d = (u32 *)dst, - r0, r1, r2, r3, r4; + *k = ctx->expkey; + const __le32 *s = (const __le32 *)src; + __le32 *d = (__le32 *)dst; + u32 r0, r1, r2, r3, r4; /* * Note: The conversions between u8* and u32* might cause trouble @@ -423,10 +423,10 @@ static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct serpent_ctx *ctx = crypto_tfm_ctx(tfm); const u32 - *k = ((struct serpent_ctx *)ctx)->expkey, - *s = (const u32 *)src; - u32 *d = (u32 *)dst, - r0, r1, r2, r3, r4; + *k = ((struct serpent_ctx *)ctx)->expkey; + const __le32 *s = (const __le32 *)src; + __le32 *d = (__le32 *)dst; + u32 r0, r1, r2, r3, r4; r0 = le32_to_cpu(s[0]); r1 = le32_to_cpu(s[1]); -- GitLab From 7359bbfd85751de23079cc26cd248635aebe840b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 23 Dec 2005 01:18:25 +0300 Subject: [PATCH 0902/1619] [PATCH] chelsio: add endian annotations Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/net/chelsio/cpl5_cmd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h index 27925e487bc..5b357d9e88d 100644 --- a/drivers/net/chelsio/cpl5_cmd.h +++ b/drivers/net/chelsio/cpl5_cmd.h @@ -108,7 +108,7 @@ struct cpl_tx_pkt_lso { u8 iff:4; #endif u16 vlan; - u32 len; + __be32 len; u32 rsvd2; u8 rsvd3; @@ -119,7 +119,7 @@ struct cpl_tx_pkt_lso { u8 ip_hdr_words:4; u8 tcp_hdr_words:4; #endif - u16 eth_type_mss; + __be16 eth_type_mss; }; struct cpl_rx_pkt { @@ -138,7 +138,7 @@ struct cpl_rx_pkt { u8 iff:4; #endif u16 csum; - u16 vlan; + __be16 vlan; u16 len; }; -- GitLab From 88c124d847d0fc60531e45323752665b01fc14f0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Dec 2005 20:56:46 -0500 Subject: [PATCH 0903/1619] [PATCH] befs: remove bogus typedef Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/befs/befs_fs_types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h index 63ef1e18fb8..d124b4c5117 100644 --- a/fs/befs/befs_fs_types.h +++ b/fs/befs/befs_fs_types.h @@ -81,7 +81,6 @@ enum inode_flags { typedef u64 befs_off_t; typedef u64 befs_time_t; -typedef void befs_binode_etc; /* Block runs */ typedef struct { -- GitLab From af10b0084dff530fb7232a0f8bbc4499e9c58574 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 01:13:13 -0500 Subject: [PATCH 0904/1619] [PATCH] befs: prepare to sanitizing headers pulled includes of endian.h from fs/befs/*.c to befs.h Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/befs/befs.h | 2 ++ fs/befs/btree.c | 1 - fs/befs/datastream.c | 1 - fs/befs/debug.c | 1 - fs/befs/endian.h | 1 - fs/befs/inode.c | 1 - fs/befs/linuxvfs.c | 1 - fs/befs/super.c | 1 - 8 files changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/befs/befs.h b/fs/befs/befs.h index 057a2c3d73b..c400bb6a6b7 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -151,4 +151,6 @@ befs_brun_size(struct super_block *sb, befs_block_run run) return BEFS_SB(sb)->block_size * run.len; } +#include "endian.h" + #endif /* _LINUX_BEFS_H */ diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 76e21979940..12e0fd60033 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -30,7 +30,6 @@ #include "befs.h" #include "btree.h" #include "datastream.h" -#include "endian.h" /* * The btree functions in this file are built on top of the diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index b7d6b920f65..67335e2853f 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -18,7 +18,6 @@ #include "befs.h" #include "datastream.h" #include "io.h" -#include "endian.h" const befs_inode_addr BAD_IADDR = { 0, 0, 0 }; diff --git a/fs/befs/debug.c b/fs/befs/debug.c index 875cc0aa318..3afd0882fdb 100644 --- a/fs/befs/debug.c +++ b/fs/befs/debug.c @@ -21,7 +21,6 @@ #endif /* __KERNEL__ */ #include "befs.h" -#include "endian.h" #define ERRBUFSIZE 1024 diff --git a/fs/befs/endian.h b/fs/befs/endian.h index 9ecaea4e332..d77a26e7bd9 100644 --- a/fs/befs/endian.h +++ b/fs/befs/endian.h @@ -10,7 +10,6 @@ #define LINUX_BEFS_ENDIAN #include -#include "befs.h" static inline u64 fs64_to_cpu(const struct super_block *sb, u64 n) diff --git a/fs/befs/inode.c b/fs/befs/inode.c index d41c9247ae8..94c17f9a957 100644 --- a/fs/befs/inode.c +++ b/fs/befs/inode.c @@ -8,7 +8,6 @@ #include "befs.h" #include "inode.h" -#include "endian.h" /* Validates the correctness of the befs inode diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 57020c7a7e6..07f7144f0e2 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -22,7 +22,6 @@ #include "datastream.h" #include "super.h" #include "io.h" -#include "endian.h" MODULE_DESCRIPTION("BeOS File System (BeFS) driver"); MODULE_AUTHOR("Will Dyson"); diff --git a/fs/befs/super.c b/fs/befs/super.c index 4557acbac52..8c3401ff6d6 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -11,7 +11,6 @@ #include "befs.h" #include "super.h" -#include "endian.h" /** * load_befs_sb -- Read from disk and properly byteswap all the fields -- GitLab From 1151895f8076584e061092afffb110b90cb38a68 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 01:32:03 -0500 Subject: [PATCH 0905/1619] [PATCH] befs: introduce on-disk endian types Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/befs/befs_fs_types.h | 4 ++++ fs/befs/endian.h | 36 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h index d124b4c5117..128066b1c4b 100644 --- a/fs/befs/befs_fs_types.h +++ b/fs/befs/befs_fs_types.h @@ -79,6 +79,10 @@ enum inode_flags { * On-Disk datastructures of BeFS */ +typedef u64 __bitwise fs64; +typedef u32 __bitwise fs32; +typedef u16 __bitwise fs16; + typedef u64 befs_off_t; typedef u64 befs_time_t; diff --git a/fs/befs/endian.h b/fs/befs/endian.h index d77a26e7bd9..979c543e6c5 100644 --- a/fs/befs/endian.h +++ b/fs/befs/endian.h @@ -12,57 +12,57 @@ #include static inline u64 -fs64_to_cpu(const struct super_block *sb, u64 n) +fs64_to_cpu(const struct super_block *sb, fs64 n) { if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) - return le64_to_cpu(n); + return le64_to_cpu((__force __le64)n); else - return be64_to_cpu(n); + return be64_to_cpu((__force __be64)n); } -static inline u64 +static inline fs64 cpu_to_fs64(const struct super_block *sb, u64 n) { if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) - return cpu_to_le64(n); + return (__force fs64)cpu_to_le64(n); else - return cpu_to_be64(n); + return (__force fs64)cpu_to_be64(n); } static inline u32 -fs32_to_cpu(const struct super_block *sb, u32 n) +fs32_to_cpu(const struct super_block *sb, fs32 n) { if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) - return le32_to_cpu(n); + return le32_to_cpu((__force __le32)n); else - return be32_to_cpu(n); + return be32_to_cpu((__force __be32)n); } -static inline u32 +static inline fs32 cpu_to_fs32(const struct super_block *sb, u32 n) { if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) - return cpu_to_le32(n); + return (__force fs32)cpu_to_le32(n); else - return cpu_to_be32(n); + return (__force fs32)cpu_to_be32(n); } static inline u16 -fs16_to_cpu(const struct super_block *sb, u16 n) +fs16_to_cpu(const struct super_block *sb, fs16 n) { if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) - return le16_to_cpu(n); + return le16_to_cpu((__force __le16)n); else - return be16_to_cpu(n); + return be16_to_cpu((__force __be16)n); } -static inline u16 +static inline fs16 cpu_to_fs16(const struct super_block *sb, u16 n) { if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) - return cpu_to_le16(n); + return (__force fs16)cpu_to_le16(n); else - return cpu_to_be16(n); + return (__force fs16)cpu_to_be16(n); } /* Composite types below here */ -- GitLab From e5201c58cd81066ecd0210bcc6c02e71200040a3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 03:09:03 -0500 Subject: [PATCH 0906/1619] [PATCH] befs: missing fs32_to_cpu() in debug.c inode->mode is disk-endian Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/befs/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/befs/debug.c b/fs/befs/debug.c index 3afd0882fdb..bb68370f649 100644 --- a/fs/befs/debug.c +++ b/fs/befs/debug.c @@ -124,7 +124,7 @@ befs_dump_inode(const struct super_block *sb, befs_inode * inode) befs_debug(sb, " type %08x", fs32_to_cpu(sb, inode->type)); befs_debug(sb, " inode_size %u", fs32_to_cpu(sb, inode->inode_size)); - if (S_ISLNK(inode->mode)) { + if (S_ISLNK(fs32_to_cpu(sb, inode->mode))) { befs_debug(sb, " Symbolic link [%s]", inode->data.symlink); } else { int i; -- GitLab From a9721f3152bc2be6702807705902e06abdd6e3bb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:28:55 -0500 Subject: [PATCH 0907/1619] [PATCH] befs: endianness annotations split the data structures that exist in host- and disk-endian variants, annotate the fields of disk-endian ones, propagate changes. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/befs/befs.h | 4 +- fs/befs/befs_fs_types.h | 107 ++++++++++++++++++++++++++-------------- fs/befs/btree.c | 28 +++++------ fs/befs/datastream.c | 10 ++-- fs/befs/debug.c | 9 ++-- fs/befs/endian.h | 20 ++++---- 6 files changed, 106 insertions(+), 72 deletions(-) diff --git a/fs/befs/befs.h b/fs/befs/befs.h index c400bb6a6b7..d9a40abda6b 100644 --- a/fs/befs/befs.h +++ b/fs/befs/befs.h @@ -94,7 +94,7 @@ void befs_debug(const struct super_block *sb, const char *fmt, ...); void befs_dump_super_block(const struct super_block *sb, befs_super_block *); void befs_dump_inode(const struct super_block *sb, befs_inode *); -void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *); +void befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super *); void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *); /****************************/ @@ -136,7 +136,7 @@ blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno) static inline unsigned int befs_iaddrs_per_block(struct super_block *sb) { - return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr); + return BEFS_SB(sb)->block_size / sizeof (befs_disk_inode_addr); } static inline int diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h index 128066b1c4b..e2595c2c403 100644 --- a/fs/befs/befs_fs_types.h +++ b/fs/befs/befs_fs_types.h @@ -84,15 +84,22 @@ typedef u32 __bitwise fs32; typedef u16 __bitwise fs16; typedef u64 befs_off_t; -typedef u64 befs_time_t; +typedef fs64 befs_time_t; /* Block runs */ +typedef struct { + fs32 allocation_group; + fs16 start; + fs16 len; +} PACKED befs_disk_block_run; + typedef struct { u32 allocation_group; u16 start; u16 len; } PACKED befs_block_run; +typedef befs_disk_block_run befs_disk_inode_addr; typedef befs_block_run befs_inode_addr; /* @@ -100,31 +107,31 @@ typedef befs_block_run befs_inode_addr; */ typedef struct { char name[B_OS_NAME_LENGTH]; - u32 magic1; - u32 fs_byte_order; + fs32 magic1; + fs32 fs_byte_order; - u32 block_size; - u32 block_shift; + fs32 block_size; + fs32 block_shift; - befs_off_t num_blocks; - befs_off_t used_blocks; + fs64 num_blocks; + fs64 used_blocks; - u32 inode_size; + fs32 inode_size; - u32 magic2; - u32 blocks_per_ag; - u32 ag_shift; - u32 num_ags; + fs32 magic2; + fs32 blocks_per_ag; + fs32 ag_shift; + fs32 num_ags; - u32 flags; + fs32 flags; - befs_block_run log_blocks; - befs_off_t log_start; - befs_off_t log_end; + befs_disk_block_run log_blocks; + fs64 log_start; + fs64 log_end; - u32 magic3; - befs_inode_addr root_dir; - befs_inode_addr indices; + fs32 magic3; + befs_disk_inode_addr root_dir; + befs_disk_inode_addr indices; } PACKED befs_super_block; @@ -132,6 +139,16 @@ typedef struct { * Note: the indirect and dbl_indir block_runs may * be longer than one block! */ +typedef struct { + befs_disk_block_run direct[BEFS_NUM_DIRECT_BLOCKS]; + fs64 max_direct_range; + befs_disk_block_run indirect; + fs64 max_indirect_range; + befs_disk_block_run double_indirect; + fs64 max_double_indirect_range; + fs64 size; +} PACKED befs_disk_data_stream; + typedef struct { befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS]; befs_off_t max_direct_range; @@ -144,35 +161,35 @@ typedef struct { /* Attribute */ typedef struct { - u32 type; - u16 name_size; - u16 data_size; + fs32 type; + fs16 name_size; + fs16 data_size; char name[1]; } PACKED befs_small_data; /* Inode structure */ typedef struct { - u32 magic1; - befs_inode_addr inode_num; - u32 uid; - u32 gid; - u32 mode; - u32 flags; + fs32 magic1; + befs_disk_inode_addr inode_num; + fs32 uid; + fs32 gid; + fs32 mode; + fs32 flags; befs_time_t create_time; befs_time_t last_modified_time; - befs_inode_addr parent; - befs_inode_addr attributes; - u32 type; + befs_disk_inode_addr parent; + befs_disk_inode_addr attributes; + fs32 type; - u32 inode_size; - u32 etc; /* not use */ + fs32 inode_size; + fs32 etc; /* not use */ union { - befs_data_stream datastream; + befs_disk_data_stream datastream; char symlink[BEFS_SYMLINK_LEN]; } data; - u32 pad[4]; /* not use */ + fs32 pad[4]; /* not use */ befs_small_data small_data[1]; } PACKED befs_inode; @@ -192,6 +209,16 @@ enum btree_types { BTREE_DOUBLE_TYPE = 6 }; +typedef struct { + fs32 magic; + fs32 node_size; + fs32 max_depth; + fs32 data_type; + fs64 root_node_ptr; + fs64 free_node_ptr; + fs64 max_size; +} PACKED befs_disk_btree_super; + typedef struct { u32 magic; u32 node_size; @@ -205,12 +232,20 @@ typedef struct { /* * Header stucture of each btree node */ +typedef struct { + fs64 left; + fs64 right; + fs64 overflow; + fs16 all_key_count; + fs16 all_key_length; +} PACKED befs_btree_nodehead; + typedef struct { befs_off_t left; befs_off_t right; befs_off_t overflow; u16 all_key_count; u16 all_key_length; -} PACKED befs_btree_nodehead; +} PACKED befs_host_btree_nodehead; #endif /* _LINUX_BEFS_FS_TYPES */ diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 12e0fd60033..81b042ee24e 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -79,7 +79,7 @@ * In memory structure of each btree node */ typedef struct { - befs_btree_nodehead head; /* head of node converted to cpu byteorder */ + befs_host_btree_nodehead head; /* head of node converted to cpu byteorder */ struct buffer_head *bh; befs_btree_nodehead *od_node; /* on disk node */ } befs_btree_node; @@ -101,9 +101,9 @@ static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds, static int befs_leafnode(befs_btree_node * node); -static u16 *befs_bt_keylen_index(befs_btree_node * node); +static fs16 *befs_bt_keylen_index(befs_btree_node * node); -static befs_off_t *befs_bt_valarray(befs_btree_node * node); +static fs64 *befs_bt_valarray(befs_btree_node * node); static char *befs_bt_keydata(befs_btree_node * node); @@ -135,7 +135,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds, befs_btree_super * sup) { struct buffer_head *bh = NULL; - befs_btree_super *od_sup = NULL; + befs_disk_btree_super *od_sup = NULL; befs_debug(sb, "---> befs_btree_read_super()"); @@ -145,7 +145,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds, befs_error(sb, "Couldn't read index header."); goto error; } - od_sup = (befs_btree_super *) bh->b_data; + od_sup = (befs_disk_btree_super *) bh->b_data; befs_dump_index_entry(sb, od_sup); sup->magic = fs32_to_cpu(sb, od_sup->magic); @@ -341,7 +341,7 @@ befs_find_key(struct super_block *sb, befs_btree_node * node, u16 keylen; int findkey_len; char *thiskey; - befs_off_t *valarray; + fs64 *valarray; befs_debug(sb, "---> befs_find_key() %s", findkey); @@ -421,7 +421,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds, befs_btree_super bt_super; befs_off_t node_off = 0; int cur_key; - befs_off_t *valarray; + fs64 *valarray; char *keystart; u16 keylen; int res; @@ -571,7 +571,7 @@ befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, this_node->head.overflow); *node_off = this_node->head.overflow; } else { - befs_off_t *valarray = befs_bt_valarray(this_node); + fs64 *valarray = befs_bt_valarray(this_node); *node_off = fs64_to_cpu(sb, valarray[0]); } if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { @@ -621,7 +621,7 @@ befs_leafnode(befs_btree_node * node) * * Except that rounding up to 8 works, and rounding up to 4 doesn't. */ -static u16 * +static fs16 * befs_bt_keylen_index(befs_btree_node * node) { const int keylen_align = 8; @@ -632,7 +632,7 @@ befs_bt_keylen_index(befs_btree_node * node) if (tmp) off += keylen_align - tmp; - return (u16 *) ((void *) node->od_node + off); + return (fs16 *) ((void *) node->od_node + off); } /** @@ -642,13 +642,13 @@ befs_bt_keylen_index(befs_btree_node * node) * Returns a pointer to the start of the value array * of the node pointed to by the node header */ -static befs_off_t * +static fs64 * befs_bt_valarray(befs_btree_node * node) { void *keylen_index_start = (void *) befs_bt_keylen_index(node); - size_t keylen_index_size = node->head.all_key_count * sizeof (u16); + size_t keylen_index_size = node->head.all_key_count * sizeof (fs16); - return (befs_off_t *) (keylen_index_start + keylen_index_size); + return (fs64 *) (keylen_index_start + keylen_index_size); } /** @@ -680,7 +680,7 @@ befs_bt_get_key(struct super_block *sb, befs_btree_node * node, { int prev_key_end; char *keystart; - u16 *keylen_index; + fs16 *keylen_index; if (index < 0 || index > node->head.all_key_count) { *keylen = 0; diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c index 67335e2853f..aacb4da6298 100644 --- a/fs/befs/datastream.c +++ b/fs/befs/datastream.c @@ -311,7 +311,7 @@ befs_find_brun_indirect(struct super_block *sb, befs_blocknr_t indir_start_blk; befs_blocknr_t search_blk; struct buffer_head *indirblock; - befs_block_run *array; + befs_disk_block_run *array; befs_block_run indirect = data->indirect; befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect); @@ -333,7 +333,7 @@ befs_find_brun_indirect(struct super_block *sb, return BEFS_ERR; } - array = (befs_block_run *) indirblock->b_data; + array = (befs_disk_block_run *) indirblock->b_data; for (j = 0; j < arraylen; ++j) { int len = fs16_to_cpu(sb, array[j].len); @@ -426,7 +426,7 @@ befs_find_brun_dblindirect(struct super_block *sb, struct buffer_head *dbl_indir_block; struct buffer_head *indir_block; befs_block_run indir_run; - befs_inode_addr *iaddr_array = NULL; + befs_disk_inode_addr *iaddr_array = NULL; befs_sb_info *befs_sb = BEFS_SB(sb); befs_blocknr_t indir_start_blk = @@ -481,7 +481,7 @@ befs_find_brun_dblindirect(struct super_block *sb, dbl_block_indx = dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb)); - iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data; + iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data; indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]); brelse(dbl_indir_block); iaddr_array = NULL; @@ -506,7 +506,7 @@ befs_find_brun_dblindirect(struct super_block *sb, } block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb)); - iaddr_array = (befs_inode_addr *) indir_block->b_data; + iaddr_array = (befs_disk_inode_addr *) indir_block->b_data; *run = fsrun_to_cpu(sb, iaddr_array[block_indx]); brelse(indir_block); iaddr_array = NULL; diff --git a/fs/befs/debug.c b/fs/befs/debug.c index bb68370f649..e831a8f3084 100644 --- a/fs/befs/debug.c +++ b/fs/befs/debug.c @@ -230,21 +230,20 @@ befs_dump_small_data(const struct super_block *sb, befs_small_data * sd) /* unused */ void -befs_dump_run(const struct super_block *sb, befs_block_run run) +befs_dump_run(const struct super_block *sb, befs_disk_block_run run) { #ifdef CONFIG_BEFS_DEBUG - run = fsrun_to_cpu(sb, run); + befs_block_run n = fsrun_to_cpu(sb, run); - befs_debug(sb, "[%u, %hu, %hu]", - run.allocation_group, run.start, run.len); + befs_debug(sb, "[%u, %hu, %hu]", n.allocation_group, n.start, n.len); #endif //CONFIG_BEFS_DEBUG } #endif /* 0 */ void -befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super) +befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super * super) { #ifdef CONFIG_BEFS_DEBUG diff --git a/fs/befs/endian.h b/fs/befs/endian.h index 979c543e6c5..e254a20869f 100644 --- a/fs/befs/endian.h +++ b/fs/befs/endian.h @@ -68,26 +68,26 @@ cpu_to_fs16(const struct super_block *sb, u16 n) /* Composite types below here */ static inline befs_block_run -fsrun_to_cpu(const struct super_block *sb, befs_block_run n) +fsrun_to_cpu(const struct super_block *sb, befs_disk_block_run n) { befs_block_run run; if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) { - run.allocation_group = le32_to_cpu(n.allocation_group); - run.start = le16_to_cpu(n.start); - run.len = le16_to_cpu(n.len); + run.allocation_group = le32_to_cpu((__force __le32)n.allocation_group); + run.start = le16_to_cpu((__force __le16)n.start); + run.len = le16_to_cpu((__force __le16)n.len); } else { - run.allocation_group = be32_to_cpu(n.allocation_group); - run.start = be16_to_cpu(n.start); - run.len = be16_to_cpu(n.len); + run.allocation_group = be32_to_cpu((__force __be32)n.allocation_group); + run.start = be16_to_cpu((__force __be16)n.start); + run.len = be16_to_cpu((__force __be16)n.len); } return run; } -static inline befs_block_run +static inline befs_disk_block_run cpu_to_fsrun(const struct super_block *sb, befs_block_run n) { - befs_block_run run; + befs_disk_block_run run; if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) { run.allocation_group = cpu_to_le32(n.allocation_group); @@ -102,7 +102,7 @@ cpu_to_fsrun(const struct super_block *sb, befs_block_run n) } static inline befs_data_stream -fsds_to_cpu(const struct super_block *sb, befs_data_stream n) +fsds_to_cpu(const struct super_block *sb, befs_disk_data_stream n) { befs_data_stream data; int i; -- GitLab From 31b1f85b71b0b69afba89a60989097cd805f13c3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:31:04 -0500 Subject: [PATCH 0908/1619] [PATCH] fs/fat endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/fat/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 045738032a8..4613cb20217 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -384,7 +384,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) le16_to_cpu(de->cdate)) + secs; inode->i_ctime.tv_nsec = csecs * 10000000; inode->i_atime.tv_sec = - date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate)); + date_dos2unix(0, le16_to_cpu(de->adate)); inode->i_atime.tv_nsec = 0; } else inode->i_ctime = inode->i_atime = inode->i_mtime; -- GitLab From 2ef1031282cd401b47a5f7f7477fe9ae69aff058 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:31:53 -0500 Subject: [PATCH 0909/1619] [PATCH] hpfs endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/hpfs/inode.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index bcf6ee36e06..7faef8544f3 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -60,14 +60,14 @@ void hpfs_read_inode(struct inode *i) if (hpfs_sb(i->i_sb)->sb_eas) { if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) { if (ea_size == 2) { - i->i_uid = le16_to_cpu(*(u16*)ea); + i->i_uid = le16_to_cpu(*(__le16*)ea); hpfs_inode->i_ea_uid = 1; } kfree(ea); } if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) { if (ea_size == 2) { - i->i_gid = le16_to_cpu(*(u16*)ea); + i->i_gid = le16_to_cpu(*(__le16*)ea); hpfs_inode->i_ea_gid = 1; } kfree(ea); @@ -87,7 +87,7 @@ void hpfs_read_inode(struct inode *i) int rdev = 0; umode_t mode = hpfs_sb(sb)->sb_mode; if (ea_size == 2) { - mode = le16_to_cpu(*(u16*)ea); + mode = le16_to_cpu(*(__le16*)ea); hpfs_inode->i_ea_mode = 1; } kfree(ea); @@ -95,7 +95,7 @@ void hpfs_read_inode(struct inode *i) if (S_ISBLK(mode) || S_ISCHR(mode)) { if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) { if (ea_size == 4) - rdev = le32_to_cpu(*(u32*)ea); + rdev = le32_to_cpu(*(__le32*)ea); kfree(ea); } } @@ -148,7 +148,7 @@ static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) we'd better not overwrite them hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino); } else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) { - u32 ea; + __le32 ea; if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) { ea = cpu_to_le32(i->i_uid); hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2); @@ -165,6 +165,7 @@ static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) && i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333)) | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) { ea = cpu_to_le32(i->i_mode); + /* sick, but legal */ hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2); hpfs_inode->i_ea_mode = 1; } -- GitLab From 6ca1584173d0320f47464092eb180a17259cc3f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:32:38 -0500 Subject: [PATCH 0910/1619] [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(-) diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index 367d6c3e8ed..13b3af54786 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)) -- GitLab From d02d48d8650bf3e2011f25373dbcf87f3c19f16b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:33:09 -0500 Subject: [PATCH 0911/1619] [PATCH] isofs endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/isofs/joliet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c index 81a90e170ac..fb8fe7a9ddc 100644 --- a/fs/isofs/joliet.c +++ b/fs/isofs/joliet.c @@ -14,9 +14,9 @@ * Convert Unicode 16 to UTF-8 or ASCII. */ static int -uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls) +uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls) { - wchar_t *ip, ch; + __be16 *ip, ch; unsigned char *op; ip = uni; @@ -24,8 +24,8 @@ uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls) while ((ch = get_unaligned(ip)) && len) { int llen; - ch = be16_to_cpu(ch); - if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0) + llen = nls->uni2char(be16_to_cpu(ch), op, NLS_MAX_CHARSET_SIZE); + if (llen > 0) op += llen; else *op++ = '?'; @@ -82,7 +82,7 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st len = wcsntombs_be(outname, de->name, de->name_len[0] >> 1, PAGE_SIZE); } else { - len = uni16_to_x8(outname, (u16 *) de->name, + len = uni16_to_x8(outname, (__be16 *) de->name, de->name_len[0] >> 1, nls); } if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) { -- GitLab From d136fe7243081a45a141bb297a7b7a627ab60fa9 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 28 Dec 2005 22:27:10 +0300 Subject: [PATCH 0912/1619] [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(-) diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index ab274083274..35cb3857358 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 da9cfe92715..60a508eb194 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; -- GitLab From 3524de1c7953e7a22c43b9214ffc3680af6f8edb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:39:13 -0500 Subject: [PATCH 0913/1619] [PATCH] fs/partitions endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/partitions/msdos.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 4f8df71e49d..8c7af177781 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -32,13 +32,11 @@ #include #define SYS_IND(p) (get_unaligned(&p->sys_ind)) -#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \ - get_unaligned(&p->nr_sects); \ +#define NR_SECTS(p) ({ __le32 __a = get_unaligned(&p->nr_sects); \ le32_to_cpu(__a); \ }) -#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \ - get_unaligned(&p->start_sect); \ +#define START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \ le32_to_cpu(__a); \ }) -- GitLab From 44aa5359be589f9cbe9cf0d5c97e22b27a04c7d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Aug 2006 01:54:30 -0400 Subject: [PATCH 0914/1619] [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(-) diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 22f820a9b15..17437574f79 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 fc62887c520..61eef508b04 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 */ -- GitLab From 107c3a73e0ee037322efa00fa3cb45b3b7eb6069 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Aug 2006 15:38:04 -0400 Subject: [PATCH 0915/1619] [PATCH] endianness annotations in s2io Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/net/s2io.h | 322 ++++++++++++++++++++++----------------------- 1 file changed, 161 insertions(+), 161 deletions(-) diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 72f52dc98f5..12b719f4d00 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -116,179 +116,179 @@ typedef struct { /* The statistics block of Xena */ typedef struct stat_block { /* Tx MAC statistics counters. */ - u32 tmac_data_octets; - u32 tmac_frms; - u64 tmac_drop_frms; - u32 tmac_bcst_frms; - u32 tmac_mcst_frms; - u64 tmac_pause_ctrl_frms; - u32 tmac_ucst_frms; - u32 tmac_ttl_octets; - u32 tmac_any_err_frms; - u32 tmac_nucst_frms; - u64 tmac_ttl_less_fb_octets; - u64 tmac_vld_ip_octets; - u32 tmac_drop_ip; - u32 tmac_vld_ip; - u32 tmac_rst_tcp; - u32 tmac_icmp; - u64 tmac_tcp; - u32 reserved_0; - u32 tmac_udp; + __le32 tmac_data_octets; + __le32 tmac_frms; + __le64 tmac_drop_frms; + __le32 tmac_bcst_frms; + __le32 tmac_mcst_frms; + __le64 tmac_pause_ctrl_frms; + __le32 tmac_ucst_frms; + __le32 tmac_ttl_octets; + __le32 tmac_any_err_frms; + __le32 tmac_nucst_frms; + __le64 tmac_ttl_less_fb_octets; + __le64 tmac_vld_ip_octets; + __le32 tmac_drop_ip; + __le32 tmac_vld_ip; + __le32 tmac_rst_tcp; + __le32 tmac_icmp; + __le64 tmac_tcp; + __le32 reserved_0; + __le32 tmac_udp; /* Rx MAC Statistics counters. */ - u32 rmac_data_octets; - u32 rmac_vld_frms; - u64 rmac_fcs_err_frms; - u64 rmac_drop_frms; - u32 rmac_vld_bcst_frms; - u32 rmac_vld_mcst_frms; - u32 rmac_out_rng_len_err_frms; - u32 rmac_in_rng_len_err_frms; - u64 rmac_long_frms; - u64 rmac_pause_ctrl_frms; - u64 rmac_unsup_ctrl_frms; - u32 rmac_accepted_ucst_frms; - u32 rmac_ttl_octets; - u32 rmac_discarded_frms; - u32 rmac_accepted_nucst_frms; - u32 reserved_1; - u32 rmac_drop_events; - u64 rmac_ttl_less_fb_octets; - u64 rmac_ttl_frms; - u64 reserved_2; - u32 rmac_usized_frms; - u32 reserved_3; - u32 rmac_frag_frms; - u32 rmac_osized_frms; - u32 reserved_4; - u32 rmac_jabber_frms; - u64 rmac_ttl_64_frms; - u64 rmac_ttl_65_127_frms; - u64 reserved_5; - u64 rmac_ttl_128_255_frms; - u64 rmac_ttl_256_511_frms; - u64 reserved_6; - u64 rmac_ttl_512_1023_frms; - u64 rmac_ttl_1024_1518_frms; - u32 rmac_ip; - u32 reserved_7; - u64 rmac_ip_octets; - u32 rmac_drop_ip; - u32 rmac_hdr_err_ip; - u32 reserved_8; - u32 rmac_icmp; - u64 rmac_tcp; - u32 rmac_err_drp_udp; - u32 rmac_udp; - u64 rmac_xgmii_err_sym; - u64 rmac_frms_q0; - u64 rmac_frms_q1; - u64 rmac_frms_q2; - u64 rmac_frms_q3; - u64 rmac_frms_q4; - u64 rmac_frms_q5; - u64 rmac_frms_q6; - u64 rmac_frms_q7; - u16 rmac_full_q3; - u16 rmac_full_q2; - u16 rmac_full_q1; - u16 rmac_full_q0; - u16 rmac_full_q7; - u16 rmac_full_q6; - u16 rmac_full_q5; - u16 rmac_full_q4; - u32 reserved_9; - u32 rmac_pause_cnt; - u64 rmac_xgmii_data_err_cnt; - u64 rmac_xgmii_ctrl_err_cnt; - u32 rmac_err_tcp; - u32 rmac_accepted_ip; + __le32 rmac_data_octets; + __le32 rmac_vld_frms; + __le64 rmac_fcs_err_frms; + __le64 rmac_drop_frms; + __le32 rmac_vld_bcst_frms; + __le32 rmac_vld_mcst_frms; + __le32 rmac_out_rng_len_err_frms; + __le32 rmac_in_rng_len_err_frms; + __le64 rmac_long_frms; + __le64 rmac_pause_ctrl_frms; + __le64 rmac_unsup_ctrl_frms; + __le32 rmac_accepted_ucst_frms; + __le32 rmac_ttl_octets; + __le32 rmac_discarded_frms; + __le32 rmac_accepted_nucst_frms; + __le32 reserved_1; + __le32 rmac_drop_events; + __le64 rmac_ttl_less_fb_octets; + __le64 rmac_ttl_frms; + __le64 reserved_2; + __le32 rmac_usized_frms; + __le32 reserved_3; + __le32 rmac_frag_frms; + __le32 rmac_osized_frms; + __le32 reserved_4; + __le32 rmac_jabber_frms; + __le64 rmac_ttl_64_frms; + __le64 rmac_ttl_65_127_frms; + __le64 reserved_5; + __le64 rmac_ttl_128_255_frms; + __le64 rmac_ttl_256_511_frms; + __le64 reserved_6; + __le64 rmac_ttl_512_1023_frms; + __le64 rmac_ttl_1024_1518_frms; + __le32 rmac_ip; + __le32 reserved_7; + __le64 rmac_ip_octets; + __le32 rmac_drop_ip; + __le32 rmac_hdr_err_ip; + __le32 reserved_8; + __le32 rmac_icmp; + __le64 rmac_tcp; + __le32 rmac_err_drp_udp; + __le32 rmac_udp; + __le64 rmac_xgmii_err_sym; + __le64 rmac_frms_q0; + __le64 rmac_frms_q1; + __le64 rmac_frms_q2; + __le64 rmac_frms_q3; + __le64 rmac_frms_q4; + __le64 rmac_frms_q5; + __le64 rmac_frms_q6; + __le64 rmac_frms_q7; + __le16 rmac_full_q3; + __le16 rmac_full_q2; + __le16 rmac_full_q1; + __le16 rmac_full_q0; + __le16 rmac_full_q7; + __le16 rmac_full_q6; + __le16 rmac_full_q5; + __le16 rmac_full_q4; + __le32 reserved_9; + __le32 rmac_pause_cnt; + __le64 rmac_xgmii_data_err_cnt; + __le64 rmac_xgmii_ctrl_err_cnt; + __le32 rmac_err_tcp; + __le32 rmac_accepted_ip; /* PCI/PCI-X Read transaction statistics. */ - u32 new_rd_req_cnt; - u32 rd_req_cnt; - u32 rd_rtry_cnt; - u32 new_rd_req_rtry_cnt; + __le32 new_rd_req_cnt; + __le32 rd_req_cnt; + __le32 rd_rtry_cnt; + __le32 new_rd_req_rtry_cnt; /* PCI/PCI-X Write/Read transaction statistics. */ - u32 wr_req_cnt; - u32 wr_rtry_rd_ack_cnt; - u32 new_wr_req_rtry_cnt; - u32 new_wr_req_cnt; - u32 wr_disc_cnt; - u32 wr_rtry_cnt; + __le32 wr_req_cnt; + __le32 wr_rtry_rd_ack_cnt; + __le32 new_wr_req_rtry_cnt; + __le32 new_wr_req_cnt; + __le32 wr_disc_cnt; + __le32 wr_rtry_cnt; /* PCI/PCI-X Write / DMA Transaction statistics. */ - u32 txp_wr_cnt; - u32 rd_rtry_wr_ack_cnt; - u32 txd_wr_cnt; - u32 txd_rd_cnt; - u32 rxd_wr_cnt; - u32 rxd_rd_cnt; - u32 rxf_wr_cnt; - u32 txf_rd_cnt; + __le32 txp_wr_cnt; + __le32 rd_rtry_wr_ack_cnt; + __le32 txd_wr_cnt; + __le32 txd_rd_cnt; + __le32 rxd_wr_cnt; + __le32 rxd_rd_cnt; + __le32 rxf_wr_cnt; + __le32 txf_rd_cnt; /* Tx MAC statistics overflow counters. */ - u32 tmac_data_octets_oflow; - u32 tmac_frms_oflow; - u32 tmac_bcst_frms_oflow; - u32 tmac_mcst_frms_oflow; - u32 tmac_ucst_frms_oflow; - u32 tmac_ttl_octets_oflow; - u32 tmac_any_err_frms_oflow; - u32 tmac_nucst_frms_oflow; - u64 tmac_vlan_frms; - u32 tmac_drop_ip_oflow; - u32 tmac_vld_ip_oflow; - u32 tmac_rst_tcp_oflow; - u32 tmac_icmp_oflow; - u32 tpa_unknown_protocol; - u32 tmac_udp_oflow; - u32 reserved_10; - u32 tpa_parse_failure; + __le32 tmac_data_octets_oflow; + __le32 tmac_frms_oflow; + __le32 tmac_bcst_frms_oflow; + __le32 tmac_mcst_frms_oflow; + __le32 tmac_ucst_frms_oflow; + __le32 tmac_ttl_octets_oflow; + __le32 tmac_any_err_frms_oflow; + __le32 tmac_nucst_frms_oflow; + __le64 tmac_vlan_frms; + __le32 tmac_drop_ip_oflow; + __le32 tmac_vld_ip_oflow; + __le32 tmac_rst_tcp_oflow; + __le32 tmac_icmp_oflow; + __le32 tpa_unknown_protocol; + __le32 tmac_udp_oflow; + __le32 reserved_10; + __le32 tpa_parse_failure; /* Rx MAC Statistics overflow counters. */ - u32 rmac_data_octets_oflow; - u32 rmac_vld_frms_oflow; - u32 rmac_vld_bcst_frms_oflow; - u32 rmac_vld_mcst_frms_oflow; - u32 rmac_accepted_ucst_frms_oflow; - u32 rmac_ttl_octets_oflow; - u32 rmac_discarded_frms_oflow; - u32 rmac_accepted_nucst_frms_oflow; - u32 rmac_usized_frms_oflow; - u32 rmac_drop_events_oflow; - u32 rmac_frag_frms_oflow; - u32 rmac_osized_frms_oflow; - u32 rmac_ip_oflow; - u32 rmac_jabber_frms_oflow; - u32 rmac_icmp_oflow; - u32 rmac_drop_ip_oflow; - u32 rmac_err_drp_udp_oflow; - u32 rmac_udp_oflow; - u32 reserved_11; - u32 rmac_pause_cnt_oflow; - u64 rmac_ttl_1519_4095_frms; - u64 rmac_ttl_4096_8191_frms; - u64 rmac_ttl_8192_max_frms; - u64 rmac_ttl_gt_max_frms; - u64 rmac_osized_alt_frms; - u64 rmac_jabber_alt_frms; - u64 rmac_gt_max_alt_frms; - u64 rmac_vlan_frms; - u32 rmac_len_discard; - u32 rmac_fcs_discard; - u32 rmac_pf_discard; - u32 rmac_da_discard; - u32 rmac_red_discard; - u32 rmac_rts_discard; - u32 reserved_12; - u32 rmac_ingm_full_discard; - u32 reserved_13; - u32 rmac_accepted_ip_oflow; - u32 reserved_14; - u32 link_fault_cnt; + __le32 rmac_data_octets_oflow; + __le32 rmac_vld_frms_oflow; + __le32 rmac_vld_bcst_frms_oflow; + __le32 rmac_vld_mcst_frms_oflow; + __le32 rmac_accepted_ucst_frms_oflow; + __le32 rmac_ttl_octets_oflow; + __le32 rmac_discarded_frms_oflow; + __le32 rmac_accepted_nucst_frms_oflow; + __le32 rmac_usized_frms_oflow; + __le32 rmac_drop_events_oflow; + __le32 rmac_frag_frms_oflow; + __le32 rmac_osized_frms_oflow; + __le32 rmac_ip_oflow; + __le32 rmac_jabber_frms_oflow; + __le32 rmac_icmp_oflow; + __le32 rmac_drop_ip_oflow; + __le32 rmac_err_drp_udp_oflow; + __le32 rmac_udp_oflow; + __le32 reserved_11; + __le32 rmac_pause_cnt_oflow; + __le64 rmac_ttl_1519_4095_frms; + __le64 rmac_ttl_4096_8191_frms; + __le64 rmac_ttl_8192_max_frms; + __le64 rmac_ttl_gt_max_frms; + __le64 rmac_osized_alt_frms; + __le64 rmac_jabber_alt_frms; + __le64 rmac_gt_max_alt_frms; + __le64 rmac_vlan_frms; + __le32 rmac_len_discard; + __le32 rmac_fcs_discard; + __le32 rmac_pf_discard; + __le32 rmac_da_discard; + __le32 rmac_red_discard; + __le32 rmac_rts_discard; + __le32 reserved_12; + __le32 rmac_ingm_full_discard; + __le32 reserved_13; + __le32 rmac_accepted_ip_oflow; + __le32 reserved_14; + __le32 link_fault_cnt; u8 buffer[20]; swStat_t sw_stat; xpakStat_t xpak_stat; -- GitLab From 15e541feb340bc2a4caaf707ee5ad71a47fdd068 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 10 Oct 2006 01:40:55 -0400 Subject: [PATCH 0916/1619] [PATCH] irda: donauboe fixes, cleanups - fix: toshoboe_invalid_dev() was recently removed, but not all callers were updated, causing the obvious linker error. Remove caller, because the check (like the one removed) isn't used. - fix: propagate request_irq() return value - cleanup: remove void* casts - cleanup: remove impossible ASSERTs Signed-off-by: Jeff Garzik Signed-off-by: Linus Torvalds --- drivers/net/irda/donauboe.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 636d0630fe0..16620bd97fb 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1154,13 +1154,10 @@ dumpbufs(skb->data,skb->len,'>'); static irqreturn_t toshoboe_interrupt (int irq, void *dev_id) { - struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; + struct toshoboe_cb *self = dev_id; __u8 irqstat; struct sk_buff *skb = NULL; - if (self == NULL && toshoboe_invalid_dev(irq)) - return IRQ_NONE; - irqstat = INB (OBOE_ISR); /* was it us */ @@ -1348,13 +1345,11 @@ toshoboe_net_open (struct net_device *dev) { struct toshoboe_cb *self; unsigned long flags; + int rc; IRDA_DEBUG (4, "%s()\n", __FUNCTION__); - IRDA_ASSERT (dev != NULL, return -1; ); - self = (struct toshoboe_cb *) dev->priv; - - IRDA_ASSERT (self != NULL, return 0; ); + self = netdev_priv(dev); if (self->async) return -EBUSY; @@ -1362,11 +1357,10 @@ toshoboe_net_open (struct net_device *dev) if (self->stopped) return 0; - if (request_irq (self->io.irq, toshoboe_interrupt, - IRQF_SHARED | IRQF_DISABLED, dev->name, (void *) self)) - { - return -EAGAIN; - } + rc = request_irq (self->io.irq, toshoboe_interrupt, + IRQF_SHARED | IRQF_DISABLED, dev->name, self); + if (rc) + return rc; spin_lock_irqsave(&self->spinlock, flags); toshoboe_startchip (self); -- GitLab From 0968cf51b6f2ca8a951de4b976370189cf43bbdd Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 10 Oct 2006 02:58:14 -0400 Subject: [PATCH 0917/1619] [PATCH] firmware/dcdbas: fix bug in error cleanup The error path path mistakenly called sysfs_create_group() rather than sysfs_remove_group(). They take the same arguments, so it's easy to cut-n-paste such a bug. Signed-off-by: Jeff Garzik Signed-off-by: Linus Torvalds --- drivers/firmware/dcdbas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 339f405ff70..8bcb58cd4ac 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -559,7 +559,7 @@ static int __devinit dcdbas_probe(struct platform_device *dev) while (--i >= 0) sysfs_remove_bin_file(&dev->dev.kobj, dcdbas_bin_attrs[i]); - sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group); + sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group); return error; } } -- GitLab From 53a5fbdc2dff55161a206ed1a1385a8fa8055c34 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 10 Oct 2006 17:14:44 -0700 Subject: [PATCH 0918/1619] ACPI: Allow setting SCI_EN bit in PM1_CONTROL register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed by at least the Mac Mini's, which (incorrectly) come back from suspend with SCI_EN clear. Thanks to Frédéric Riss for hunting this down. Acked-by: Frédéric Riss Cc: Pavel Machek Cc: Len Brown Cc: Arjan van de Ven Signed-off-by: Linus Torvalds --- drivers/acpi/hardware/hwregs.c | 2 -- include/acpi/aclocal.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 3143f36fcec..fa58c1edce1 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -665,8 +665,6 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) /* * Perform a read first to preserve certain bits (per ACPI spec) - * - * Note: This includes SCI_EN, we never want to change this bit */ status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index a4d0e73d5ac..063c4b54290 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -708,7 +708,7 @@ struct acpi_bit_register_info { * must be preserved. */ #define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */ -#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0201 /* Bit 9, Bit 0 (SCI_EN) */ +#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0200 /* Bit 9 (whatever) */ /* * Register IDs -- GitLab From 438dd926260f11ff01fc3441ac6dd4c412d20ea4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 11 Oct 2006 03:49:30 +0000 Subject: [PATCH 0919/1619] [CIFS] Fix leaps year calculation for years after 2100 Signed-off-by: Steve French --- fs/cifs/netmisc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 3d86b31cf2e..32562d19955 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -946,6 +946,15 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) year = sd->Year; days += year * 365; days += (year/4); /* leap year */ + /* generalized leap year calculation is more complex, ie no leap year + for years/100 except for years/400, but since the maximum number for DOS + year is 2**7, the last year is 1980+127, which means we need only + consider 2 special case years, ie the years 2000 and 2100, and only + adjust for the lack of leap year for the year 2100, as 2000 was a + leap year (divisable by 400) */ + if(year >= 120) /* the year 2100 */ + days = days - 1; /* do not count leap year for the year 2100 */ + /* adjust for leap year where we are still before leap day */ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); sec += 24 * 60 * 60 * days; -- GitLab From 80fc9f532d8c05d4cb12d55660624ce53a378349 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 11 Oct 2006 01:43:58 -0400 Subject: [PATCH 0920/1619] Input: add missing exports to fix modular build Signed-off-by: Dmitry Torokhov --- drivers/char/random.c | 1 + lib/kobject.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index 07f47a0208a..eb6b13f4211 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -645,6 +645,7 @@ void add_input_randomness(unsigned int type, unsigned int code, add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ value); } +EXPORT_SYMBOL_GPL(add_input_randomness); void add_interrupt_randomness(int irq) { diff --git a/lib/kobject.c b/lib/kobject.c index 1699eb9161f..7dd5c0e9d99 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -119,6 +119,7 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) return path; } +EXPORT_SYMBOL_GPL(kobject_get_path); /** * kobject_init - initialize object. -- GitLab From 817e6ba3623de9cdc66c6aba90eae30b5588ff11 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 11 Oct 2006 01:44:28 -0400 Subject: [PATCH 0921/1619] Input: i8042 - supress ACK/NAKs when blinking during panic This allows using SysRq and not fill logs with complaints from atkbd. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 09b06e605b5..7e3141f37e3 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -106,6 +106,7 @@ static unsigned char i8042_ctr; static unsigned char i8042_mux_present; static unsigned char i8042_kbd_irq_registered; static unsigned char i8042_aux_irq_registered; +static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; static irqreturn_t i8042_interrupt(int irq, void *dev_id); @@ -316,7 +317,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) unsigned char str, data; unsigned int dfl; unsigned int port_no; - int ret; + int ret = 1; spin_lock_irqsave(&i8042_lock, flags); str = i8042_read_status(); @@ -378,10 +379,16 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); + if (unlikely(i8042_suppress_kbd_ack)) + if (port_no == I8042_KBD_PORT_NO && + (data == 0xfa || data == 0xfe)) { + i8042_suppress_kbd_ack = 0; + goto out; + } + if (likely(port->exists)) serio_interrupt(port->serio, data, dfl); - ret = 1; out: return IRQ_RETVAL(ret); } @@ -842,11 +849,13 @@ static long i8042_panic_blink(long count) led ^= 0x01 | 0x04; while (i8042_read_status() & I8042_STR_IBF) DELAY; + i8042_suppress_kbd_ack = 1; i8042_write_data(0xed); /* set leds */ DELAY; while (i8042_read_status() & I8042_STR_IBF) DELAY; DELAY; + i8042_suppress_kbd_ack = 1; i8042_write_data(led); DELAY; last_blink = count; -- GitLab From 86255d9d0bede79140f4912482447963f00818c0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 11 Oct 2006 01:44:46 -0400 Subject: [PATCH 0922/1619] Input: atkbd - supress "too many keys" error message Many users seems to be annoyed by this warning so kill the message and implement a counter exported as a sysfs attribute so we still know what is going on. Make atkbd use attribute groups while we are at it. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 54 ++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index b6ef9eaad1d..cbb93669d1c 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -221,6 +221,7 @@ struct atkbd { unsigned long xl_bit; unsigned int last; unsigned long time; + unsigned long err_count; struct work_struct event_work; struct mutex event_mutex; @@ -234,11 +235,13 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t #define ATKBD_DEFINE_ATTR(_name) \ static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ -static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ +static ssize_t atkbd_do_show_##_name(struct device *d, \ + struct device_attribute *attr, char *b) \ { \ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ } \ -static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \ +static ssize_t atkbd_do_set_##_name(struct device *d, \ + struct device_attribute *attr, const char *b, size_t s) \ { \ return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ } \ @@ -251,6 +254,32 @@ ATKBD_DEFINE_ATTR(set); ATKBD_DEFINE_ATTR(softrepeat); ATKBD_DEFINE_ATTR(softraw); +#define ATKBD_DEFINE_RO_ATTR(_name) \ +static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ +static ssize_t atkbd_do_show_##_name(struct device *d, \ + struct device_attribute *attr, char *b) \ +{ \ + return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ +} \ +static struct device_attribute atkbd_attr_##_name = \ + __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); + +ATKBD_DEFINE_RO_ATTR(err_count); + +static struct attribute *atkbd_attributes[] = { + &atkbd_attr_extra.attr, + &atkbd_attr_scroll.attr, + &atkbd_attr_set.attr, + &atkbd_attr_softrepeat.attr, + &atkbd_attr_softraw.attr, + &atkbd_attr_err_count.attr, + NULL +}; + +static struct attribute_group atkbd_attribute_group = { + .attrs = atkbd_attributes, +}; + static const unsigned int xl_table[] = { ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, @@ -396,7 +425,10 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, add_release_event = 1; break; case ATKBD_RET_ERR: + atkbd->err_count++; +#ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); +#endif goto out; } @@ -786,12 +818,7 @@ static void atkbd_disconnect(struct serio *serio) synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */ flush_scheduled_work(); - device_remove_file(&serio->dev, &atkbd_attr_extra); - device_remove_file(&serio->dev, &atkbd_attr_scroll); - device_remove_file(&serio->dev, &atkbd_attr_set); - device_remove_file(&serio->dev, &atkbd_attr_softrepeat); - device_remove_file(&serio->dev, &atkbd_attr_softraw); - + sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); input_unregister_device(atkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); @@ -961,11 +988,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - device_create_file(&serio->dev, &atkbd_attr_extra); - device_create_file(&serio->dev, &atkbd_attr_scroll); - device_create_file(&serio->dev, &atkbd_attr_set); - device_create_file(&serio->dev, &atkbd_attr_softrepeat); - device_create_file(&serio->dev, &atkbd_attr_softraw); + sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group); atkbd_enable(atkbd); @@ -1259,6 +1282,11 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co return count; } +static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf) +{ + return sprintf(buf, "%lu\n", atkbd->err_count); +} + static int __init atkbd_init(void) { -- GitLab From 4dfbb9d8c6cbfc32faa5c71145bd2a43e1f8237c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 11 Oct 2006 01:45:14 -0400 Subject: [PATCH 0923/1619] 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(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 1314ca0f29b..14fec2a23b2 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 4c055346100..ba7156ac70c 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 e3203c654dd..18651641a7b 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 db4fed74b94..c4cfd6c0342 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 901d0e7da89..cdb4e3d0560 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 dafaf1de249..b6c4f898197 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 b77e155cbe6..d472db4776c 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); } /** -- GitLab From 88aa0103e408616e433c209e80169ab8d6eda99e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 11 Oct 2006 01:45:31 -0400 Subject: [PATCH 0924/1619] 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(-) diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index dcb16b5cbec..e5b1b60757b 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 960fae3c3ce..480fdc5d20b 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 3a697cc6eca..b99c5ca9708 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 */ -- GitLab From 12f417ee95bf98cd3e42d2a771f7c6d360159b9d Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 10 Oct 2006 14:33:22 -0700 Subject: [PATCH 0925/1619] [PATCH] Update smc91x driver with ARM Versatile board info We need to specify a Versatile-specific SMC_IRQ_FLAGS value or the new generic IRQ layer will complain thusly: No IRQF_TRIGGER set_type function for IRQ 25 () Signed-off-by: Deepak Saxena Cc: Jeff Garzik Cc: Russell King Cc: Nicolas Pitre Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 636dbfcdf8c..0c9f1e7dab2 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -398,6 +398,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_IRQ_FLAGS (0) +#elif defined(CONFIG_ARCH_VERSATILE) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define SMC_IRQ_FLAGS (0) + #else #define SMC_CAN_USE_8BIT 1 -- GitLab From 6f62768344e46520ae585f3e201c9d3e497b028f Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 10 Oct 2006 14:33:26 -0700 Subject: [PATCH 0926/1619] [PATCH] b44: fix eeprom endianess issue This fixes eeprom read on big-endian architectures. readw returns the data in CPU order. With cpu_to_le16 we convert it to little endian, because "ptr" is a pointer to a _byte_ arrray. See the cast above. A byte array is little endian. The bug is: Reading u16 values with readw, casting them into an u8 array and accessing this u8 array as an u8 (byte) array. The correct fix is to swap the CPU-ordering value returned by readw into little endian, as the u8 array is little endian. This compiles to nothing on little endian hardware (so it does not change b44 code on LE hardware), but _fixes_ code on BE hardware. Signed-off-by: Michael Buesch Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index ebb726e655a..1ec217433b4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2056,7 +2056,7 @@ static int b44_read_eeprom(struct b44 *bp, u8 *data) u16 *ptr = (u16 *) data; for (i = 0; i < 128; i += 2) - ptr[i / 2] = readw(bp->regs + 4096 + i); + ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); return 0; } -- GitLab From 5f77113c01d8a9f8193769d2ca73763047af39ef Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 10 Oct 2006 14:33:30 -0700 Subject: [PATCH 0927/1619] [PATCH] ibmveth irq fix drivers/net/ibmveth.c:939: error: too many arguments to function `ibmveth_interrupt' Cc: Jeff Garzik Cc: Anton Blanchard Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index bf414a93fac..2802db23d3c 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -936,7 +936,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) static void ibmveth_poll_controller(struct net_device *dev) { ibmveth_replenish_task(dev->priv); - ibmveth_interrupt(dev->irq, dev, NULL); + ibmveth_interrupt(dev->irq, dev); } #endif -- GitLab From 08093c8fd66ef7a8c2f887812cc98c54f5f12703 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Thu, 5 Oct 2006 16:53:12 +0200 Subject: [PATCH 0928/1619] [PATCH] ehea: firmware (hvcall) interface changes This eHEA patch covers required changes related to Anton Blanchard's new hvcall interface. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_phyp.c | 573 +++++++++++++++-------------------- 1 file changed, 238 insertions(+), 335 deletions(-) diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 4a85aca4c7e..0b51a8cea07 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -44,71 +44,99 @@ static inline u16 get_order_of_qentries(u16 queue_entries) #define H_ALL_RES_TYPE_MR 5 #define H_ALL_RES_TYPE_MW 6 -static long ehea_hcall_9arg_9ret(unsigned long opcode, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5, unsigned long arg6, - unsigned long arg7, unsigned long arg8, - unsigned long arg9, unsigned long *out1, - unsigned long *out2,unsigned long *out3, - unsigned long *out4,unsigned long *out5, - unsigned long *out6,unsigned long *out7, - unsigned long *out8,unsigned long *out9) +static long ehea_plpar_hcall_norets(unsigned long opcode, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6, + unsigned long arg7) { - long hret; + long ret; int i, sleep_msecs; for (i = 0; i < 5; i++) { - hret = plpar_hcall_9arg_9ret(opcode,arg1, arg2, arg3, arg4, - arg5, arg6, arg7, arg8, arg9, out1, - out2, out3, out4, out5, out6, out7, - out8, out9); - if (H_IS_LONG_BUSY(hret)) { - sleep_msecs = get_longbusy_msecs(hret); + ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, + arg5, arg6, arg7); + + if (H_IS_LONG_BUSY(ret)) { + sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); continue; } - if (hret < H_SUCCESS) - ehea_error("op=%lx hret=%lx " - "i1=%lx i2=%lx i3=%lx i4=%lx i5=%lx i6=%lx " - "i7=%lx i8=%lx i9=%lx " - "o1=%lx o2=%lx o3=%lx o4=%lx o5=%lx o6=%lx " - "o7=%lx o8=%lx o9=%lx", - opcode, hret, arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8, arg9, *out1, *out2, *out3, - *out4, *out5, *out6, *out7, *out8, *out9); - return hret; + if (ret < H_SUCCESS) + ehea_error("opcode=%lx ret=%lx" + " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" + " arg5=%lx arg6=%lx arg7=%lx ", + opcode, ret, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7); + + return ret; } + return H_BUSY; } -u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, - const u64 qp_handle, const u64 sel_mask, void *cb_addr) +static long ehea_plpar_hcall9(unsigned long opcode, + unsigned long *outs, /* array of 9 outputs */ + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6, + unsigned long arg7, + unsigned long arg8, + unsigned long arg9) { - u64 dummy; + long ret; + int i, sleep_msecs; - if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) { - ehea_error("not on pageboundary"); - return H_PARAMETER; + for (i = 0; i < 5; i++) { + ret = plpar_hcall9(opcode, outs, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9); + + if (H_IS_LONG_BUSY(ret)) { + sleep_msecs = get_longbusy_msecs(ret); + msleep_interruptible(sleep_msecs); + continue; + } + + if (ret < H_SUCCESS) + ehea_error("opcode=%lx ret=%lx" + " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" + " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" + " arg9=%lx" + " out1=%lx out2=%lx out3=%lx out4=%lx" + " out5=%lx out6=%lx out7=%lx out8=%lx" + " out9=%lx", + opcode, ret, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9, + outs[0], outs[1], outs[2], outs[3], + outs[4], outs[5], outs[6], outs[7], + outs[8]); + + return ret; } - return ehea_hcall_9arg_9ret(H_QUERY_HEA_QP, - adapter_handle, /* R4 */ - qp_category, /* R5 */ - qp_handle, /* R6 */ - sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return H_BUSY; +} + +u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, + const u64 qp_handle, const u64 sel_mask, void *cb_addr) +{ + return ehea_plpar_hcall_norets(H_QUERY_HEA_QP, + adapter_handle, /* R4 */ + qp_category, /* R5 */ + qp_handle, /* R6 */ + sel_mask, /* R7 */ + virt_to_abs(cb_addr), /* R8 */ + 0, 0); } /* input param R5 */ @@ -180,6 +208,7 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, u64 *qp_handle, struct h_epas *h_epas) { u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; u64 allocate_controls = EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0) @@ -219,45 +248,29 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold) | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold); - u64 r5_out = 0; - u64 r6_out = 0; - u64 r7_out = 0; - u64 r8_out = 0; - u64 r9_out = 0; - u64 g_la_user_out = 0; - u64 r11_out = 0; - u64 r12_out = 0; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - allocate_controls, /* R5 */ - init_attr->send_cq_handle, /* R6 */ - init_attr->recv_cq_handle, /* R7 */ - init_attr->aff_eq_handle, /* R8 */ - r9_reg, /* R9 */ - max_r10_reg, /* R10 */ - r11_in, /* R11 */ - threshold, /* R12 */ - qp_handle, /* R4 */ - &r5_out, /* R5 */ - &r6_out, /* R6 */ - &r7_out, /* R7 */ - &r8_out, /* R8 */ - &r9_out, /* R9 */ - &g_la_user_out, /* R10 */ - &r11_out, /* R11 */ - &r12_out); /* R12 */ - - init_attr->qp_nr = (u32)r5_out; + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + allocate_controls, /* R5 */ + init_attr->send_cq_handle, /* R6 */ + init_attr->recv_cq_handle, /* R7 */ + init_attr->aff_eq_handle, /* R8 */ + r9_reg, /* R9 */ + max_r10_reg, /* R10 */ + r11_in, /* R11 */ + threshold); /* R12 */ + + *qp_handle = outs[0]; + init_attr->qp_nr = (u32)outs[1]; init_attr->act_nr_send_wqes = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, outs[2]); init_attr->act_nr_rwqes_rq1 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, outs[2]); init_attr->act_nr_rwqes_rq2 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, outs[2]); init_attr->act_nr_rwqes_rq3 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, outs[2]); init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq; init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1; @@ -265,25 +278,25 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3; init_attr->nr_sq_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, outs[4]); init_attr->nr_rq1_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, outs[4]); init_attr->nr_rq2_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, outs[5]); init_attr->nr_rq3_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, outs[5]); init_attr->liobn_sq = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, outs[7]); init_attr->liobn_rq1 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, outs[7]); init_attr->liobn_rq2 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, outs[8]); init_attr->liobn_rq3 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, outs[8]); if (!hret) - hcp_epas_ctor(h_epas, g_la_user_out, g_la_user_out); + hcp_epas_ctor(h_epas, outs[6], outs[6]); return hret; } @@ -292,31 +305,24 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, struct ehea_cq_attr *cq_attr, u64 *cq_handle, struct h_epas *epas) { - u64 hret, dummy, act_nr_of_cqes_out, act_pages_out; - u64 g_la_privileged_out, g_la_user_out; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - H_ALL_RES_TYPE_CQ, /* R5 */ - cq_attr->eq_handle, /* R6 */ - cq_attr->cq_token, /* R7 */ - cq_attr->max_nr_of_cqes, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - cq_handle, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &act_nr_of_cqes_out, /* R7 */ - &act_pages_out, /* R8 */ - &g_la_privileged_out, /* R9 */ - &g_la_user_out, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - - cq_attr->act_nr_of_cqes = act_nr_of_cqes_out; - cq_attr->nr_pages = act_pages_out; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + H_ALL_RES_TYPE_CQ, /* R5 */ + cq_attr->eq_handle, /* R6 */ + cq_attr->cq_token, /* R7 */ + cq_attr->max_nr_of_cqes, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + *cq_handle = outs[0]; + cq_attr->act_nr_of_cqes = outs[3]; + cq_attr->nr_pages = outs[4]; if (!hret) - hcp_epas_ctor(epas, g_la_privileged_out, g_la_user_out); + hcp_epas_ctor(epas, outs[5], outs[6]); return hret; } @@ -361,9 +367,8 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, struct ehea_eq_attr *eq_attr, u64 *eq_handle) { - u64 hret, dummy, eq_liobn, allocate_controls; - u64 ist1_out, ist2_out, ist3_out, ist4_out; - u64 act_nr_of_eqes_out, act_pages_out; + u64 hret, allocate_controls; + u64 outs[PLPAR_HCALL9_BUFSIZE]; /* resource type */ allocate_controls = @@ -372,27 +377,20 @@ u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen) | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1); - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - allocate_controls, /* R5 */ - eq_attr->max_nr_of_eqes, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R10 */ - eq_handle, /* R4 */ - &dummy, /* R5 */ - &eq_liobn, /* R6 */ - &act_nr_of_eqes_out, /* R7 */ - &act_pages_out, /* R8 */ - &ist1_out, /* R9 */ - &ist2_out, /* R10 */ - &ist3_out, /* R11 */ - &ist4_out); /* R12 */ - - eq_attr->act_nr_of_eqes = act_nr_of_eqes_out; - eq_attr->nr_pages = act_pages_out; - eq_attr->ist1 = ist1_out; - eq_attr->ist2 = ist2_out; - eq_attr->ist3 = ist3_out; - eq_attr->ist4 = ist4_out; + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + allocate_controls, /* R5 */ + eq_attr->max_nr_of_eqes, /* R6 */ + 0, 0, 0, 0, 0, 0); /* R7-R10 */ + + *eq_handle = outs[0]; + eq_attr->act_nr_of_eqes = outs[3]; + eq_attr->nr_pages = outs[4]; + eq_attr->ist1 = outs[5]; + eq_attr->ist2 = outs[6]; + eq_attr->ist3 = outs[7]; + eq_attr->ist4 = outs[8]; return hret; } @@ -402,31 +400,22 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat, void *cb_addr, u64 *inv_attr_id, u64 *proc_mask, u16 *out_swr, u16 *out_rwr) { - u64 hret, dummy, act_out_swr, act_out_rwr; - - if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) { - ehea_error("not on page boundary"); - return H_PARAMETER; - } - - hret = ehea_hcall_9arg_9ret(H_MODIFY_HEA_QP, - adapter_handle, /* R4 */ - (u64) cat, /* R5 */ - qp_handle, /* R6 */ - sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - inv_attr_id, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &act_out_swr, /* R7 */ - &act_out_rwr, /* R8 */ - proc_mask, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - *out_swr = act_out_swr; - *out_rwr = act_out_rwr; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP, + outs, + adapter_handle, /* R4 */ + (u64) cat, /* R5 */ + qp_handle, /* R6 */ + sel_mask, /* R7 */ + virt_to_abs(cb_addr), /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + *inv_attr_id = outs[0]; + *out_swr = outs[3]; + *out_rwr = outs[4]; + *proc_mask = outs[5]; return hret; } @@ -435,122 +424,81 @@ u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize, const u8 queue_type, const u64 resource_handle, const u64 log_pageaddr, u64 count) { - u64 dummy, reg_control; + u64 reg_control; reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize) | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type); - return ehea_hcall_9arg_9ret(H_REGISTER_HEA_RPAGES, - adapter_handle, /* R4 */ - reg_control, /* R5 */ - resource_handle, /* R6 */ - log_pageaddr, /* R7 */ - count, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_REGISTER_HEA_RPAGES, + adapter_handle, /* R4 */ + reg_control, /* R5 */ + resource_handle, /* R6 */ + log_pageaddr, /* R7 */ + count, /* R8 */ + 0, 0); /* R9-R10 */ } u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle, const u64 vaddr_in, const u32 access_ctrl, const u32 pd, struct ehea_mr *mr) { - u64 hret, dummy, lkey_out; - - hret = ehea_hcall_9arg_9ret(H_REGISTER_SMR, - adapter_handle , /* R4 */ - orig_mr_handle, /* R5 */ - vaddr_in, /* R6 */ - (((u64)access_ctrl) << 32ULL), /* R7 */ - pd, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &mr->handle, /* R4 */ - &dummy, /* R5 */ - &lkey_out, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - mr->lkey = (u32)lkey_out; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_REGISTER_SMR, + outs, + adapter_handle , /* R4 */ + orig_mr_handle, /* R5 */ + vaddr_in, /* R6 */ + (((u64)access_ctrl) << 32ULL), /* R7 */ + pd, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + mr->handle = outs[0]; + mr->lkey = (u32)outs[2]; return hret; } u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle) { - u64 hret, dummy, ladr_next_sq_wqe_out; - u64 ladr_next_rq1_wqe_out, ladr_next_rq2_wqe_out, ladr_next_rq3_wqe_out; - - hret = ehea_hcall_9arg_9ret(H_DISABLE_AND_GET_HEA, - adapter_handle, /* R4 */ - H_DISABLE_GET_EHEA_WQE_P, /* R5 */ - qp_handle, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R12 */ - &ladr_next_sq_wqe_out, /* R4 */ - &ladr_next_rq1_wqe_out, /* R5 */ - &ladr_next_rq2_wqe_out, /* R6 */ - &ladr_next_rq3_wqe_out, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - return hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA, + outs, + adapter_handle, /* R4 */ + H_DISABLE_GET_EHEA_WQE_P, /* R5 */ + qp_handle, /* R6 */ + 0, 0, 0, 0, 0, 0); /* R7-R12 */ } u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle) { - u64 dummy; - - return ehea_hcall_9arg_9ret(H_FREE_RESOURCE, - adapter_handle, /* R4 */ - res_handle, /* R5 */ - 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_FREE_RESOURCE, + adapter_handle, /* R4 */ + res_handle, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ } u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, const u64 length, const u32 access_ctrl, const u32 pd, u64 *mr_handle, u32 *lkey) { - u64 hret, dummy, lkey_out; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - 5, /* R5 */ - vaddr, /* R6 */ - length, /* R7 */ - (((u64) access_ctrl) << 32ULL),/* R8 */ - pd, /* R9 */ - 0, 0, 0, /* R10-R12 */ - mr_handle, /* R4 */ - &dummy, /* R5 */ - &lkey_out, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - *lkey = (u32) lkey_out; - + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + 5, /* R5 */ + vaddr, /* R6 */ + length, /* R7 */ + (((u64) access_ctrl) << 32ULL), /* R8 */ + pd, /* R9 */ + 0, 0, 0); /* R10-R12 */ + + *mr_handle = outs[0]; + *lkey = (u32)outs[2]; return hret; } @@ -570,23 +518,14 @@ u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle, u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr) { - u64 hret, dummy, cb_logaddr; + u64 hret, cb_logaddr; cb_logaddr = virt_to_abs(cb_addr); - hret = ehea_hcall_9arg_9ret(H_QUERY_HEA, - adapter_handle, /* R4 */ - cb_logaddr, /* R5 */ - 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + hret = ehea_plpar_hcall_norets(H_QUERY_HEA, + adapter_handle, /* R4 */ + cb_logaddr, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ #ifdef DEBUG ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); #endif @@ -597,36 +536,28 @@ u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 port_info, dummy; + u64 port_info; u64 cb_logaddr = virt_to_abs(cb_addr); u64 arr_index = 0; port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat) | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num); - return ehea_hcall_9arg_9ret(H_QUERY_HEA_PORT, - adapter_handle, /* R4 */ - port_info, /* R5 */ - select_mask, /* R6 */ - arr_index, /* R7 */ - cb_logaddr, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_QUERY_HEA_PORT, + adapter_handle, /* R4 */ + port_info, /* R5 */ + select_mask, /* R6 */ + arr_index, /* R7 */ + cb_logaddr, /* R8 */ + 0, 0); /* R9-R10 */ } u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 port_info, dummy, inv_attr_ident, proc_mask; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + u64 port_info; u64 arr_index = 0; u64 cb_logaddr = virt_to_abs(cb_addr); @@ -635,29 +566,21 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, #ifdef DEBUG ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL"); #endif - return ehea_hcall_9arg_9ret(H_MODIFY_HEA_PORT, - adapter_handle, /* R4 */ - port_info, /* R5 */ - select_mask, /* R6 */ - arr_index, /* R7 */ - cb_logaddr, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &inv_attr_ident, /* R4 */ - &proc_mask, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall9(H_MODIFY_HEA_PORT, + outs, + adapter_handle, /* R4 */ + port_info, /* R5 */ + select_mask, /* R6 */ + arr_index, /* R7 */ + cb_logaddr, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ } u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, const u8 reg_type, const u64 mc_mac_addr, const u16 vlan_id, const u32 hcall_id) { - u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id, dummy; + u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id; u64 mac_addr = mc_mac_addr >> 16; r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num); @@ -665,41 +588,21 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr); r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id); - return ehea_hcall_9arg_9ret(hcall_id, - adapter_handle, /* R4 */ - r5_port_num, /* R5 */ - r6_reg_type, /* R6 */ - r7_mc_mac_addr, /* R7 */ - r8_vlan_id, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(hcall_id, + adapter_handle, /* R4 */ + r5_port_num, /* R5 */ + r6_reg_type, /* R6 */ + r7_mc_mac_addr, /* R7 */ + r8_vlan_id, /* R8 */ + 0, 0); /* R9-R12 */ } u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, const u64 event_mask) { - u64 dummy; - - return ehea_hcall_9arg_9ret(H_RESET_EVENTS, - adapter_handle, /* R4 */ - neq_handle, /* R5 */ - event_mask, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_RESET_EVENTS, + adapter_handle, /* R4 */ + neq_handle, /* R5 */ + event_mask, /* R6 */ + 0, 0, 0, 0); /* R7-R12 */ } -- GitLab From bff0a55f34e62970203c4af9c8ef4dc7d73e2f96 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Thu, 5 Oct 2006 16:53:14 +0200 Subject: [PATCH 0929/1619] [PATCH] ehea: fix port state notification, default queue sizes This patch includes a bug fix for the port state notification and fixes the default queue sizes. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 13 +++++++------ drivers/net/ehea/ehea_main.c | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 23b451a8ae1..b40724fc6b7 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0028" +#define DRV_VERSION "EHEA_0034" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) @@ -50,6 +50,7 @@ #define EHEA_MAX_ENTRIES_SQ 32767 #define EHEA_MIN_ENTRIES_QP 127 +#define EHEA_SMALL_QUEUES #define EHEA_NUM_TX_QP 1 #ifdef EHEA_SMALL_QUEUES @@ -59,11 +60,11 @@ #define EHEA_DEF_ENTRIES_RQ2 1023 #define EHEA_DEF_ENTRIES_RQ3 1023 #else -#define EHEA_MAX_CQE_COUNT 32000 -#define EHEA_DEF_ENTRIES_SQ 16000 -#define EHEA_DEF_ENTRIES_RQ1 32080 -#define EHEA_DEF_ENTRIES_RQ2 4020 -#define EHEA_DEF_ENTRIES_RQ3 4020 +#define EHEA_MAX_CQE_COUNT 4080 +#define EHEA_DEF_ENTRIES_SQ 4080 +#define EHEA_DEF_ENTRIES_RQ1 8160 +#define EHEA_DEF_ENTRIES_RQ2 2040 +#define EHEA_DEF_ENTRIES_RQ3 2040 #endif #define EHEA_MAX_ENTRIES_EQ 20 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index c6b31775e26..eb7d44de59f 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -766,7 +766,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) { if (!netif_carrier_ok(port->netdev)) { ret = ehea_sense_port_attr( - adapter->port[portnum]); + port); if (ret) { ehea_error("failed resensing port " "attributes"); @@ -818,7 +818,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) netif_stop_queue(port->netdev); break; default: - ehea_error("unknown event code %x", ec); + ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe); break; } } @@ -1841,7 +1841,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) if (netif_msg_tx_queued(port)) { ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr); - ehea_dump(swqe, sizeof(*swqe), "swqe"); + ehea_dump(swqe, 512, "swqe"); } ehea_post_swqe(pr->qp, swqe); -- GitLab From 90f10841180e9b7938f63db69e90dacb7d21bbe5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 15:56:04 -0500 Subject: [PATCH 0930/1619] [PATCH] powerpc/cell spidernet ethtool -i version number info. This patch adds version information as reported by ethtool -i to the Spidernet driver. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 3 +++ drivers/net/spider_net.h | 2 ++ drivers/net/spider_net_ethtool.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 46a009085f7..96dafb0f563 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -55,6 +55,7 @@ MODULE_AUTHOR("Utz Bacher and Jens Osterkamp " \ ""); MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; @@ -2252,6 +2253,8 @@ static struct pci_driver spider_net_driver = { */ static int __init spider_net_init(void) { + printk(KERN_INFO "Spidernet version %s.\n", VERSION); + if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) { rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN; pr_info("adjusting rx descriptors to %i.\n", rx_descriptors); diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index a59deda2f95..6193ea83628 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -24,6 +24,8 @@ #ifndef _SPIDER_NET_H #define _SPIDER_NET_H +#define VERSION "1.1 A" + #include "sungem_phy.h" extern int spider_net_stop(struct net_device *netdev); diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 589e43658de..fda74f7d6fd 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -76,7 +76,7 @@ spider_net_ethtool_get_drvinfo(struct net_device *netdev, /* clear and fill out info */ memset(drvinfo, 0, sizeof(struct ethtool_drvinfo)); strncpy(drvinfo->driver, spider_net_driver_name, 32); - strncpy(drvinfo->version, "0.1", 32); + strncpy(drvinfo->version, VERSION, 32); strcpy(drvinfo->fw_version, "no information"); strncpy(drvinfo->bus_info, pci_name(card->pdev), 32); } -- GitLab From a02d601dd59d08a77563499cc05b48603df8f4a4 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 15:57:26 -0500 Subject: [PATCH 0931/1619] [PATCH] powerpc/cell spidernet burst alignment patch. This patch increases the Burst Address alignment from 64 to 1024 in the Spidernet driver. This improves transmit performance for large packets. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 6193ea83628..b2e3570c010 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -211,7 +211,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003 /* to set TX_DMA_EN */ #define SPIDER_NET_TX_DMA_EN 0x80000000 -#define SPIDER_NET_GDTDCEIDIS 0x00000002 +#define SPIDER_NET_GDTDCEIDIS 0x00000302 #define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ SPIDER_NET_GDTDCEIDIS #define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003 -- GitLab From e2874f2e8c3695953b9ec26d396d678a7128ee64 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 15:59:02 -0500 Subject: [PATCH 0932/1619] [PATCH] Spidernet module parm permissions The module param permsissions should bw read-only, not writable. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 96dafb0f563..ff409a10274 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -60,8 +60,8 @@ MODULE_VERSION(VERSION); static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; -module_param(rx_descriptors, int, 0644); -module_param(tx_descriptors, int, 0644); +module_param(rx_descriptors, int, 0444); +module_param(tx_descriptors, int, 0444); MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \ "in rx chains"); -- GitLab From c3fee4c55915c42b3278b65c91f9be8cee13426e Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:00:04 -0500 Subject: [PATCH 0933/1619] [PATCH] powerpc/cell spidernet force-end fix Bugfix: when cleaning up the transmit queue upon device close, be sure to walk the entire queue. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index ff409a10274..52bf1b2968b 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -699,6 +699,8 @@ spider_net_release_tx_descr(struct spider_net_card *card) /* unmap the skb */ skb = descr->skb; + if (!skb) + return; pci_unmap_single(card->pdev, descr->buf_addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); @@ -751,7 +753,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) default: card->netdev_stats.tx_dropped++; - return 1; + if (!brutal) + return 1; } spider_net_release_tx_descr(card); } -- GitLab From 808999c9a4749dc67c39bf52f712d0c27aa00e67 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:01:00 -0500 Subject: [PATCH 0934/1619] [PATCH] powerpc/cell spidernet zlen min packet length Polite device drivers pad short packets to 60 bytes, so that mean-spirited users don't accidentally DOS some other OS that can't handle short packets. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 52bf1b2968b..f5f73571a7a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -648,18 +648,26 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, { struct spider_net_descr *descr = card->tx_chain.head; dma_addr_t buf; + int length; - buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + length = skb->len; + if (length < ETH_ZLEN) { + if (skb_pad(skb, ETH_ZLEN-length)) + return 0; + length = ETH_ZLEN; + } + + buf = pci_map_single(card->pdev, skb->data, length, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(buf)) { if (netif_msg_tx_err(card) && net_ratelimit()) pr_err("could not iommu-map packet (%p, %i). " - "Dropping packet\n", skb->data, skb->len); + "Dropping packet\n", skb->data, length); card->spider_stats.tx_iommu_map_error++; return -ENOMEM; } descr->buf_addr = buf; - descr->buf_size = skb->len; + descr->buf_size = length; descr->next_descr_addr = 0; descr->skb = skb; descr->data_status = 0; @@ -693,6 +701,7 @@ spider_net_release_tx_descr(struct spider_net_card *card) { struct spider_net_descr *descr = card->tx_chain.tail; struct sk_buff *skb; + unsigned int len; card->tx_chain.tail = card->tx_chain.tail->next; descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; @@ -701,7 +710,8 @@ spider_net_release_tx_descr(struct spider_net_card *card) skb = descr->skb; if (!skb) return; - pci_unmap_single(card->pdev, descr->buf_addr, skb->len, + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + pci_unmap_single(card->pdev, descr->buf_addr, len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); } -- GitLab From 917a5b8e648f420105158023ae0317eb0e77a2d5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:01:51 -0500 Subject: [PATCH 0935/1619] [PATCH] powerpc/cell spidernet add missing netdev watchdog Set the netdev watchdog timer. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index f5f73571a7a..0aed69382b2 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -686,6 +686,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, descr->prev->next_descr_addr = descr->bus_addr; + card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ return 0; } -- GitLab From ded8028a0b61075d841c33a412da5c869140d7aa Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:02:54 -0500 Subject: [PATCH 0936/1619] [PATCH] Spidernet fix register field definitions This patch fixes the names of a few fields in the DMA control register. There is no functional change. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 +- drivers/net/spider_net.h | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 0aed69382b2..2f54cddf75a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1614,7 +1614,7 @@ spider_net_enable_card(struct spider_net_card *card) SPIDER_NET_INT2_MASK_VALUE); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, - SPIDER_NET_GDTDCEIDIS); + SPIDER_NET_GDTBSTA | SPIDER_NET_GDTDCEIDIS); } /** diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index b2e3570c010..80f4d2739d4 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -191,7 +191,9 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_MACMODE_VALUE 0x00000001 #define SPIDER_NET_BURSTLMT_VALUE 0x00000200 /* about 16 us */ -/* 1(0) enable r/tx dma +/* DMAC control register GDMACCNTR + * + * 1(0) enable r/tx dma * 0000000 fixed to 0 * * 000000 fixed to 0 @@ -200,6 +202,7 @@ extern char spider_net_driver_name[]; * * 000000 fixed to 0 * 00 burst alignment: 128 bytes + * 11 burst alignment: 1024 bytes * * 00000 fixed to 0 * 0 descr writeback size 32 bytes @@ -210,10 +213,13 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_DMA_RX_VALUE 0x80000000 #define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003 /* to set TX_DMA_EN */ -#define SPIDER_NET_TX_DMA_EN 0x80000000 -#define SPIDER_NET_GDTDCEIDIS 0x00000302 -#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ - SPIDER_NET_GDTDCEIDIS +#define SPIDER_NET_TX_DMA_EN 0x80000000 +#define SPIDER_NET_GDTBSTA 0x00000300 +#define SPIDER_NET_GDTDCEIDIS 0x00000002 +#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ + SPIDER_NET_GDTBSTA | \ + SPIDER_NET_GDTDCEIDIS + #define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003 /* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */ -- GitLab From 313ef4b76c96ef427a7613d89df550aa5d02bf21 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:04:00 -0500 Subject: [PATCH 0937/1619] [PATCH] Spidernet stop queue when queue is full. This patch adds a call to netif_stop_queue() when there is no more room for more packets on the transmit queue. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 2f54cddf75a..05bdd0be739 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -823,39 +823,25 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) struct spider_net_descr_chain *chain = &card->tx_chain; struct spider_net_descr *descr = chain->head; unsigned long flags; - int result; spin_lock_irqsave(&chain->lock, flags); spider_net_release_tx_chain(card, 0); - if (chain->head->next == chain->tail->prev) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; - } + if ((chain->head->next == chain->tail->prev) || + (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) || + (spider_net_prepare_tx_descr(card, skb) != 0)) { - if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) { card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; + spin_unlock_irqrestore(&chain->lock, flags); + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; } - if (spider_net_prepare_tx_descr(card, skb) != 0) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_BUSY; - goto out; - } - - result = NETDEV_TX_OK; - spider_net_kick_tx_dma(card); card->tx_chain.head = card->tx_chain.head->next; - -out: spin_unlock_irqrestore(&chain->lock, flags); - netif_wake_queue(netdev); - return result; + return NETDEV_TX_OK; } /** @@ -874,9 +860,10 @@ spider_net_cleanup_tx_ring(struct spider_net_card *card) spin_lock_irqsave(&card->tx_chain.lock, flags); if ((spider_net_release_tx_chain(card, 0) != 0) && - (card->netdev->flags & IFF_UP)) + (card->netdev->flags & IFF_UP)) { spider_net_kick_tx_dma(card); - + netif_wake_queue(card->netdev); + } spin_unlock_irqrestore(&card->tx_chain.lock, flags); } -- GitLab From 43932d938d5a193bf9602b0ac8aa6783ba78b1aa Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:05:00 -0500 Subject: [PATCH 0938/1619] [PATCH] powerpc/cell spidernet bogus rx interrupt bit The current receive interrupt mask sets a bogus bit that doesn't even belong to the definition of this register. Remove it. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 80f4d2739d4..6c9d7ce7f73 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -332,9 +332,8 @@ enum spider_net_int2_status { (1 << SPIDER_NET_GDTDCEINT) | \ (1 << SPIDER_NET_GDTFDCINT) ) -/* we rely on flagged descriptor interrupts*/ -#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \ - (1 << SPIDER_NET_GRMFLLINT) ) +/* We rely on flagged descriptor interrupts */ +#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) #define SPIDER_NET_ERRINT ( 0xffffffff & \ (~SPIDER_NET_TXINT) & \ -- GitLab From 37aad7500bf7064bf150ea1f234303f4173f7b24 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:06:53 -0500 Subject: [PATCH 0939/1619] [PATCH] powerpc/cell spidernet fix error interrupt print The print message associated with the descriptor chain end interrupt prints a bogs value. Fix that. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 05bdd0be739..9d2ed04f9fd 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1356,7 +1356,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) if (netif_msg_intr(card)) pr_err("got descriptor chain end interrupt, " "restarting DMAC %c.\n", - 'D'+i-SPIDER_NET_GDDDCEINT); + 'D'-(i-SPIDER_NET_GDDDCEINT)/3); spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); show_error = 0; -- GitLab From 98b9040c747e50fe02ad616c9d5fee9aa4017cd1 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:08:42 -0500 Subject: [PATCH 0940/1619] [PATCH] powerpc/cell spidernet stop error printing patch. Turn off mis-interpretation of the queue-empty interrupt status bit as an error. Signed-off-by: Linas Vepstas Signed-off-by: James K Lewis Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 9d2ed04f9fd..0eeff1add88 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1245,12 +1245,15 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_PHYINT: case SPIDER_NET_GMAC2INT: case SPIDER_NET_GMAC1INT: - case SPIDER_NET_GIPSINT: case SPIDER_NET_GFIFOINT: case SPIDER_NET_DMACINT: case SPIDER_NET_GSYSINT: break; */ + case SPIDER_NET_GIPSINT: + show_error = 0; + break; + case SPIDER_NET_GPWOPCMPINT: /* PHY write operation completed */ show_error = 0; @@ -1309,9 +1312,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GDTDCEINT: /* chain end. If a descriptor should be sent, kick off * tx dma - if (card->tx_chain.tail == card->tx_chain.head) + if (card->tx_chain.tail != card->tx_chain.head) spider_net_kick_tx_dma(card); - show_error = 0; */ + */ + show_error = 0; break; /* case SPIDER_NET_G1TMCNTINT: not used. print a message */ @@ -1425,8 +1429,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) } if ((show_error) && (netif_msg_intr(card))) - pr_err("Got error interrupt, GHIINT0STS = 0x%08x, " + pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, " "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n", + card->netdev->name, status_reg, error_reg1, error_reg2); /* clear interrupt sources */ -- GitLab From b21606a773faffc2b3ec326325c433bdf37ecbdf Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:09:40 -0500 Subject: [PATCH 0941/1619] [PATCH] powerpc/cell spidernet incorrect offset Bugfix -- the rx chain is in memory after the tx chain -- the offset being used was wrong, resulting in memory corruption when the size of the rx and tx rings weren't exactly the same. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 0eeff1add88..d779a0b9d45 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1628,8 +1628,10 @@ spider_net_open(struct net_device *netdev) if (spider_net_init_chain(card, &card->tx_chain, card->descr, PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; + + /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->rx_desc, + card->descr + card->tx_desc, PCI_DMA_FROMDEVICE, card->rx_desc)) goto alloc_rx_failed; -- GitLab From 204e5fa17c7ba45a89989f8da6dfe8e54d64b79b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:11:33 -0500 Subject: [PATCH 0942/1619] [PATCH] powerpc/cell spidernet low watermark patch. Implement basic low-watermark support for the transmit queue. Hardware low-watermarks allow a properly configured kernel to continously stream data to a device and not have to handle any interrupts at all in doing so. Correct zero-interrupt operation can be actually observed for this driver, when the socket buffer is made large enough. The basic idea of a low-watermark interrupt is as follows. The device driver queues up a bunch of packets for the hardware to transmit, and then kicks the hardware to get it started. As the hardware drains the queue of pending, untransmitted packets, the device driver will want to know when the queue is almost empty, so that it can queue some more packets. If the queue drains down to the low waterark, then an interrupt will be generated. However, if the kernel/driver continues to add enough packets to keep the queue partially filled, no interrupt will actually be generated, and the hardware can continue streaming packets indefinitely in this mode. The impelmentation is done by setting the DESCR_TXDESFLG flag in one of the packets. When the hardware sees this flag, it will interrupt the device driver. Because this flag is on a fixed packet, rather than at fixed location in the queue, the code below needs to move the flag as more packets are queued up. This implementation attempts to keep the flag at about 1/4 from "empty". Signed-off-by: Linas Vepstas Signed-off-by: James K Lewis Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 43 ++++++++++++++++++++++++++++++++++++++++ drivers/net/spider_net.h | 8 ++++---- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index d779a0b9d45..96b5d00c21d 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -684,6 +684,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, break; } + /* Chain the bus address, so that the DMA engine finds this descr. */ descr->prev->next_descr_addr = descr->bus_addr; card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ @@ -717,6 +718,41 @@ spider_net_release_tx_descr(struct spider_net_card *card) dev_kfree_skb_any(skb); } +static void +spider_net_set_low_watermark(struct spider_net_card *card) +{ + int status; + int cnt=0; + int i; + struct spider_net_descr *descr = card->tx_chain.tail; + + /* Measure the length of the queue. */ + while (descr != card->tx_chain.head) { + status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; + if (status == SPIDER_NET_DESCR_NOT_IN_USE) + break; + descr = descr->next; + cnt++; + } + + /* If TX queue is short, don't even bother with interrupts */ + if (cnt < card->tx_desc/4) + return; + + /* Set low-watermark 3/4th's of the way into the queue. */ + descr = card->tx_chain.tail; + cnt = (cnt*3)/4; + for (i=0;inext; + + /* Set the new watermark, clear the old watermark */ + descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; + if (card->low_watermark && card->low_watermark != descr) + card->low_watermark->dmac_cmd_status = + card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; + card->low_watermark = descr; +} + /** * spider_net_release_tx_chain - processes sent tx descriptors * @card: adapter structure @@ -838,6 +874,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } + spider_net_set_low_watermark(card); spider_net_kick_tx_dma(card); card->tx_chain.head = card->tx_chain.head->next; spin_unlock_irqrestore(&chain->lock, flags); @@ -1467,6 +1504,10 @@ spider_net_interrupt(int irq, void *ptr) spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } + if (status_reg & SPIDER_NET_TXINT ) { + spider_net_cleanup_tx_ring(card); + netif_wake_queue(netdev); + } if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1629,6 +1670,8 @@ spider_net_open(struct net_device *netdev) PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; + card->low_watermark = NULL; + /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, card->descr + card->tx_desc, diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 6c9d7ce7f73..1f5c9dc806a 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -49,7 +49,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_TX_DESCRIPTORS_MIN 16 #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 -#define SPIDER_NET_TX_TIMER 20 +#define SPIDER_NET_TX_TIMER (HZ/5) #define SPIDER_NET_RX_CSUM_DEFAULT 1 @@ -328,9 +328,7 @@ enum spider_net_int2_status { SPIDER_NET_GRISPDNGINT }; -#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \ - (1 << SPIDER_NET_GDTDCEINT) | \ - (1 << SPIDER_NET_GDTFDCINT) ) +#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GDTFDCINT) ) /* We rely on flagged descriptor interrupts */ #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) @@ -356,6 +354,7 @@ enum spider_net_int2_status { #define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000 +#define SPIDER_NET_DESCR_TXDESFLG 0x00800000 struct spider_net_descr { /* as defined by the hardware */ @@ -440,6 +439,7 @@ struct spider_net_card { struct spider_net_descr_chain tx_chain; struct spider_net_descr_chain rx_chain; + struct spider_net_descr *low_watermark; struct net_device_stats netdev_stats; -- GitLab From 68a8c609b3071c2441fa64f584d15311f2c10e61 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:13:05 -0500 Subject: [PATCH 0943/1619] [PATCH] powerpc/cell spidernet NAPI polling info. This patch moves transmit queue cleanup code out of the interrupt context, and into the NAPI polling routine. Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Cc: James K Lewis Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 96b5d00c21d..e429abc1e94 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -715,7 +715,7 @@ spider_net_release_tx_descr(struct spider_net_card *card) len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; pci_unmap_single(card->pdev, descr->buf_addr, len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } static void @@ -885,9 +885,10 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) * spider_net_cleanup_tx_ring - cleans up the TX ring * @card: card structure * - * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use - * interrupts to cleanup our TX ring) and returns sent packets to the stack - * by freeing them + * spider_net_cleanup_tx_ring is called by either the tx_timer + * or from the NAPI polling routine. + * This routine releases resources associted with transmitted + * packets, including updating the queue tail pointer. */ static void spider_net_cleanup_tx_ring(struct spider_net_card *card) @@ -1092,6 +1093,7 @@ spider_net_poll(struct net_device *netdev, int *budget) int packets_to_do, packets_done = 0; int no_more_packets = 0; + spider_net_cleanup_tx_ring(card); packets_to_do = min(*budget, netdev->quota); while (packets_to_do) { @@ -1504,10 +1506,8 @@ spider_net_interrupt(int irq, void *ptr) spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } - if (status_reg & SPIDER_NET_TXINT ) { - spider_net_cleanup_tx_ring(card); - netif_wake_queue(netdev); - } + if (status_reg & SPIDER_NET_TXINT) + netif_rx_schedule(netdev); if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); -- GitLab From 9cc7bf7edf50a8a6b456b337aff97fe780ae369b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:14:29 -0500 Subject: [PATCH 0944/1619] [PATCH] powerpc/cell spidernet refine locking The transmit side of the spider ethernet driver currently places locks around some very large chunks of code. This results in a fair amount of lock contention is some cases. This patch makes the locks much more fine-grained, protecting only the cirtical sections. One lock is used to protect three locations: the queue head and tail pointers, and the queue low-watermark location. Signed-off-by: Linas Vepstas Cc: Arnd Bergmann Cc: James K Lewis Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 95 ++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 52 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index e429abc1e94..f8d7d0d91a6 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -646,8 +646,9 @@ static int spider_net_prepare_tx_descr(struct spider_net_card *card, struct sk_buff *skb) { - struct spider_net_descr *descr = card->tx_chain.head; + struct spider_net_descr *descr; dma_addr_t buf; + unsigned long flags; int length; length = skb->len; @@ -666,6 +667,10 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return -ENOMEM; } + spin_lock_irqsave(&card->tx_chain.lock, flags); + descr = card->tx_chain.head; + card->tx_chain.head = descr->next; + descr->buf_addr = buf; descr->buf_size = length; descr->next_descr_addr = 0; @@ -674,6 +679,8 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; + spin_unlock_irqrestore(&card->tx_chain.lock, flags); + if (skb->protocol == htons(ETH_P_IP)) switch (skb->nh.iph->protocol) { case IPPROTO_TCP: @@ -691,42 +698,17 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return 0; } -/** - * spider_net_release_tx_descr - processes a used tx descriptor - * @card: card structure - * @descr: descriptor to release - * - * releases a used tx descriptor (unmapping, freeing of skb) - */ -static inline void -spider_net_release_tx_descr(struct spider_net_card *card) -{ - struct spider_net_descr *descr = card->tx_chain.tail; - struct sk_buff *skb; - unsigned int len; - - card->tx_chain.tail = card->tx_chain.tail->next; - descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; - - /* unmap the skb */ - skb = descr->skb; - if (!skb) - return; - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - pci_unmap_single(card->pdev, descr->buf_addr, len, - PCI_DMA_TODEVICE); - dev_kfree_skb(skb); -} - static void spider_net_set_low_watermark(struct spider_net_card *card) { + unsigned long flags; int status; int cnt=0; int i; struct spider_net_descr *descr = card->tx_chain.tail; - /* Measure the length of the queue. */ + /* Measure the length of the queue. Measurement does not + * need to be precise -- does not need a lock. */ while (descr != card->tx_chain.head) { status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; if (status == SPIDER_NET_DESCR_NOT_IN_USE) @@ -746,11 +728,13 @@ spider_net_set_low_watermark(struct spider_net_card *card) descr = descr->next; /* Set the new watermark, clear the old watermark */ + spin_lock_irqsave(&card->tx_chain.lock, flags); descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; if (card->low_watermark && card->low_watermark != descr) card->low_watermark->dmac_cmd_status = card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; card->low_watermark = descr; + spin_unlock_irqrestore(&card->tx_chain.lock, flags); } /** @@ -769,21 +753,31 @@ static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { struct spider_net_descr_chain *chain = &card->tx_chain; + struct spider_net_descr *descr; + struct sk_buff *skb; + u32 buf_addr; + unsigned long flags; int status; spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR); while (chain->tail != chain->head) { - status = spider_net_get_descr_status(chain->tail); + spin_lock_irqsave(&chain->lock, flags); + descr = chain->tail; + + status = spider_net_get_descr_status(descr); switch (status) { case SPIDER_NET_DESCR_COMPLETE: card->netdev_stats.tx_packets++; - card->netdev_stats.tx_bytes += chain->tail->skb->len; + card->netdev_stats.tx_bytes += descr->skb->len; break; case SPIDER_NET_DESCR_CARDOWNED: - if (!brutal) + if (!brutal) { + spin_unlock_irqrestore(&chain->lock, flags); return 1; + } + /* fallthrough, if we release the descriptors * brutally (then we don't care about * SPIDER_NET_DESCR_CARDOWNED) */ @@ -800,12 +794,25 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) default: card->netdev_stats.tx_dropped++; - if (!brutal) + if (!brutal) { + spin_unlock_irqrestore(&chain->lock, flags); return 1; + } } - spider_net_release_tx_descr(card); - } + chain->tail = descr->next; + descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; + skb = descr->skb; + buf_addr = descr->buf_addr; + spin_unlock_irqrestore(&chain->lock, flags); + + /* unmap the skb */ + if (skb) { + int len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + pci_unmap_single(card->pdev, buf_addr, len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + } + } return 0; } @@ -857,27 +864,19 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); struct spider_net_descr_chain *chain = &card->tx_chain; - struct spider_net_descr *descr = chain->head; - unsigned long flags; - - spin_lock_irqsave(&chain->lock, flags); spider_net_release_tx_chain(card, 0); if ((chain->head->next == chain->tail->prev) || - (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) || (spider_net_prepare_tx_descr(card, skb) != 0)) { card->netdev_stats.tx_dropped++; - spin_unlock_irqrestore(&chain->lock, flags); netif_stop_queue(netdev); return NETDEV_TX_BUSY; } spider_net_set_low_watermark(card); spider_net_kick_tx_dma(card); - card->tx_chain.head = card->tx_chain.head->next; - spin_unlock_irqrestore(&chain->lock, flags); return NETDEV_TX_OK; } @@ -893,16 +892,11 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) static void spider_net_cleanup_tx_ring(struct spider_net_card *card) { - unsigned long flags; - - spin_lock_irqsave(&card->tx_chain.lock, flags); - if ((spider_net_release_tx_chain(card, 0) != 0) && (card->netdev->flags & IFF_UP)) { spider_net_kick_tx_dma(card); netif_wake_queue(card->netdev); } - spin_unlock_irqrestore(&card->tx_chain.lock, flags); } /** @@ -1930,10 +1924,7 @@ spider_net_stop(struct net_device *netdev) spider_net_disable_rxdmac(card); /* release chains */ - if (spin_trylock(&card->tx_chain.lock)) { - spider_net_release_tx_chain(card, 1); - spin_unlock(&card->tx_chain.lock); - } + spider_net_release_tx_chain(card, 1); spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); -- GitLab From 499eea18722e43f0ee15e11ac16ffcbd10b70b24 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:15:29 -0500 Subject: [PATCH 0945/1619] [PATCH] powerpc/cell spidernet Remove a dummy register read that is not needed. This reduces CPU usage notably during transmit. Signed-off-by: Linas Vepstas Cc: Arnd Bergmann Cc: James K Lewis Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index f8d7d0d91a6..6bb8f1f9437 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -759,8 +759,6 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) unsigned long flags; int status; - spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR); - while (chain->tail != chain->head) { spin_lock_irqsave(&chain->lock, flags); descr = chain->tail; -- GitLab From a664ccf430547696951bf3949f5a2de5079ece5a Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:18:18 -0500 Subject: [PATCH 0946/1619] [PATCH] powerpc/cell spidernet reduce DMA kicking The current code attempts to start the TX dma every time a packet is queued. This is too conservative, and wastes CPU time. This patch changes behaviour to call the kick-dma function less often, only when the tx queue is at risk of emptying. This reduces cpu usage, improves performance. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 6bb8f1f9437..caa11c6f21b 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -698,7 +698,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return 0; } -static void +static int spider_net_set_low_watermark(struct spider_net_card *card) { unsigned long flags; @@ -719,7 +719,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) /* If TX queue is short, don't even bother with interrupts */ if (cnt < card->tx_desc/4) - return; + return cnt; /* Set low-watermark 3/4th's of the way into the queue. */ descr = card->tx_chain.tail; @@ -735,6 +735,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; card->low_watermark = descr; spin_unlock_irqrestore(&card->tx_chain.lock, flags); + return cnt; } /** @@ -819,8 +820,12 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) * @card: card structure * @descr: descriptor address to enable TX processing at * - * spider_net_kick_tx_dma writes the current tx chain head as start address - * of the tx descriptor chain and enables the transmission DMA engine + * This routine will start the transmit DMA running if + * it is not already running. This routine ned only be + * called when queueing a new packet to an empty tx queue. + * Writes the current tx chain head as start address + * of the tx descriptor chain and enables the transmission + * DMA engine. */ static inline void spider_net_kick_tx_dma(struct spider_net_card *card) @@ -860,6 +865,7 @@ out: static int spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { + int cnt; struct spider_net_card *card = netdev_priv(netdev); struct spider_net_descr_chain *chain = &card->tx_chain; @@ -873,8 +879,9 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - spider_net_set_low_watermark(card); - spider_net_kick_tx_dma(card); + cnt = spider_net_set_low_watermark(card); + if (cnt < 5) + spider_net_kick_tx_dma(card); return NETDEV_TX_OK; } -- GitLab From 66c097165cf6d4196e798145fb33c768164fb361 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:19:34 -0500 Subject: [PATCH 0947/1619] [PATCH] powerpc/cell spidernet variable name change Cosmetic patch: give the variable holding the numer of descriptors a more descriptive name, so to avoid confusion. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 12 ++++++------ drivers/net/spider_net.h | 4 ++-- drivers/net/spider_net_ethtool.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index caa11c6f21b..88e7e41adec 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -718,7 +718,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) } /* If TX queue is short, don't even bother with interrupts */ - if (cnt < card->tx_desc/4) + if (cnt < card->num_tx_desc/4) return cnt; /* Set low-watermark 3/4th's of the way into the queue. */ @@ -1666,15 +1666,15 @@ spider_net_open(struct net_device *netdev) result = -ENOMEM; if (spider_net_init_chain(card, &card->tx_chain, card->descr, - PCI_DMA_TODEVICE, card->tx_desc)) + PCI_DMA_TODEVICE, card->num_tx_desc)) goto alloc_tx_failed; card->low_watermark = NULL; /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->tx_desc, - PCI_DMA_FROMDEVICE, card->rx_desc)) + card->descr + card->num_tx_desc, + PCI_DMA_FROMDEVICE, card->num_rx_desc)) goto alloc_rx_failed; /* allocate rx skbs */ @@ -2060,8 +2060,8 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - card->tx_desc = tx_descriptors; - card->rx_desc = rx_descriptors; + card->num_tx_desc = tx_descriptors; + card->num_rx_desc = rx_descriptors; spider_net_setup_netdev_ops(netdev); diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 1f5c9dc806a..b3b46119b42 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -455,8 +455,8 @@ struct spider_net_card { /* for ethtool */ int msg_enable; - int rx_desc; - int tx_desc; + int num_rx_desc; + int num_tx_desc; struct spider_net_extra_stats spider_stats; struct spider_net_descr descr[0]; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index fda74f7d6fd..91b99510291 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, struct spider_net_card *card = netdev->priv; ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; - ering->tx_pending = card->tx_desc; + ering->tx_pending = card->num_tx_desc; ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; - ering->rx_pending = card->rx_desc; + ering->rx_pending = card->num_rx_desc; } static int spider_net_get_stats_count(struct net_device *netdev) -- GitLab From 348bc2a6e306dc3e875cee3389e1405963ace617 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:21:10 -0500 Subject: [PATCH 0948/1619] [PATCH] powerpc/cell spidernet DMA direction fix The ring buffer descriptors are DMA-accessed bidirectionally, but are not declared in this way. Fix this. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 88e7e41adec..a26dd1c6318 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -301,7 +301,7 @@ static int spider_net_init_chain(struct spider_net_card *card, struct spider_net_descr_chain *chain, struct spider_net_descr *start_descr, - int direction, int no) + int no) { int i; struct spider_net_descr *descr; @@ -316,7 +316,7 @@ spider_net_init_chain(struct spider_net_card *card, buf = pci_map_single(card->pdev, descr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(buf)) goto iommu_error; @@ -330,11 +330,6 @@ spider_net_init_chain(struct spider_net_card *card, (descr-1)->next = start_descr; start_descr->prev = descr-1; - descr = start_descr; - if (direction == PCI_DMA_FROMDEVICE) - for (i=0; i < no; i++, descr++) - descr->next_descr_addr = descr->next->bus_addr; - spin_lock_init(&chain->lock); chain->head = start_descr; chain->tail = start_descr; @@ -347,7 +342,7 @@ iommu_error: if (descr->bus_addr) pci_unmap_single(card->pdev, descr->bus_addr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); return -ENOMEM; } @@ -368,7 +363,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); + PCI_DMA_BIDIRECTIONAL); } descr = descr->next; } @@ -1662,21 +1657,26 @@ int spider_net_open(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - int result; + struct spider_net_descr *descr; + int i, result; result = -ENOMEM; if (spider_net_init_chain(card, &card->tx_chain, card->descr, - PCI_DMA_TODEVICE, card->num_tx_desc)) + card->num_tx_desc)) goto alloc_tx_failed; card->low_watermark = NULL; /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->num_tx_desc, - PCI_DMA_FROMDEVICE, card->num_rx_desc)) + card->descr + card->num_tx_desc, + card->num_rx_desc)) goto alloc_rx_failed; + descr = card->rx_chain.head; + for (i=0; i < card->num_rx_desc; i++, descr++) + descr->next_descr_addr = descr->next->bus_addr; + /* allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; -- GitLab From 647519100105fb4ddfe6455e820093999c08c4be Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:22:29 -0500 Subject: [PATCH 0949/1619] [PATCH] powerpc/cell spidernet release all descrs Bugfix: rx descriptor release function fails to visit the last entry while walking receive descriptor ring. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index a26dd1c6318..418138dd6c6 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -358,7 +358,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) struct spider_net_descr *descr; descr = card->rx_chain.head; - while (descr->next != card->rx_chain.head) { + do { if (descr->skb) { dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, @@ -366,7 +366,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) PCI_DMA_BIDIRECTIONAL); } descr = descr->next; - } + } while (descr != card->rx_chain.head); } /** -- GitLab From a1bc9b875be597cdf147db2748ba7ddc6b0f0fbe Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:50 -0700 Subject: [PATCH 0950/1619] [PATCH] skge: fix stuck irq when fiber down The PHY interrupt from the internal fiber is getting stuck on when the link is down. Add code to handle the transition and mask it. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 53 ++++++++++++++++++++++++++++++---------------- drivers/net/skge.h | 3 ++- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a4a58e4e93a..57764935a9f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -884,6 +884,29 @@ static void skge_link_down(struct skge_port *skge) printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); } + +static void xm_link_down(struct skge_hw *hw, int port) +{ + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); + u16 cmd, msk; + + if (hw->phy_type == SK_PHY_XMAC) { + msk = xm_read16(hw, port, XM_IMSK); + msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND; + xm_write16(hw, port, XM_IMSK, msk); + } + + cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); + xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ + (void) xm_read16(hw, port, XM_MMU_CMD); + + if (netif_carrier_ok(dev)) + skge_link_down(skge); +} + static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) { int i; @@ -1008,14 +1031,7 @@ static void bcom_check_link(struct skge_hw *hw, int port) status = xm_phy_read(hw, port, PHY_BCOM_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); + xm_link_down(hw, port); return; } @@ -1235,14 +1251,7 @@ static void xm_check_link(struct net_device *dev) status = xm_phy_read(hw, port, PHY_XMAC_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); + xm_link_down(hw, port); return; } @@ -1568,6 +1577,10 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", skge->netdev->name, status); + if (hw->phy_type == SK_PHY_XMAC && + (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC))) + xm_link_down(hw, port); + if (status & XM_IS_TXF_UR) { xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; @@ -1582,7 +1595,7 @@ static void genesis_link_up(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u16 cmd; + u16 cmd, msk; u32 mode; cmd = xm_read16(hw, port, XM_MMU_CMD); @@ -1631,7 +1644,11 @@ static void genesis_link_up(struct skge_port *skge) } xm_write32(hw, port, XM_MODE, mode); - xm_write16(hw, port, XM_IMSK, XM_DEF_MSK); + msk = XM_DEF_MSK; + if (hw->phy_type != SK_PHY_XMAC) + msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ + + xm_write16(hw, port, XM_IMSK, msk); xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ diff --git a/drivers/net/skge.h b/drivers/net/skge.h index d0b47d46cf9..9cc955c1250 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2195,7 +2195,8 @@ enum { XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ }; -#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR)) +#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \ + XM_IS_RXF_OV | XM_IS_TXF_UR)) /* XM_HW_CFG 16 bit r/w Hardware Config Register */ -- GitLab From 4b67be999ed5bfb1bfe4cc502d37d59b4f6b6b7f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:51 -0700 Subject: [PATCH 0951/1619] [PATCH] skge: pause mapping for fiber Do correct mapping of pause and duplex when using 1000BaseX fiber versions of the board. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 57764935a9f..c19f49bce7a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -197,8 +197,8 @@ static u32 skge_supported_modes(const struct skge_hw *hw) else if (hw->chip_id == CHIP_ID_YUKON) supported &= ~SUPPORTED_1000baseT_Half; } else - supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; + supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half + | SUPPORTED_FIBRE | SUPPORTED_Autoneg; return supported; } @@ -1018,6 +1018,14 @@ static const u16 phy_pause_map[] = { [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, }; +/* special defines for FIBER (88E1011S only) */ +static const u16 fiber_pause_map[] = { + [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, + [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, + [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, + [FLOW_MODE_REM_SEND] = PHY_X_P_BOTH_MD, +}; + /* Check status of Broadcom phy link */ static void bcom_check_link(struct skge_hw *hw, int port) @@ -1207,17 +1215,7 @@ static void xm_phy_init(struct skge_port *skge) if (skge->advertising & ADVERTISED_1000baseT_Full) ctrl |= PHY_X_AN_FD; - switch(skge->flow_control) { - case FLOW_MODE_NONE: - ctrl |= PHY_X_P_NO_PAUSE; - break; - case FLOW_MODE_LOC_SEND: - ctrl |= PHY_X_P_ASYM_MD; - break; - case FLOW_MODE_SYMMETRIC: - ctrl |= PHY_X_P_BOTH_MD; - break; - } + ctrl |= fiber_pause_map[skge->flow_control]; xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); @@ -1796,11 +1794,17 @@ static void yukon_init(struct skge_hw *hw, int port) adv |= PHY_M_AN_10_FD; if (skge->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - } else /* special defines for FIBER (88E1011S only) */ - adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; - /* Set Flow-control capabilities */ - adv |= phy_pause_map[skge->flow_control]; + /* Set Flow-control capabilities */ + adv |= phy_pause_map[skge->flow_control]; + } else { + if (skge->advertising & ADVERTISED_1000baseT_Full) + adv |= PHY_M_AN_1000X_AFD; + if (skge->advertising & ADVERTISED_1000baseT_Half) + adv |= PHY_M_AN_1000X_AHD; + + adv |= fiber_pause_map[skge->flow_control]; + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; -- GitLab From 5d5c8e03786691d0d083142b922edce8609c0fd5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:52 -0700 Subject: [PATCH 0952/1619] [PATCH] skge: better flow control negotiation Do flow control negotiation properly. Don't let auto negotiation status limit renegotiation. Separate desired pause values from the result of auto negotiation. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 129 +++++++++++++++++++++++++++------------------ drivers/net/skge.h | 22 ++++++-- 2 files changed, 95 insertions(+), 56 deletions(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c19f49bce7a..d844a837a8f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -487,31 +487,37 @@ static void skge_get_pauseparam(struct net_device *dev, { struct skge_port *skge = netdev_priv(dev); - ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); - ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); + ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC) + || (skge->flow_control == FLOW_MODE_SYM_OR_REM); + ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND); - ecmd->autoneg = skge->autoneg; + ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause; } static int skge_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { struct skge_port *skge = netdev_priv(dev); + struct ethtool_pauseparam old; - skge->autoneg = ecmd->autoneg; - if (ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if (ecmd->rx_pause && !ecmd->tx_pause) - skge->flow_control = FLOW_MODE_REM_SEND; - else if (!ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_LOC_SEND; - else - skge->flow_control = FLOW_MODE_NONE; + skge_get_pauseparam(dev, &old); + + if (ecmd->autoneg != old.autoneg) + skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC; + else { + if (ecmd->rx_pause && ecmd->tx_pause) + skge->flow_control = FLOW_MODE_SYMMETRIC; + else if (ecmd->rx_pause && !ecmd->tx_pause) + skge->flow_control = FLOW_MODE_SYM_OR_REM; + else if (!ecmd->rx_pause && ecmd->tx_pause) + skge->flow_control = FLOW_MODE_LOC_SEND; + else + skge->flow_control = FLOW_MODE_NONE; + } if (netif_running(dev)) skge_phy_reset(skge); + return 0; } @@ -854,6 +860,23 @@ static int skge_rx_fill(struct net_device *dev) return 0; } +static const char *skge_pause(enum pause_status status) +{ + switch(status) { + case FLOW_STAT_NONE: + return "none"; + case FLOW_STAT_REM_SEND: + return "rx only"; + case FLOW_STAT_LOC_SEND: + return "tx_only"; + case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */ + return "both"; + default: + return "indeterminated"; + } +} + + static void skge_link_up(struct skge_port *skge) { skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), @@ -862,16 +885,13 @@ static void skge_link_up(struct skge_port *skge) netif_carrier_on(skge->netdev); netif_wake_queue(skge->netdev); - if (netif_msg_link(skge)) + if (netif_msg_link(skge)) { printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", skge->netdev->name, skge->speed, skge->duplex == DUPLEX_FULL ? "full" : "half", - (skge->flow_control == FLOW_MODE_NONE) ? "none" : - (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" : - (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" : - (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" : - "unknown"); + skge_pause(skge->flow_status)); + } } static void skge_link_down(struct skge_port *skge) @@ -1015,7 +1035,7 @@ static const u16 phy_pause_map[] = { [FLOW_MODE_NONE] = 0, [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, - [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, + [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, }; /* special defines for FIBER (88E1011S only) */ @@ -1023,7 +1043,7 @@ static const u16 fiber_pause_map[] = { [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, - [FLOW_MODE_REM_SEND] = PHY_X_P_BOTH_MD, + [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD, }; @@ -1072,20 +1092,19 @@ static void bcom_check_link(struct skge_hw *hw, int port) return; } - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (aux & PHY_B_AS_PAUSE_MSK) { case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } skge->speed = SPEED_1000; } @@ -1283,15 +1302,20 @@ static void xm_check_link(struct net_device *dev) } /* We are using IEEE 802.3z/D5.0 Table 37-4 */ - if (lpa & PHY_X_P_SYM_MD) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) - skge->flow_control = FLOW_MODE_REM_SEND; - else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) - skge->flow_control = FLOW_MODE_LOC_SEND; + if ((skge->flow_control == FLOW_MODE_SYMMETRIC || + skge->flow_control == FLOW_MODE_SYM_OR_REM) && + (lpa & PHY_X_P_SYM_MD)) + skge->flow_status = FLOW_STAT_SYMMETRIC; + else if (skge->flow_control == FLOW_MODE_SYM_OR_REM && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) + /* Enable PAUSE receive, disable PAUSE transmit */ + skge->flow_status = FLOW_STAT_REM_SEND; + else if (skge->flow_control == FLOW_MODE_LOC_SEND && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) + /* Disable PAUSE receive, enable PAUSE transmit */ + skge->flow_status = FLOW_STAT_LOC_SEND; else - skge->flow_control = FLOW_MODE_NONE; - + skge->flow_status = FLOW_STAT_NONE; skge->speed = SPEED_1000; } @@ -1602,8 +1626,8 @@ static void genesis_link_up(struct skge_port *skge) * enabling pause frame reception is required for 1000BT * because the XMAC is not reset if the link is going down */ - if (skge->flow_control == FLOW_MODE_NONE || - skge->flow_control == FLOW_MODE_LOC_SEND) + if (skge->flow_status == FLOW_STAT_NONE || + skge->flow_status == FLOW_STAT_LOC_SEND) /* Disable Pause Frame Reception */ cmd |= XM_MMU_IGN_PF; else @@ -1613,8 +1637,8 @@ static void genesis_link_up(struct skge_port *skge) xm_write16(hw, port, XM_MMU_CMD, cmd); mode = xm_read32(hw, port, XM_MODE); - if (skge->flow_control == FLOW_MODE_SYMMETRIC || - skge->flow_control == FLOW_MODE_LOC_SEND) { + if (skge->flow_status== FLOW_STAT_SYMMETRIC || + skge->flow_status == FLOW_STAT_LOC_SEND) { /* * Configure Pause Frame Generation * Use internal and external Pause Frame Generation. @@ -1938,6 +1962,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) case FLOW_MODE_LOC_SEND: /* disable Rx flow-control */ reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; + break; + case FLOW_MODE_SYMMETRIC: + case FLOW_MODE_SYM_OR_REM: + /* enable Tx & Rx flow-control */ + break; } gma_write16(hw, port, GM_GP_CTRL, reg); @@ -2132,13 +2161,11 @@ static void yukon_link_down(struct skge_port *skge) ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); - if (skge->flow_control == FLOW_MODE_REM_SEND) { + if (skge->flow_status == FLOW_STAT_REM_SEND) { + ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); + ctrl |= PHY_M_AN_ASP; /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, - PHY_MARV_AUNE_ADV) - | PHY_M_AN_ASP); - + gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl); } yukon_reset(hw, port); @@ -2185,19 +2212,19 @@ static void yukon_phy_intr(struct skge_port *skge) /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (phystat & PHY_M_PS_PAUSE_MSK) { case PHY_M_PS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_M_PS_RX_P_EN: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_M_PS_TX_P_EN: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } - if (skge->flow_control == FLOW_MODE_NONE || + if (skge->flow_status == FLOW_STAT_NONE || (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); else @@ -3420,7 +3447,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* Auto speed and flow control */ skge->autoneg = AUTONEG_ENABLE; - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_control = FLOW_MODE_SYM_OR_REM; skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 9cc955c1250..537c0aaa1db 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2427,13 +2427,24 @@ struct skge_hw { struct mutex phy_mutex; }; -enum { - FLOW_MODE_NONE = 0, /* No Flow-Control */ - FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ - FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */ +enum pause_control { + FLOW_MODE_NONE = 1, /* No Flow-Control */ + FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ + FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or + * just the remote station may send PAUSE + */ +}; + +enum pause_status { + FLOW_STAT_INDETERMINATED=0, /* indeterminated */ + FLOW_STAT_NONE, /* No Flow Control */ + FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */ + FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */ + FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */ }; + struct skge_port { u32 msg_enable; struct skge_hw *hw; @@ -2446,9 +2457,10 @@ struct skge_port { struct net_device_stats net_stats; struct work_struct link_thread; + enum pause_control flow_control; + enum pause_status flow_status; u8 rx_csum; u8 blink_on; - u8 flow_control; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ -- GitLab From 370de6cdc2ed27c41b313c031e4258ffa32272bc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:53 -0700 Subject: [PATCH 0953/1619] [PATCH] skge: version 1.9 Want to be able to track downstream impact of fiber related fixes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d844a837a8f..e7e414928f8 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -43,7 +43,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.8" +#define DRV_VERSION "1.9" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 -- GitLab From 7bd656d12119708b37414bf909ab2995473da818 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 9 Oct 2006 14:40:38 -0700 Subject: [PATCH 0954/1619] [PATCH] sky2: revert pci express extensions The pci express error handling extensions don't work unless PCI access is via mmconfig. Otherwise, all accesses to pci config registers greater than 256 fail. Since the sky2 driver has other ways of getting to PCI config space, it works around this short coming, but the pci_find_ext_capablity doesn't work. This backs out commit 91aeb3edbcf4e6ed72d138ac8c22fd68e6d717c3 Go back to hardcoding, since we know where the error registers are anyway. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=7222 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 30 ++++++++---------------------- drivers/net/sky2.h | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 5a5289b7a88..1f91f30f4c6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2220,8 +2220,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) /* PCI-Express uncorrectable Error occurred */ u32 pex_err; - pex_err = sky2_pci_read32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS); + pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); if (net_ratelimit()) printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", @@ -2229,20 +2228,15 @@ static void sky2_hw_intr(struct sky2_hw *hw) /* clear the interrupt */ sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - sky2_pci_write32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS, - 0xffffffffUL); + sky2_pci_write32(hw, PEX_UNC_ERR_STAT, + 0xffffffffUL); sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - - /* In case of fatal error mask off to keep from getting stuck */ - if (pex_err & (PCI_ERR_UNC_POISON_TLP | PCI_ERR_UNC_FCP - | PCI_ERR_UNC_DLP)) { + if (pex_err & PEX_FATAL_ERRORS) { u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); hwmsk &= ~Y2_IS_PCI_EXP; sky2_write32(hw, B0_HWE_IMSK, hwmsk); } - } if (status & Y2_HWE_L1_MASK) @@ -2423,7 +2417,6 @@ static int sky2_reset(struct sky2_hw *hw) u16 status; u8 t8; int i; - u32 msk; sky2_write8(hw, B0_CTST, CS_RST_CLR); @@ -2464,13 +2457,9 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_MRST_CLR); /* clear any PEX errors */ - if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) { - hw->err_cap = pci_find_ext_capability(hw->pdev, PCI_EXT_CAP_ID_ERR); - if (hw->err_cap) - sky2_pci_write32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS, - 0xffffffffUL); - } + if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) + sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); hw->ports = 1; @@ -2527,10 +2516,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53); } - msk = Y2_HWE_ALL_MASK; - if (!hw->err_cap) - msk &= ~Y2_IS_PCI_EXP; - sky2_write32(hw, B0_HWE_IMSK, msk); + sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); for (i = 0; i < hw->ports; i++) sky2_gmac_reset(hw, i); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f66109a96d9..43d2accf60e 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -6,15 +6,24 @@ #define ETH_JUMBO_MTU 9000 /* Maximum MTU supported */ -/* PCI device specific config registers */ +/* PCI config registers */ enum { PCI_DEV_REG1 = 0x40, PCI_DEV_REG2 = 0x44, + PCI_DEV_STATUS = 0x7c, PCI_DEV_REG3 = 0x80, PCI_DEV_REG4 = 0x84, PCI_DEV_REG5 = 0x88, }; +enum { + PEX_DEV_CAP = 0xe4, + PEX_DEV_CTRL = 0xe8, + PEX_DEV_STA = 0xea, + PEX_LNK_STAT = 0xf2, + PEX_UNC_ERR_STAT= 0x104, +}; + /* Yukon-2 */ enum pci_dev_reg_1 { PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */ @@ -63,6 +72,39 @@ enum pci_dev_reg_4 { PCI_STATUS_REC_MASTER_ABORT | \ PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) + +enum pex_dev_ctrl { + PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */ + PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */ + PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */ + PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */ + PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */ + PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */ + PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */ + PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */ + PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */ + PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */ + PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */ +}; +#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK) + +/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */ +enum pex_err { + PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */ + + PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */ + + PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */ + + PEX_COMP_TO = 1<<14, /* Completion Timeout */ + PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */ + PEX_POIS_TLP = 1<<12, /* Poisoned TLP */ + + PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */ + PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P), +}; + + enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -1836,7 +1878,6 @@ struct sky2_hw { struct net_device *dev[2]; int pm_cap; - int err_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; -- GitLab From 6e532cfe49b6e961e1260642a44959b645e9ab54 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 9 Oct 2006 15:49:27 -0700 Subject: [PATCH 0955/1619] [PATCH] sky2: set lower pause threshold to prevent overrun Adjust the pause threshold on slower systems to keep from getting overrun. Since FIFO is 2K bytes, don't send XON pause until there is space for a full frame. Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1f91f30f4c6..c10e7f5faa5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -683,7 +683,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); + sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 512/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); if (hw->dev[port]->mtu > ETH_DATA_LEN) { /* set Tx GMAC FIFO Almost Empty Threshold */ -- GitLab From 4a1d2d81fa327d095a0a8a1f961bace5b0a2f7da Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 6 Oct 2006 12:12:34 -0600 Subject: [PATCH 0956/1619] [PATCH] Fix section mismatch in de2104x.c WARNING: drivers/net/tulip/de2104x.o - Section mismatch: reference to .init.text:de_init_one from .data.rel.local after 'de_driver' (at offset 0x20) WARNING: drivers/net/tulip/de2104x.o - Section mismatch: reference to .exit.text:de_remove_one from .data.rel.local after 'de_driver' (at offset 0x28) Signed-off-by: Helge Deller Signed-off-by: Kyle McMartin Signed-off-by: Matthew Wilcox Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 2cfd9634895..f6b3a94e97b 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1730,7 +1730,7 @@ static void __init de21040_get_media_info(struct de_private *de) } /* Note: this routine returns extra data bits for size detection. */ -static unsigned __init tulip_read_eeprom(void __iomem *regs, int location, int addr_len) +static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len) { int i; unsigned retval = 0; @@ -1926,7 +1926,7 @@ bad_srom: goto fill_defaults; } -static int __init de_init_one (struct pci_dev *pdev, +static int __devinit de_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; @@ -2082,7 +2082,7 @@ err_out_free: return rc; } -static void __exit de_remove_one (struct pci_dev *pdev) +static void __devexit de_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct de_private *de = dev->priv; @@ -2164,7 +2164,7 @@ static struct pci_driver de_driver = { .name = DRV_NAME, .id_table = de_pci_tbl, .probe = de_init_one, - .remove = __exit_p(de_remove_one), + .remove = __devexit_p(de_remove_one), #ifdef CONFIG_PM .suspend = de_suspend, .resume = de_resume, -- GitLab From bbe1fe7ea3438f8c4447dbcd46a126581ed2ed41 Mon Sep 17 00:00:00 2001 From: Eran Tromer Date: Tue, 10 Oct 2006 14:29:25 -0700 Subject: [PATCH 0957/1619] [PATCH] libata: return sense data in HDIO_DRIVE_CMD ioctl Make the HDIO_DRIVE_CMD ioctl in libata (ATA command pass through) return a few ATA registers to userspace, following the same convention as the drivers/ide implementation of the same ioctl. This is needed to support ATA commands like CHECK POWER MODE, which return information in nsectors. This fixes "hdparm -C" on SATA drives. Forcing the sense data read via the cc flag causes spurious check conditions, so we filter these out (following the ATA command pass-through specification T10/04-262r7). Signed-off-by: Eran Tromer Acked-by: Tejun Heo Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 46 +++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b0d0cc41f3e..7af2a4ba499 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -164,10 +164,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) { int rc = 0; u8 scsi_cmd[MAX_COMMAND_SIZE]; - u8 args[4], *argbuf = NULL; + u8 args[4], *argbuf = NULL, *sensebuf = NULL; int argsize = 0; - struct scsi_sense_hdr sshdr; enum dma_data_direction data_dir; + int cmd_result; if (arg == NULL) return -EINVAL; @@ -175,6 +175,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) if (copy_from_user(args, arg, sizeof(args))) return -EFAULT; + sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); + if (!sensebuf) + return -ENOMEM; + memset(scsi_cmd, 0, sizeof(scsi_cmd)); if (args[3]) { @@ -191,7 +195,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) data_dir = DMA_FROM_DEVICE; } else { scsi_cmd[1] = (3 << 1); /* Non-data */ - /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + scsi_cmd[2] = 0x20; /* cc but no off.line or data xfer */ data_dir = DMA_NONE; } @@ -210,18 +214,46 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) /* Good values for timeout and retries? Values below from scsi_ioctl_send_command() for default case... */ - if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize, - &sshdr, (10*HZ), 5)) { + cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize, + sensebuf, (10*HZ), 5, 0); + + if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */ + u8 *desc = sensebuf + 8; + cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ + + /* If we set cc then ATA pass-through will cause a + * check condition even if no error. Filter that. */ + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, + &sshdr); + if (sshdr.sense_key==0 && + sshdr.asc==0 && sshdr.ascq==0) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + + /* Send userspace a few ATA registers (same as drivers/ide) */ + if (sensebuf[0] == 0x72 && /* format is "descriptor" */ + desc[0] == 0x09 ) { /* code is "ATA Descriptor" */ + args[0] = desc[13]; /* status */ + args[1] = desc[3]; /* error */ + args[2] = desc[5]; /* sector count (0:7) */ + if (copy_to_user(arg, args, sizeof(args))) + rc = -EFAULT; + } + } + + + if (cmd_result) { rc = -EIO; goto error; } - /* Need code to retrieve data from check condition? */ - if ((argbuf) && copy_to_user(arg + sizeof(args), argbuf, argsize)) rc = -EFAULT; error: + kfree(sensebuf); kfree(argbuf); return rc; } -- GitLab From a83068bbaca39197dca26287c16186baee615f0a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 04:46:52 -0400 Subject: [PATCH 0958/1619] [libata] sata_promise: add PCI ID Noticed by Steve Brown Signed-off-by: Jeff Garzik --- drivers/ata/sata_promise.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index d636ede064a..1eb0d63c17d 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -260,6 +260,7 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = { #if 0 { PCI_VDEVICE(PROMISE, 0x3570), board_20771 }, #endif + { PCI_VDEVICE(PROMISE, 0x3577), board_20771 }, { } /* terminate list */ }; -- GitLab From 53e36ada37cb8b01cfbf674580a79edc0bb764c7 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 9 Oct 2006 09:53:09 +0200 Subject: [PATCH 0959/1619] [PATCH] pata-qdi: fix le32 in data_xfer The following tiny patch fixes a typo in qdi_data_xfer (le32 instead of le16). Signed-off-by: Peter Korsgaard Signed-off-by: Jeff Garzik --- drivers/ata/pata_qdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 7977f471d5e..2c3cc0ccc60 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -141,7 +141,7 @@ static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned memcpy(&pad, buf + buflen - slop, slop); outl(le32_to_cpu(pad), ap->ioaddr.data_addr); } else { - pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + pad = cpu_to_le32(inl(ap->ioaddr.data_addr)); memcpy(buf + buflen - slop, &pad, slop); } } -- GitLab From 9765d262b8230b735c4b2815b041c09a00833cf1 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 11 Oct 2006 22:29:51 +1000 Subject: [PATCH 0960/1619] [CRYPTO] api: fix crypto_alloc_base() return value This patch makes crypto_alloc_base() return proper return value. - If kzalloc() failure happens within __crypto_alloc_tfm(), crypto_alloc_base() returns NULL. But crypto_alloc_base() is supposed to return error code as pointer. So this patch makes it return -ENOMEM in that case. - crypto_alloc_base() is suppose to return -EINTR, if it is interrupted by signal. But it may not return -EINTR. Signed-off-by: Akinobu Mita Signed-off-by: Herbert Xu --- crypto/api.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crypto/api.c b/crypto/api.c index 2e84d4b5479..4fb7fa45cb0 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -331,7 +331,7 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) - goto out; + goto out_err; tfm->__crt_alg = alg; @@ -355,6 +355,7 @@ cra_init_failed: crypto_exit_ops(tfm); out_free_tfm: kfree(tfm); +out_err: tfm = ERR_PTR(err); out: return tfm; @@ -414,14 +415,14 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) struct crypto_alg *alg; alg = crypto_alg_mod_lookup(alg_name, type, mask); - err = PTR_ERR(alg); - tfm = ERR_PTR(err); - if (IS_ERR(alg)) + if (IS_ERR(alg)) { + err = PTR_ERR(alg); goto err; + } tfm = __crypto_alloc_tfm(alg, 0); if (!IS_ERR(tfm)) - break; + return tfm; crypto_mod_put(alg); err = PTR_ERR(tfm); @@ -433,9 +434,9 @@ err: err = -EINTR; break; } - }; + } - return tfm; + return ERR_PTR(err); } EXPORT_SYMBOL_GPL(crypto_alloc_base); -- GitLab From 9d0a57cbdb4976f382eb1c03baee338e467b6592 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 11 Oct 2006 15:31:26 +0200 Subject: [PATCH 0961/1619] [S390] irq change improvements. Remove the last few places where a pointer to pt_regs gets passed. Also make sure we call set_irq_regs() before irq_enter() and after irq_exit(). This doesn't fix anything but makes sure s390 looks the same like all other architectures. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/appldata/appldata_base.c | 2 +- arch/s390/kernel/s390_ext.c | 4 ++-- arch/s390/kernel/vtime.c | 8 ++++---- drivers/s390/cio/cio.c | 4 ++-- include/asm-s390/timer.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 2b1e6c9a6e0..45c9fa7d754 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -109,7 +109,7 @@ static LIST_HEAD(appldata_ops_list); * * schedule work and reschedule timer */ -static void appldata_timer_function(unsigned long data, struct pt_regs *regs) +static void appldata_timer_function(unsigned long data) { P_DEBUG(" -= Timer =-\n"); P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(), diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index c49ab8c784d..4faf96f8a83 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -117,8 +117,8 @@ void do_extint(struct pt_regs *regs, unsigned short code) int index; struct pt_regs *old_regs; - irq_enter(); old_regs = set_irq_regs(regs); + irq_enter(); asm volatile ("mc 0,0"); if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) /** @@ -134,8 +134,8 @@ void do_extint(struct pt_regs *regs, unsigned short code) p->handler(code); } } - set_irq_regs(old_regs); irq_exit(); + set_irq_regs(old_regs); } EXPORT_SYMBOL(register_external_interrupt); diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 1d7d3938b2b..21baaf5496d 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -209,11 +209,11 @@ static void list_add_sorted(struct vtimer_list *timer, struct list_head *head) * Do the callback functions of expired vtimer events. * Called from within the interrupt handler. */ -static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs) +static void do_callbacks(struct list_head *cb_list) { struct vtimer_queue *vt_list; struct vtimer_list *event, *tmp; - void (*fn)(unsigned long, struct pt_regs*); + void (*fn)(unsigned long); unsigned long data; if (list_empty(cb_list)) @@ -224,7 +224,7 @@ static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs) list_for_each_entry_safe(event, tmp, cb_list, entry) { fn = event->function; data = event->data; - fn(data, regs); + fn(data); if (!event->interval) /* delete one shot timer */ @@ -275,7 +275,7 @@ static void do_cpu_timer_interrupt(__u16 error_code) list_move_tail(&event->entry, &cb_list); } spin_unlock(&vt_list->lock); - do_callbacks(&cb_list, get_irq_regs()); + do_callbacks(&cb_list); /* next event is first in list */ spin_lock(&vt_list->lock); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f18b1623cad..8936e460a80 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -609,8 +609,8 @@ do_IRQ (struct pt_regs *regs) struct irb *irb; struct pt_regs *old_regs; - irq_enter (); old_regs = set_irq_regs(regs); + irq_enter(); asm volatile ("mc 0,0"); if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) /** @@ -655,8 +655,8 @@ do_IRQ (struct pt_regs *regs) * out of the sie which costs more cycles than it saves. */ } while (!MACHINE_IS_VM && tpi (NULL) != 0); + irq_exit(); set_irq_regs(old_regs); - irq_exit (); } #ifdef CONFIG_CCW_CONSOLE diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h index fcd6c256a2d..30e5cbe570f 100644 --- a/include/asm-s390/timer.h +++ b/include/asm-s390/timer.h @@ -26,7 +26,7 @@ struct vtimer_list { spinlock_t lock; unsigned long magic; - void (*function)(unsigned long, struct pt_regs*); + void (*function)(unsigned long); unsigned long data; }; -- GitLab From 08983787d2ccab64cb790965ba89621d96cc22c1 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 11 Oct 2006 15:31:30 +0200 Subject: [PATCH 0962/1619] [S390] cio: add missing KERN_INFO printk header. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index b67620208f3..c36d8b6fdb0 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -885,7 +885,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) /* Basic sense hasn't started. Try again. */ ccw_device_do_sense(cdev, irb); else { - printk("Huh? %s(%s): unsolicited interrupt...\n", + printk(KERN_INFO "Huh? %s(%s): unsolicited " + "interrupt...\n", __FUNCTION__, cdev->dev.bus_id); if (cdev->handler) cdev->handler (cdev, 0, irb); -- GitLab From 715d854bc215bbcca35097176d674c3ac58a085c Mon Sep 17 00:00:00 2001 From: Melissa Howland Date: Wed, 11 Oct 2006 15:31:34 +0200 Subject: [PATCH 0963/1619] [S390] monwriter kzalloc size. Fix length on kzalloc for data buffer so as to not overwrite unallocated storage. Signed-off-by: Melissa Howland Signed-off-by: Martin Schwidefsky --- drivers/s390/char/monwriter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 4362ff26024..abd02ed501c 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -110,7 +110,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL); if (!monbuf) return -ENOMEM; - monbuf->data = kzalloc(monbuf->hdr.datalen, + monbuf->data = kzalloc(monhdr->datalen, GFP_KERNEL | GFP_DMA); if (!monbuf->data) { kfree(monbuf); -- GitLab From 789642680518b28e7dc13f96061460a8238ec622 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 11 Oct 2006 15:31:38 +0200 Subject: [PATCH 0964/1619] [S390] cio: Use ccw_dev_id and subchannel_id in ccw_device_private Use the proper structures to identify device and subchannel. Change get_disc_ccwdev_by_devno() to get_disc_ccwdev_by_dev_id(). Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.h | 5 ++--- drivers/s390/cio/device.c | 32 +++++++++++++++----------------- drivers/s390/cio/device_fsm.c | 14 ++++++++------ drivers/s390/cio/device_id.c | 14 ++++++++------ drivers/s390/cio/device_ops.c | 4 ++-- drivers/s390/cio/device_pgid.c | 23 +++++++++++++---------- drivers/s390/cio/device_status.c | 7 +++---- drivers/s390/cio/qdio.c | 10 +++++----- include/asm-s390/cio.h | 6 ++++++ 9 files changed, 62 insertions(+), 53 deletions(-) diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 8aabb4adeb5..15bd1e28ed7 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -76,9 +76,8 @@ struct ccw_device_private { int state; /* device state */ atomic_t onoff; unsigned long registered; - __u16 devno; /* device number */ - __u16 sch_no; /* subchannel number */ - __u8 ssid; /* subchannel set id */ + struct ccw_dev_id dev_id; /* device id */ + struct subchannel_id schid; /* subchannel number */ __u8 imask; /* lpm mask for SNID/SID/SPGID */ int iretry; /* retry counter SNID/SID/SPGID */ struct { diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 688945662c1..7646a9930ec 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -552,21 +552,19 @@ ccw_device_register(struct ccw_device *cdev) } struct match_data { - unsigned int devno; - unsigned int ssid; + struct ccw_dev_id dev_id; struct ccw_device * sibling; }; static int match_devno(struct device * dev, void * data) { - struct match_data * d = (struct match_data *)data; + struct match_data * d = data; struct ccw_device * cdev; cdev = to_ccwdev(dev); if ((cdev->private->state == DEV_STATE_DISCONNECTED) && - (cdev->private->devno == d->devno) && - (cdev->private->ssid == d->ssid) && + ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) && (cdev != d->sibling)) { cdev->private->state = DEV_STATE_NOT_OPER; return 1; @@ -574,15 +572,13 @@ match_devno(struct device * dev, void * data) return 0; } -static struct ccw_device * -get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid, - struct ccw_device *sibling) +static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id, + struct ccw_device *sibling) { struct device *dev; struct match_data data; - data.devno = devno; - data.ssid = ssid; + data.dev_id = *dev_id; data.sibling = sibling; dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno); @@ -618,7 +614,7 @@ ccw_device_do_unreg_rereg(void *data) cdev = (struct ccw_device *)data; sch = to_subchannel(cdev->dev.parent); - if (cdev->private->devno != sch->schib.pmcw.dev) { + if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) { /* * The device number has changed. This is usually only when * a device has been detached under VM and then re-appeared @@ -633,10 +629,12 @@ ccw_device_do_unreg_rereg(void *data) * get possibly sick... */ struct ccw_device *other_cdev; + struct ccw_dev_id dev_id; need_rename = 1; - other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev, - sch->schid.ssid, cdev); + dev_id.devno = sch->schib.pmcw.dev; + dev_id.ssid = sch->schid.ssid; + other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev); if (other_cdev) { struct subchannel *other_sch; @@ -652,7 +650,7 @@ ccw_device_do_unreg_rereg(void *data) } /* Update ssd info here. */ css_get_ssd_info(sch); - cdev->private->devno = sch->schib.pmcw.dev; + cdev->private->dev_id.devno = sch->schib.pmcw.dev; } else need_rename = 0; device_remove_files(&cdev->dev); @@ -792,9 +790,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) /* Init private data. */ priv = cdev->private; - priv->devno = sch->schib.pmcw.dev; - priv->ssid = sch->schid.ssid; - priv->sch_no = sch->schid.sch_no; + priv->dev_id.devno = sch->schib.pmcw.dev; + priv->dev_id.ssid = sch->schid.ssid; + priv->schid = sch->schid; priv->state = DEV_STATE_NOT_OPER; INIT_LIST_HEAD(&priv->cmb_list); init_waitqueue_head(&priv->wait_q); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index c36d8b6fdb0..392eb33f3a9 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -183,7 +183,7 @@ ccw_device_handle_oper(struct ccw_device *cdev) cdev->id.cu_model != cdev->private->senseid.cu_model || cdev->id.dev_type != cdev->private->senseid.dev_type || cdev->id.dev_model != cdev->private->senseid.dev_model || - cdev->private->devno != sch->schib.pmcw.dev) { + cdev->private->dev_id.devno != sch->schib.pmcw.dev) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unreg_rereg, (void *)cdev); queue_work(ccw_device_work, &cdev->private->kick_work); @@ -255,7 +255,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) case DEV_STATE_NOT_OPER: CIO_DEBUG(KERN_WARNING, 2, "SenseID : unknown device %04x on subchannel " - "0.%x.%04x\n", cdev->private->devno, + "0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: @@ -282,14 +282,15 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: " "CU Type/Mod = %04X/%02X, Dev Type/Mod = " "%04X/%02X\n", - cdev->private->ssid, cdev->private->devno, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, cdev->id.cu_type, cdev->id.cu_model, cdev->id.dev_type, cdev->id.dev_model); break; case DEV_STATE_BOXED: CIO_DEBUG(KERN_WARNING, 2, "SenseID : boxed device %04x on subchannel " - "0.%x.%04x\n", cdev->private->devno, + "0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); break; } @@ -363,7 +364,7 @@ ccw_device_done(struct ccw_device *cdev, int state) if (state == DEV_STATE_BOXED) CIO_DEBUG(KERN_WARNING, 2, "Boxed device %04x on subchannel %04x\n", - cdev->private->devno, sch->schid.sch_no); + cdev->private->dev_id.devno, sch->schid.sch_no); if (cdev->private->flags.donotify) { cdev->private->flags.donotify = 0; @@ -412,7 +413,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev) /* PGID mismatch, can't pathgroup. */ CIO_MSG_EVENT(0, "SNID - pgid mismatch for device " "0.%x.%04x, can't pathgroup\n", - cdev->private->ssid, cdev->private->devno); + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); cdev->private->options.pgroup = 0; return; } diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 1398367b5f6..a74785b9e4e 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -251,7 +251,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) */ CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel " "0.%x.%04x reports cmd reject\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); return -EOPNOTSUPP; } @@ -259,7 +259,8 @@ ccw_device_check_sense_id(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, " "lpum %02X, cnt %02d, sns :" " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - cdev->private->ssid, cdev->private->devno, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, irb->esw.esw0.sublog.lpum, irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], @@ -274,14 +275,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x " "on subchannel 0.%x.%04x is " "'not operational'\n", sch->orb.lpm, - cdev->private->devno, sch->schid.ssid, - sch->schid.sch_no); + cdev->private->dev_id.devno, + sch->schid.ssid, sch->schid.sch_no); return -EACCES; } /* Hmm, whatever happened, try again. */ CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " "subchannel 0.%x.%04x returns status %02X%02X\n", - cdev->private->devno, sch->schid.ssid, sch->schid.sch_no, + cdev->private->dev_id.devno, sch->schid.ssid, + sch->schid.sch_no, irb->scsw.dstat, irb->scsw.cstat); return -EAGAIN; } @@ -330,7 +332,7 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) /* fall through. */ default: /* Sense ID failed. Try asking VM. */ if (MACHINE_IS_VM) { - VM_virtual_device_info (cdev->private->devno, + VM_virtual_device_info (cdev->private->dev_id.devno, &cdev->private->senseid); if (cdev->private->senseid.cu_type != 0xFFFF) { /* Got the device information from VM. */ diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 84b9b18eabc..96219935a06 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -592,13 +592,13 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) int _ccw_device_get_subchannel_number(struct ccw_device *cdev) { - return cdev->private->sch_no; + return cdev->private->schid.sch_no; } int _ccw_device_get_device_number(struct ccw_device *cdev) { - return cdev->private->devno; + return cdev->private->dev_id.devno; } diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 84917b39de4..2975ce888c1 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -79,7 +79,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not " "operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, + sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); } @@ -135,7 +136,8 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, " "lpum %02X, cnt %02d, sns : " "%02X%02X%02X%02X %02X%02X%02X%02X ...\n", - cdev->private->ssid, cdev->private->devno, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, irb->esw.esw0.sublog.lpum, irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], @@ -147,7 +149,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, sch->orb.lpm); return -EACCES; } @@ -155,7 +157,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x " "is reserved by someone else\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); return -EUSERS; } @@ -261,7 +263,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) /* PGID command failed on this path. */ CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return ret; } @@ -301,7 +303,7 @@ static int __ccw_device_do_nop(struct ccw_device *cdev) /* nop command failed on this path. */ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return ret; } @@ -328,8 +330,9 @@ __ccw_device_check_pgid(struct ccw_device *cdev) CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, " "cnt %02d, " "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - cdev->private->ssid, - cdev->private->devno, irb->esw.esw0.erw.scnt, + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, + irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], irb->ecw[2], irb->ecw[3], irb->ecw[4], irb->ecw[5], @@ -339,7 +342,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return -EACCES; } @@ -362,7 +365,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", - cdev->private->devno, sch->schid.ssid, + cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return -EACCES; } diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index caf148d5caa..3f7cbce4cd8 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -32,19 +32,18 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) return; - CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " "received" " ... device %04x on subchannel 0.%x.%04x, dev_stat " ": %02X sch_stat : %02X\n", - cdev->private->devno, cdev->private->ssid, - cdev->private->sch_no, + cdev->private->dev_id.devno, cdev->private->schid.ssid, + cdev->private->schid.sch_no, irb->scsw.dstat, irb->scsw.cstat); if (irb->scsw.cc != 3) { char dbf_text[15]; - sprintf(dbf_text, "chk%x", cdev->private->sch_no); + sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, irb, sizeof (struct irb)); } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index cde822d8b5c..0648ce5bb68 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1741,7 +1741,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, void *ptr; int available; - sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no); + sprintf(dbf_text,"qfqs%4x",cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); for (i=0;iinput_qs[i]; @@ -2924,7 +2924,7 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) irq_ptr = cdev->private->qdio_data; - sprintf(dbf_text,"qehi%4x",cdev->private->sch_no); + sprintf(dbf_text,"qehi%4x",cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); @@ -2943,7 +2943,7 @@ qdio_initialize(struct qdio_initialize *init_data) int rc; char dbf_text[15]; - sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no); + sprintf(dbf_text,"qini%4x",init_data->cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); @@ -2964,7 +2964,7 @@ qdio_allocate(struct qdio_initialize *init_data) struct qdio_irq *irq_ptr; char dbf_text[15]; - sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no); + sprintf(dbf_text,"qalc%4x",init_data->cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) || @@ -3187,7 +3187,7 @@ qdio_establish(struct qdio_initialize *init_data) tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET); } - sprintf(dbf_text,"qest%4x",cdev->private->sch_no); + sprintf(dbf_text,"qest%4x",cdev->private->schid.sch_no); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index da063cd5f0a..81287d86329 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h @@ -275,6 +275,12 @@ struct ccw_dev_id { u16 devno; }; +static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, + struct ccw_dev_id *dev_id2) +{ + return !memcmp(dev_id1, dev_id2, sizeof(struct ccw_dev_id)); +} + extern int diag210(struct diag210 *addr); extern void wait_cons_dev(void); -- GitLab From e7769b48a0216d7262fe2ba59b1b3697be462cbb Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 11 Oct 2006 15:31:41 +0200 Subject: [PATCH 0965/1619] [S390] cio: Remove grace period for vary off chpid. The grace period handling introduced needless complexity. It didn't help the dasd driver (which can handle terminated I/O just well), and it doesn't help for long running channel programs (which won't complete during the grace period anyway). Terminating I/O using a path that just disappeared immediately is much more consistent with what the user expects. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 17 ++++----- drivers/s390/cio/css.h | 2 +- drivers/s390/cio/device.h | 1 - drivers/s390/cio/device_fsm.c | 68 ++++------------------------------- drivers/s390/cio/device_ops.c | 2 -- 5 files changed, 14 insertions(+), 76 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 07c7f19339d..eabe018d348 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -707,8 +707,7 @@ chp_process_crw(int chpid, int on) return chp_add(chpid); } -static inline int -__check_for_io_and_kill(struct subchannel *sch, int index) +static inline int check_for_io_on_path(struct subchannel *sch, int index) { int cc; @@ -718,10 +717,8 @@ __check_for_io_and_kill(struct subchannel *sch, int index) cc = stsch(sch->schid, &sch->schib); if (cc) return 0; - if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) { - device_set_waiting(sch); + if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) return 1; - } return 0; } @@ -750,12 +747,10 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) } else { sch->opm &= ~(0x80 >> chp); sch->lpm &= ~(0x80 >> chp); - /* - * Give running I/O a grace period in which it - * can successfully terminate, even using the - * just varied off path. Then kill it. - */ - if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) { + if (check_for_io_on_path(sch, chp)) + /* Path verification is done after killing. */ + device_kill_io(sch); + else if (!sch->lpm) { if (css_enqueue_subchannel_slow(sch->schid)) { css_clear_subchannel_slow_list(); need_rescan = 1; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 15bd1e28ed7..4c2ff833628 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -170,7 +170,7 @@ void device_trigger_reprobe(struct subchannel *); /* Helper functions for vary on/off. */ int device_is_online(struct subchannel *); -void device_set_waiting(struct subchannel *); +void device_kill_io(struct subchannel *); /* Machine check helper function. */ void device_kill_pending_timer(struct subchannel *); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 00be9a5b4ac..c6140cc97a8 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -21,7 +21,6 @@ enum dev_state { /* states to wait for i/o completion before doing something */ DEV_STATE_CLEAR_VERIFY, DEV_STATE_TIMEOUT_KILL, - DEV_STATE_WAIT4IO, DEV_STATE_QUIESCE, /* special states for devices gone not operational */ DEV_STATE_DISCONNECTED, diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 392eb33f3a9..44e4a53c598 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -59,18 +59,6 @@ device_set_disconnected(struct subchannel *sch) cdev->private->state = DEV_STATE_DISCONNECTED; } -void -device_set_waiting(struct subchannel *sch) -{ - struct ccw_device *cdev; - - if (!sch->dev.driver_data) - return; - cdev = sch->dev.driver_data; - ccw_device_set_timeout(cdev, 10*HZ); - cdev->private->state = DEV_STATE_WAIT4IO; -} - /* * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. */ @@ -947,7 +935,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-ETIMEDOUT)); + ERR_PTR(-EIO)); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_nopath_notify, (void *)cdev); @@ -984,51 +972,15 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-ETIMEDOUT)); + ERR_PTR(-EIO)); } -static void -ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event) -{ - struct irb *irb; - struct subchannel *sch; - - irb = (struct irb *) __LC_IRB; - /* - * Accumulate status and find out if a basic sense is needed. - * This is fine since we have already adapted the lpm. - */ - ccw_device_accumulate_irb(cdev, irb); - if (cdev->private->flags.dosense) { - if (ccw_device_do_sense(cdev, irb) == 0) { - cdev->private->state = DEV_STATE_W4SENSE; - } - return; - } - - /* Iff device is idle, reset timeout. */ - sch = to_subchannel(cdev->dev.parent); - if (!stsch(sch->schid, &sch->schib)) - if (sch->schib.scsw.actl == 0) - ccw_device_set_timeout(cdev, 0); - /* Call the handler. */ - ccw_device_call_handler(cdev); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); - queue_work(ccw_device_notify_work, &cdev->private->kick_work); - } else if (cdev->private->flags.doverify) - ccw_device_online_verify(cdev, 0); -} - -static void -ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event) +void device_kill_io(struct subchannel *sch) { int ret; - struct subchannel *sch; + struct ccw_device *cdev; - sch = to_subchannel(cdev->dev.parent); - ccw_device_set_timeout(cdev, 0); + cdev = sch->dev.driver_data; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -1047,12 +999,12 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event) } if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-ETIMEDOUT)); + ERR_PTR(-EIO)); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_nopath_notify, (void *)cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); - } else if (cdev->private->flags.doverify) + } else /* Start delayed path verification. */ ccw_device_online_verify(cdev, 0); } @@ -1289,12 +1241,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME }, - [DEV_STATE_WAIT4IO] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout, - [DEV_EVENT_VERIFY] = ccw_device_delay_verify, - }, [DEV_STATE_QUIESCE] = { [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done, [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done, diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 96219935a06..b39c1fa48ac 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -50,7 +50,6 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && - cdev->private->state != DEV_STATE_WAIT4IO && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; sch = to_subchannel(cdev->dev.parent); @@ -155,7 +154,6 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && - cdev->private->state != DEV_STATE_WAIT4IO && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; sch = to_subchannel(cdev->dev.parent); -- GitLab From 12975aef62836e9f3e179afaaded8045f8a25ac4 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 11 Oct 2006 15:31:47 +0200 Subject: [PATCH 0966/1619] [S390] cio: remove casts from/to (void *). Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 6 +++--- drivers/s390/cio/css.c | 2 +- drivers/s390/cio/device.c | 16 ++++++++-------- drivers/s390/cio/device_fsm.c | 28 ++++++++++++++-------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index eabe018d348..2d78f0f4a40 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -370,7 +370,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) struct res_acc_data *res_data; struct subchannel *sch; - res_data = (struct res_acc_data *)data; + res_data = data; sch = get_subchannel_by_schid(schid); if (!sch) /* Check if a subchannel is newly available. */ @@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data) u32 isinfo[28]; } *lir; - lir = (struct lir*) data; + lir = data; if (!(lir->iq&0x80)) /* NULL link incident record */ return -EINVAL; @@ -628,7 +628,7 @@ __chp_add(struct subchannel_id schid, void *data) struct channel_path *chp; struct subchannel *sch; - chp = (struct channel_path *)data; + chp = data; sch = get_subchannel_by_schid(schid); if (!sch) /* Check if the subchannel is now available. */ diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 7086a74e987..a2dee5bf5a1 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -177,7 +177,7 @@ get_subchannel_by_schid(struct subchannel_id schid) struct device *dev; dev = bus_find_device(&css_bus_type, NULL, - (void *)&schid, check_subchannel); + &schid, check_subchannel); return dev ? to_subchannel(dev) : NULL; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7646a9930ec..94bdd4d8a4c 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -591,7 +591,7 @@ ccw_device_add_changed(void *data) struct ccw_device *cdev; - cdev = (struct ccw_device *)data; + cdev = data; if (device_add(&cdev->dev)) { put_device(&cdev->dev); return; @@ -612,7 +612,7 @@ ccw_device_do_unreg_rereg(void *data) struct subchannel *sch; int need_rename; - cdev = (struct ccw_device *)data; + cdev = data; sch = to_subchannel(cdev->dev.parent); if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) { /* @@ -660,7 +660,7 @@ ccw_device_do_unreg_rereg(void *data) snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", sch->schid.ssid, sch->schib.pmcw.dev); PREPARE_WORK(&cdev->private->kick_work, - ccw_device_add_changed, (void *)cdev); + ccw_device_add_changed, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } @@ -685,7 +685,7 @@ io_subchannel_register(void *data) int ret; unsigned long flags; - cdev = (struct ccw_device *) data; + cdev = data; sch = to_subchannel(cdev->dev.parent); if (klist_node_attached(&cdev->dev.knode_parent)) { @@ -757,7 +757,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) break; sch = to_subchannel(cdev->dev.parent); PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister, (void *) cdev); + ccw_device_call_sch_unregister, cdev); queue_work(slow_path_wq, &cdev->private->kick_work); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); @@ -772,7 +772,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) if (!get_device(&cdev->dev)) break; PREPARE_WORK(&cdev->private->kick_work, - io_subchannel_register, (void *) cdev); + io_subchannel_register, cdev); queue_work(slow_path_wq, &cdev->private->kick_work); break; } @@ -910,7 +910,7 @@ io_subchannel_remove (struct subchannel *sch) */ if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_unregister, (void *) cdev); + ccw_device_unregister, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } return 0; @@ -1053,7 +1053,7 @@ __ccwdev_check_busid(struct device *dev, void *id) { char *bus_id; - bus_id = (char *)id; + bus_id = id; return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0); } diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 44e4a53c598..fcaf28d7b4e 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -173,7 +173,7 @@ ccw_device_handle_oper(struct ccw_device *cdev) cdev->id.dev_model != cdev->private->senseid.dev_model || cdev->private->dev_id.devno != sch->schib.pmcw.dev) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_do_unreg_rereg, (void *)cdev); + ccw_device_do_unreg_rereg, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); return 0; } @@ -314,13 +314,13 @@ ccw_device_oper_notify(void *data) struct subchannel *sch; int ret; - cdev = (struct ccw_device *)data; + cdev = data; sch = to_subchannel(cdev->dev.parent); ret = (sch->driver && sch->driver->notify) ? sch->driver->notify(&sch->dev, CIO_OPER) : 0; if (!ret) /* Driver doesn't want device back. */ - ccw_device_do_unreg_rereg((void *)cdev); + ccw_device_do_unreg_rereg(cdev); else { /* Reenable channel measurements, if needed. */ cmf_reenable(cdev); @@ -357,7 +357,7 @@ ccw_device_done(struct ccw_device *cdev, int state) if (cdev->private->flags.donotify) { cdev->private->flags.donotify = 0; PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify, - (void *)cdev); + cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } wake_up(&cdev->private->wait_q); @@ -513,7 +513,7 @@ ccw_device_nopath_notify(void *data) struct subchannel *sch; int ret; - cdev = (struct ccw_device *)data; + cdev = data; sch = to_subchannel(cdev->dev.parent); /* Extra sanity. */ if (sch->lpm) @@ -527,7 +527,7 @@ ccw_device_nopath_notify(void *data) if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister, - (void *)cdev); + cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } else @@ -582,7 +582,7 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) break; default: PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; @@ -713,7 +713,7 @@ ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister, (void *)cdev); + ccw_device_call_sch_unregister, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } wake_up(&cdev->private->wait_q); @@ -744,7 +744,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) } if (get_device(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister, (void *)cdev); + ccw_device_call_sch_unregister, cdev); queue_work(ccw_device_work, &cdev->private->kick_work); } wake_up(&cdev->private->wait_q); @@ -849,7 +849,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else @@ -938,7 +938,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) ERR_PTR(-EIO)); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else if (cdev->private->flags.doverify) /* Start delayed path verification. */ @@ -961,7 +961,7 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else @@ -990,7 +990,7 @@ void device_kill_io(struct subchannel *sch) if (ret == -ENODEV) { if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else @@ -1002,7 +1002,7 @@ void device_kill_io(struct subchannel *sch) ERR_PTR(-EIO)); if (!sch->lpm) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify, (void *)cdev); + ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); } else /* Start delayed path verification. */ -- GitLab From 75e9de18f079a51fa987ef0703112d5bc125fdb7 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 11 Oct 2006 15:31:52 +0200 Subject: [PATCH 0967/1619] [S390] stacktrace bug. The latest kernel 2.6.19-rc1 triggers a bug in the s390 specific stack trace code when compiled with gcc 3.4. This patch fixes the latest lock dependency validator code (2.6.19-rc1) on s390 gcc 3.4. The variable sp was fixed to r15 (which is the stack pointer in the s390 abi) and assigned new values to r15. Therefore, gcc 3.4 assigns a new value to r15 and does not restore it on exit (r15 is supposed to be call save) - the kernel stack is broken. Avoid trouble by not assigning any new value to sp (r15). Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/stacktrace.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index d9428a0fc8f..0d14a4789bf 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -62,27 +62,26 @@ static inline unsigned long save_context_stack(struct stack_trace *trace, void save_stack_trace(struct stack_trace *trace, struct task_struct *task) { register unsigned long sp asm ("15"); - unsigned long orig_sp; + unsigned long orig_sp, new_sp; - sp &= PSW_ADDR_INSN; - orig_sp = sp; + orig_sp = sp & PSW_ADDR_INSN; - sp = save_context_stack(trace, &trace->skip, sp, + new_sp = save_context_stack(trace, &trace->skip, orig_sp, S390_lowcore.panic_stack - PAGE_SIZE, S390_lowcore.panic_stack); - if ((sp != orig_sp) && !trace->all_contexts) + if ((new_sp != orig_sp) && !trace->all_contexts) return; - sp = save_context_stack(trace, &trace->skip, sp, + new_sp = save_context_stack(trace, &trace->skip, new_sp, S390_lowcore.async_stack - ASYNC_SIZE, S390_lowcore.async_stack); - if ((sp != orig_sp) && !trace->all_contexts) + if ((new_sp != orig_sp) && !trace->all_contexts) return; if (task) - save_context_stack(trace, &trace->skip, sp, + save_context_stack(trace, &trace->skip, new_sp, (unsigned long) task_stack_page(task), (unsigned long) task_stack_page(task) + THREAD_SIZE); else - save_context_stack(trace, &trace->skip, sp, + save_context_stack(trace, &trace->skip, new_sp, S390_lowcore.thread_info, S390_lowcore.thread_info + THREAD_SIZE); return; -- GitLab From 7e491092e442b3f8c0d90d470b398fdb74703ec7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:20:35 -0700 Subject: [PATCH 0968/1619] [PATCH] revert "nvidiafb: use generic ddc reading" Olaf reports that this gave him a black screen. Cc: Olaf Hering Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/Kconfig | 1 - drivers/video/nvidia/nv_i2c.c | 45 ++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index daaa486159c..7a43020fa58 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -701,7 +701,6 @@ config FB_NVIDIA depends on FB && PCI select I2C_ALGOBIT if FB_NVIDIA_I2C select I2C if FB_NVIDIA_I2C - select FB_DDC if FB_NVIDIA_I2C select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index e48de3c9fd1..19eef3a0902 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -160,12 +160,51 @@ void nvidia_delete_i2c_busses(struct nvidia_par *par) } +static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .len = 1, + .buf = &start, + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + if (!chan->par) + return NULL; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) { struct nvidia_par *par = info->par; - u8 *edid; - - edid = fb_ddc_read(&par->chan[conn - 1].adapter); + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]); + if (edid) + break; + } if (!edid && conn == 1) { /* try to get from firmware */ -- GitLab From 41716c7c21b15e7ecf14f0caf1eef3980707fb74 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Wed, 11 Oct 2006 01:20:37 -0700 Subject: [PATCH 0969/1619] [PATCH] null dereference in fs/jbd/journal.c Since commit d1807793e1e7e502e3dc047115e9dbc3b50e4534 we dereference a NULL pointer. Coverity id #1432. We set journal to NULL, and use it directly afterwards. Signed-off-by: Eric Sesterhenn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/journal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index c518dd8fe60..b85c686b60d 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -725,6 +725,7 @@ journal_t * journal_init_dev(struct block_device *bdev, __FUNCTION__); kfree(journal); journal = NULL; + goto out; } journal->j_dev = bdev; journal->j_fs_dev = fs_dev; @@ -735,7 +736,7 @@ journal_t * journal_init_dev(struct block_device *bdev, J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; - +out: return journal; } -- GitLab From 4e0fadfcf62e252d2b14de0e0927eb2830c0c28c Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 11 Oct 2006 01:20:37 -0700 Subject: [PATCH 0970/1619] [PATCH] IRQ: Fix AVR32 breakage Make the necessary changes to AVR32 required by the irq regs stuff. Signed-off-by: Haavard Skinnemoen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/avr32/kernel/time.c | 10 +++++----- arch/avr32/mach-at32ap/extint.c | 5 ++--- arch/avr32/mach-at32ap/intc.c | 7 ++++++- include/asm-avr32/irq_regs.h | 1 + 4 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 include/asm-avr32/irq_regs.h diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c index 3e56b9f4358..5a247ba71a7 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -124,15 +124,15 @@ unsigned long long sched_clock(void) * * In UP mode, it is invoked from the (global) timer_interrupt. */ -static void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static 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())); } static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +timer_interrupt(int irq, void *dev_id) { unsigned int count; @@ -157,7 +157,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * * SMP is not supported yet. */ - local_timer_interrupt(irq, dev_id, regs); + local_timer_interrupt(irq, dev_id); return IRQ_HANDLED; } diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index 7da9c5f7a0e..4dff1f98890 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -102,8 +102,7 @@ struct irq_chip eim_chip = { .set_type = eim_set_irq_type, }; -static void demux_eim_irq(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void demux_eim_irq(unsigned int irq, struct irq_desc *desc) { struct at32_sm *sm = desc->handler_data; struct irq_desc *ext_desc; @@ -121,7 +120,7 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc, ext_irq = i + sm->eim_first_irq; ext_desc = irq_desc + ext_irq; - ext_desc->handle_irq(ext_irq, ext_desc, regs); + ext_desc->handle_irq(ext_irq, ext_desc); } spin_unlock(&sm->lock); diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c index 74f8c9f2f03..eb87a18ad7b 100644 --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c @@ -52,16 +52,19 @@ static struct intc intc0 = { asmlinkage void do_IRQ(int level, struct pt_regs *regs) { struct irq_desc *desc; + struct pt_regs *old_regs; unsigned int irq; unsigned long status_reg; local_irq_disable(); + old_regs = set_irq_regs(regs); + irq_enter(); irq = intc_readl(&intc0, INTCAUSE0 - 4 * level); desc = irq_desc + irq; - desc->handle_irq(irq, desc, regs); + desc->handle_irq(irq, desc); /* * Clear all interrupt level masks so that we may handle @@ -75,6 +78,8 @@ asmlinkage void do_IRQ(int level, struct pt_regs *regs) sysreg_write(SR, status_reg); irq_exit(); + + set_irq_regs(old_regs); } void __init init_IRQ(void) diff --git a/include/asm-avr32/irq_regs.h b/include/asm-avr32/irq_regs.h new file mode 100644 index 00000000000..3dd9c0b7027 --- /dev/null +++ b/include/asm-avr32/irq_regs.h @@ -0,0 +1 @@ +#include -- GitLab From 6391af174ad75f72e92043c1dd8302660a2fec58 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 11 Oct 2006 01:20:39 -0700 Subject: [PATCH 0971/1619] [PATCH] mm: use symbolic names instead of indices for zone initialisation Arch-independent zone-sizing is using indices instead of symbolic names to offset within an array related to zones (max_zone_pfns). The unintended impact is that ZONE_DMA and ZONE_NORMAL is initialised on powerpc instead of ZONE_DMA and ZONE_HIGHMEM when CONFIG_HIGHMEM is set. As a result, the the machine fails to boot but will boot with CONFIG_HIGHMEM turned off. The following patch properly initialises the max_zone_pfns[] array and uses symbolic names instead of indices in each architecture using arch-independent zone-sizing. Two users have successfully booted their powerpcs with it (one an ibook G4). It has also been boot tested on x86, x86_64, ppc64 and ia64. Please merge for 2.6.19-rc2. Credit to Benjamin Herrenschmidt for identifying the bug and rolling the first fix. Additional credit to Johannes Berg and Andreas Schwab for reporting the problem and testing on powerpc. Signed-off-by: Mel Gorman Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/setup.c | 13 ++++++------- arch/i386/mm/discontig.c | 11 ++++++----- arch/ia64/mm/contig.c | 1 + arch/ia64/mm/discontig.c | 1 + arch/powerpc/mm/mem.c | 7 ++++--- arch/powerpc/mm/numa.c | 6 +++--- arch/ppc/mm/init.c | 7 ++++--- arch/x86_64/mm/init.c | 9 ++++++--- arch/x86_64/mm/numa.c | 8 +++++--- 9 files changed, 36 insertions(+), 27 deletions(-) diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 000cf03751f..519e63c3c13 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1083,16 +1083,15 @@ static unsigned long __init setup_memory(void) void __init zone_sizes_init(void) { + unsigned long max_zone_pfns[MAX_NR_ZONES]; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = + virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; #ifdef CONFIG_HIGHMEM - unsigned long max_zone_pfns[MAX_NR_ZONES] = { - virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT, - max_low_pfn, - highend_pfn}; + max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; add_active_range(0, 0, highend_pfn); #else - unsigned long max_zone_pfns[MAX_NR_ZONES] = { - virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT, - max_low_pfn}; add_active_range(0, 0, max_low_pfn); #endif diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c index 455597db84d..ddbdb0336f2 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c @@ -356,11 +356,12 @@ void __init numa_kva_reserve(void) void __init zone_sizes_init(void) { int nid; - unsigned long max_zone_pfns[MAX_NR_ZONES] = { - virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT, - max_low_pfn, - highend_pfn - }; + unsigned long max_zone_pfns[MAX_NR_ZONES]; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = + virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; /* If SRAT has not registered memory, register it now */ if (find_max_pfn_with_active_regions() == 0) { diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index daf977ff292..82deaa3a7c4 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -233,6 +233,7 @@ paging_init (void) efi_memmap_walk(count_pages, &num_physpages); max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); max_zone_pfns[ZONE_DMA] = max_dma; max_zone_pfns[ZONE_NORMAL] = max_low_pfn; diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index d497b6b0f5b..96722cb1b49 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -709,6 +709,7 @@ void __init paging_init(void) max_pfn = mem_data[node].max_pfn; } + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); max_zone_pfns[ZONE_DMA] = max_dma; max_zone_pfns[ZONE_NORMAL] = max_pfn; free_area_init_nodes(max_zone_pfns); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 16fe027bbc1..d1c0758c561 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -307,11 +307,12 @@ void __init paging_init(void) top_of_ram, total_ram); printk(KERN_DEBUG "Memory hole size: %ldMB\n", (top_of_ram - total_ram) >> 20); + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); #ifdef CONFIG_HIGHMEM - max_zone_pfns[0] = total_lowmem >> PAGE_SHIFT; - max_zone_pfns[1] = top_of_ram >> PAGE_SHIFT; + max_zone_pfns[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; + max_zone_pfns[ZONE_HIGHMEM] = top_of_ram >> PAGE_SHIFT; #else - max_zone_pfns[0] = top_of_ram >> PAGE_SHIFT; + max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; #endif free_area_init_nodes(max_zone_pfns); } diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 43c272075e1..9da01dc8cfd 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -617,9 +617,9 @@ void __init do_init_bootmem(void) void __init paging_init(void) { - unsigned long max_zone_pfns[MAX_NR_ZONES] = { - lmb_end_of_DRAM() >> PAGE_SHIFT - }; + unsigned long max_zone_pfns[MAX_NR_ZONES]; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = lmb_end_of_DRAM() >> PAGE_SHIFT; free_area_init_nodes(max_zone_pfns); } diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 410200046af..c374e53ae03 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -374,11 +374,12 @@ void __init paging_init(void) end_pfn = start_pfn + (total_memory >> PAGE_SHIFT); add_active_range(0, start_pfn, end_pfn); + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); #ifdef CONFIG_HIGHMEM - max_zone_pfns[0] = total_lowmem >> PAGE_SHIFT; - max_zone_pfns[1] = total_memory >> PAGE_SHIFT; + max_zone_pfns[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; + max_zone_pfns[ZONE_HIGHMEM] = total_memory >> PAGE_SHIFT; #else - max_zone_pfns[0] = total_memory >> PAGE_SHIFT; + max_zone_pfns[ZONE_DMA] = total_memory >> PAGE_SHIFT; #endif /* CONFIG_HIGHMEM */ free_area_init_nodes(max_zone_pfns); } diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 19c72520a86..971dc1181e6 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -406,9 +406,12 @@ void __cpuinit zap_low_mappings(int cpu) #ifndef CONFIG_NUMA void __init paging_init(void) { - unsigned long max_zone_pfns[MAX_NR_ZONES] = {MAX_DMA_PFN, - MAX_DMA32_PFN, - end_pfn}; + unsigned long max_zone_pfns[MAX_NR_ZONES]; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; + max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; + max_zone_pfns[ZONE_NORMAL] = end_pfn; + memory_present(0, 0, end_pfn); sparse_init(); free_area_init_nodes(max_zone_pfns); diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 829a008bd39..2ee2e003606 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -338,9 +338,11 @@ static void __init arch_sparse_init(void) void __init paging_init(void) { int i; - unsigned long max_zone_pfns[MAX_NR_ZONES] = { MAX_DMA_PFN, - MAX_DMA32_PFN, - end_pfn}; + unsigned long max_zone_pfns[MAX_NR_ZONES]; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; + max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; + max_zone_pfns[ZONE_NORMAL] = end_pfn; arch_sparse_init(); -- GitLab From b888132b0ff29ca0733589a594c243ed612438eb Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 11 Oct 2006 01:20:40 -0700 Subject: [PATCH 0972/1619] [PATCH] mm: remove memmap_zone_idx() memmap_zone_idx() is not used anymore. It was required by an earlier version of account-for-memmap-and-optionally-the-kernel-image-as-holes.patch but not any more. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a8c003e7b3d..8246e834b2f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2294,19 +2294,6 @@ unsigned long __init zone_absent_pages_in_node(int nid, return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn); } -/* 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, @@ -2325,10 +2312,6 @@ 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, -- GitLab From 1db11ea65eaf1e7f6a70805fe52bc0aef53f68ef Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Wed, 11 Oct 2006 01:20:41 -0700 Subject: [PATCH 0973/1619] [PATCH] Fix menuconfig build failure due to missing stdbool.h scripts/kconfig/lxdialog/util.c fails to build because it uses true/false without including stdbool.h: kronos:~/src/linux-2.6$ make O=../linux-build-git menuconfig GEN /home/kronos/src/linux-build/Makefile HOSTCC scripts/kconfig/lxdialog/util.o /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c: In function 'set_classic_theme': /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:68: error: 'true' undeclared (first use in this function) /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:68: error: (Each undeclared identifier is reported only once /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:68: error: for each function it appears in.) /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:70: error: 'false' undeclared (first use in this function) /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c: In function 'set_blackbg_theme': /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:101: error: 'true' undeclared (first use in this function) /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:102: error: 'false' undeclared (first use in this function) /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c: In function 'set_bluetitle_theme': /home/kronos/src/linux-2.6/scripts/kconfig/lxdialog/util.c:144: error: 'true' undeclared (first use in this function) make[2]: *** [scripts/kconfig/lxdialog/util.o] Error 1 make[1]: *** [menuconfig] Error 2 make: *** [menuconfig] Error 2 Add to dialog.h to fix the breakage. Signed-off-by: Luca Tettamanti Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kconfig/lxdialog/dialog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index 8dea47f9d3e..fd695e1070f 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef __sun__ #define CURS_MACROS -- GitLab From c37e108d156101dcde7ec7033eabe7abe83366bc Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 11 Oct 2006 01:20:43 -0700 Subject: [PATCH 0974/1619] [PATCH] use struct irq_chip instead of struct hw_interrupt_type hw_interrupt_type is deprecated in favour of struct irq_chip. [mingo@elte.hu: do x86_64 too] Acked-by: Thomas Gleixner Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 2 +- arch/x86_64/kernel/io_apic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index cd082c36ca0..27bceaf5ce4 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2594,7 +2594,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) } #endif -static struct hw_interrupt_type ht_irq_chip = { +static struct irq_chip ht_irq_chip = { .name = "PCI-HT", .mask = mask_ht_irq, .unmask = unmask_ht_irq, diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 771bcf77daf..c3cdcab2968 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1897,7 +1897,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) } #endif -static struct hw_interrupt_type ht_irq_chip = { +static struct irq_chip ht_irq_chip = { .name = "PCI-HT", .mask = mask_ht_irq, .unmask = unmask_ht_irq, -- GitLab From dea20a3fbdd08e5ae2a0b33d2577c794a3764a11 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 11 Oct 2006 01:20:44 -0700 Subject: [PATCH 0975/1619] [PATCH] Disable DETECT_SOFTLOCKUP for s390 We got several false bug reports because of enabled CONFIG_DETECT_SOFTLOCKUP. Disable soft lockup detection on s390, since it doesn't work on a virtualized architecture. Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 756a908c441..2d7cb0d04fc 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -71,7 +71,7 @@ config LOG_BUF_SHIFT config DETECT_SOFTLOCKUP bool "Detect Soft Lockups" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && !S390 default y help Say Y here to enable the kernel to detect "soft lockups", -- GitLab From 97c7801cd5b0bb6a38c16108a496235474dc6310 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Oct 2006 01:20:45 -0700 Subject: [PATCH 0976/1619] [PATCH] swsusp: Use suspend_console Add suspend_console() and resume_console() to the suspend-to-disk code paths so that the users of netconsole can use swsusp with it. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/power/disk.c | 8 ++++++++ kernel/power/user.c | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/kernel/power/disk.c b/kernel/power/disk.c index d7223494279..d3a158a6031 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "power.h" @@ -119,8 +120,10 @@ int pm_suspend_disk(void) if (error) return error; + suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) { + resume_console(); printk("Some devices failed to suspend\n"); unprepare_processes(); return error; @@ -133,6 +136,7 @@ int pm_suspend_disk(void) if (in_suspend) { device_resume(); + resume_console(); pr_debug("PM: writing image.\n"); error = swsusp_write(); if (!error) @@ -148,6 +152,7 @@ int pm_suspend_disk(void) swsusp_free(); Done: device_resume(); + resume_console(); unprepare_processes(); return error; } @@ -212,7 +217,9 @@ static int software_resume(void) pr_debug("PM: Preparing devices for restore.\n"); + suspend_console(); if ((error = device_suspend(PMSG_PRETHAW))) { + resume_console(); printk("Some devices failed to suspend\n"); swsusp_free(); goto Thaw; @@ -224,6 +231,7 @@ static int software_resume(void) swsusp_resume(); pr_debug("PM: Restore failed, recovering.n"); device_resume(); + resume_console(); Thaw: unprepare_processes(); Done: diff --git a/kernel/power/user.c b/kernel/power/user.c index 93b5dd283de..d991d3b0e5a 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -173,12 +174,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (!error) { + suspend_console(); error = device_suspend(PMSG_FREEZE); if (!error) { in_suspend = 1; error = swsusp_suspend(); device_resume(); } + resume_console(); } up(&pm_sem); if (!error) @@ -196,11 +199,13 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, snapshot_free_unused_memory(&data->handle); down(&pm_sem); pm_prepare_console(); + suspend_console(); error = device_suspend(PMSG_PRETHAW); if (!error) { error = swsusp_resume(); device_resume(); } + resume_console(); pm_restore_console(); up(&pm_sem); break; @@ -289,6 +294,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, } /* Put devices to sleep */ + suspend_console(); error = device_suspend(PMSG_SUSPEND); if (error) { printk(KERN_ERR "Failed to suspend some devices.\n"); @@ -299,7 +305,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, /* Wake up devices */ device_resume(); } - + resume_console(); if (pm_ops->finish) pm_ops->finish(PM_SUSPEND_MEM); -- GitLab From 502717f4e112b18d9c37753a32f675bec9f2838b Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Wed, 11 Oct 2006 01:20:46 -0700 Subject: [PATCH 0977/1619] [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(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 5e03b2f67b9..4ee3f006b86 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 c25a38d8f60..5081d27bfa2 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 1d709ff528e..2dbec90dc3b 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) { -- GitLab From ac27a0ec112a089f1a5102bc8dffc79c8c815571 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:20:50 -0700 Subject: [PATCH 0978/1619] [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 diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile new file mode 100644 index 00000000000..704cd44a40c --- /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 00000000000..1e5038d9a01 --- /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 00000000000..0d1e6279cbf --- /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 00000000000..b41a7d7e20f --- /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 00000000000..b9176eed98d --- /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 00000000000..d0b54f30b91 --- /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 00000000000..e96c388047e --- /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 00000000000..dd1fd3c0fc0 --- /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 00000000000..deeb27b5ba8 --- /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 00000000000..e45dbd65173 --- /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 00000000000..03ba5bcab18 --- /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 00000000000..12daa686957 --- /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 00000000000..906731a20f1 --- /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 00000000000..f2ce2b0065c --- /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 00000000000..b73cba12f79 --- /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 00000000000..8bfd56ef18c --- /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 00000000000..4f79122cde6 --- /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 00000000000..f86f2482f01 --- /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 00000000000..6b1ae1c6182 --- /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 00000000000..b9c40c15647 --- /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 00000000000..86d91f1186d --- /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 00000000000..a85a0a17c4f --- /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 00000000000..11cca1bdc0c --- /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 00000000000..4395e520674 --- /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 00000000000..f61309c81cc --- /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 00000000000..ce0e6109aff --- /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 */ -- GitLab From 617ba13b31fbf505cc21799826639ef24ed94af0 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:20:53 -0700 Subject: [PATCH 0979/1619] [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(-) diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 704cd44a40c..09c487893e4 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 1e5038d9a01..d143489aeb4 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 0d1e6279cbf..26a5c1abf14 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 b41a7d7e20f..357e4e50374 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 b9176eed98d..f4b35706f39 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 d0b54f30b91..ec114d7886c 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 e96c388047e..d938fbe1e08 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 dd1fd3c0fc0..272faa27761 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 deeb27b5ba8..d15bb427442 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 e45dbd65173..4b92066ca08 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 03ba5bcab18..7275d60dcc5 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 12daa686957..a567af161b0 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 906731a20f1..956b38113f6 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 f2ce2b0065c..5e4dfff36a0 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 b73cba12f79..4a47895d9d6 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 8bfd56ef18c..9e32a2a8d28 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 4f79122cde6..9e4c75f912f 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 f86f2482f01..d3a40815410 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 6b1ae1c6182..79432b35398 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 b9c40c15647..d84b1dabeb1 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 86d91f1186d..11bd58c95a6 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 a85a0a17c4f..9c5a665e083 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 11cca1bdc0c..f582cd762ca 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 4395e520674..18a6ce98537 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 f61309c81cc..ce4856d7010 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 ce0e6109aff..3dbf6c77903 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 */ -- GitLab From 02ea2104c55b625cf5b5d9ba8586a4fc17920f5c Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:20:56 -0700 Subject: [PATCH 0980/1619] [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(-) diff --git a/fs/Kconfig b/fs/Kconfig index 599de54451a..ac9ba1c3093 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 df614eacee8..64396af37b2 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 22036dd2ba3..156c40fc664 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 -- GitLab From 470decc613ab2048b619a01028072d932d9086ee Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:20:57 -0700 Subject: [PATCH 0981/1619] [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 diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile new file mode 100644 index 00000000000..54aca4868a3 --- /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 00000000000..0208cc7ac5d --- /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 00000000000..10be51290a2 --- /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 00000000000..c518dd8fe60 --- /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 00000000000..11563fe2a52 --- /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 00000000000..c532429d8d9 --- /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 00000000000..e1b3c8af4d1 --- /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 00000000000..3dbf6c77903 --- /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 00000000000..fe89444b1c6 --- /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 */ -- GitLab From f7f4bccb729844a0fa873e224e3a6f7eeed095bb Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:20:59 -0700 Subject: [PATCH 0982/1619] [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(-) diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile index 54aca4868a3..802a3413872 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 0208cc7ac5d..68039fa9a56 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 10be51290a2..b1a4eafc154 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 c518dd8fe60..3fbbba20a51 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 11563fe2a52..b2012d11243 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 c532429d8d9..2fccddc7aca 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 e1b3c8af4d1..149957bef90 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 3dbf6c77903..99d37557cbb 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 fe89444b1c6..3251f7abb57 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 -- GitLab From a920e9416b3469994860ab552dfd7fd5a5aff162 Mon Sep 17 00:00:00 2001 From: Johann Lombardi Date: Wed, 11 Oct 2006 01:21:00 -0700 Subject: [PATCH 0983/1619] [PATCH] jbd2: rename slab jbd and jbd2 currently use the same slab names which must be unique. The patch below just renames jbd2's slabs. Signed-off-by: Johann Lombardi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/journal.c | 6 +++--- fs/jbd2/revoke.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 3fbbba20a51..8d0f71e562f 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1631,7 +1631,7 @@ void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry) 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" + "jbd2_1k", "jbd2_2k", "jbd2_4k", NULL, "jbd2_8k" }; static void jbd2_journal_destroy_jbd_slabs(void) @@ -1702,7 +1702,7 @@ static int journal_init_jbd2_journal_head_cache(void) int retval; J_ASSERT(jbd2_journal_head_cache == 0); - jbd2_journal_head_cache = kmem_cache_create("journal_head", + jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head", sizeof(struct journal_head), 0, /* offset */ 0, /* flags */ @@ -1999,7 +1999,7 @@ kmem_cache_t *jbd2_handle_cache; static int __init journal_init_handle_cache(void) { - jbd2_handle_cache = kmem_cache_create("journal_handle", + jbd2_handle_cache = kmem_cache_create("jbd2_journal_handle", sizeof(handle_t), 0, /* offset */ 0, /* flags */ diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 2fccddc7aca..5820a0c5ad2 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -168,13 +168,13 @@ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, int __init jbd2_journal_init_revoke_caches(void) { - jbd2_revoke_record_cache = kmem_cache_create("revoke_record", + jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record", sizeof(struct jbd2_revoke_record_s), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (jbd2_revoke_record_cache == 0) return -ENOMEM; - jbd2_revoke_table_cache = kmem_cache_create("revoke_table", + jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table", sizeof(struct jbd2_revoke_table_s), 0, 0, NULL, NULL); if (jbd2_revoke_table_cache == 0) { -- GitLab From dab291af8d6307a3075c3d67d0cc8f98e646cb94 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:01 -0700 Subject: [PATCH 0984/1619] [PATCH] jbd2: enable building of jbd2 and have ext4 use it rather than jbd Reworked from a patch by Mingming Cao and Randy Dunlap 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 | 48 +++++++++++++++++++---- fs/Makefile | 1 + fs/ext4/acl.c | 2 +- fs/ext4/balloc.c | 10 ++--- fs/ext4/bitmap.c | 2 +- fs/ext4/dir.c | 2 +- fs/ext4/file.c | 4 +- fs/ext4/fsync.c | 4 +- fs/ext4/hash.c | 2 +- fs/ext4/ialloc.c | 6 +-- fs/ext4/inode.c | 52 ++++++++++++------------- fs/ext4/ioctl.c | 16 ++++---- fs/ext4/namei.c | 4 +- fs/ext4/resize.c | 2 +- fs/ext4/super.c | 84 ++++++++++++++++++++-------------------- fs/ext4/symlink.c | 2 +- fs/ext4/xattr.c | 2 +- fs/ext4/xattr_security.c | 2 +- fs/ext4/xattr_trusted.c | 2 +- fs/ext4/xattr_user.c | 2 +- 20 files changed, 141 insertions(+), 108 deletions(-) diff --git a/fs/Kconfig b/fs/Kconfig index ac9ba1c3093..db4d13324c3 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -143,24 +143,24 @@ config EXT3_FS_SECURITY config EXT4DEV_FS tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)" depends on EXPERIMENTAL - select JBD - help + select JBD2 + 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: + 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 + 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. + 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, + 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. + 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 @@ -239,6 +239,38 @@ config JBD_DEBUG generated. To turn debugging off again, do "echo 0 > /proc/sys/fs/jbd-debug". +config JBD2 + tristate + help + This is a generic journaling layer for block devices that support + both 32-bit and 64-bit block numbers. It is currently used by + the ext4dev/ext4 filesystem, but it could also be used to add + journal support to other file systems or block devices such + as RAID or LVM. + + If you are using ext4dev/ext4, you need to say Y here. If you are not + using ext4dev/ext4 then you will probably want to say N. + + To compile this device as a module, choose M here. The module will be + called jbd2. If you are compiling ext4dev/ext4 into the kernel, + you cannot compile this code as a module. + +config JBD2_DEBUG + bool "JBD2 (ext4dev/ext4) debugging support" + depends on JBD2 + help + If you are using the ext4dev/ext4 journaled file system (or + potentially any other filesystem/device using JBD2), this option + allows you to enable debugging output while the system is running, + in order to help track down any problems you are having. + By default, the debugging output will be turned off. + + If you select Y here, then you will be able to turn on debugging + with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between + 1 and 5. The higher the number, the more debugging output is + generated. To turn debugging off again, do + "echo 0 > /proc/sys/fs/jbd2-debug". + config FS_MBCACHE # Meta block cache for Extended Attributes (ext2/ext3/ext4) tristate diff --git a/fs/Makefile b/fs/Makefile index 64396af37b2..9a5ce9323bf 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -64,6 +64,7 @@ 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_JBD2) += jbd2/ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ obj-$(CONFIG_RAMFS) += ramfs/ diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index d143489aeb4..0a965dd5664 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include "xattr.h" #include "acl.h" diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 357e4e50374..e9e98449137 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -14,9 +14,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include @@ -526,12 +526,12 @@ do_more: * transaction. * * Ideally we would want to allow that to happen, but to - * do so requires making journal_forget() capable of + * do so requires making jbd2_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() + * Eventually we can fix this by making jbd2_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 @@ -1382,7 +1382,7 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries) jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); - return journal_force_commit_nested(EXT4_SB(sb)->s_journal); + return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal); } /** diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index f4b35706f39..11e93c169bc 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -8,7 +8,7 @@ */ #include -#include +#include #include #ifdef EXT4FS_DEBUG diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index ec114d7886c..9833d5d00c4 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -22,7 +22,7 @@ */ #include -#include +#include #include #include #include diff --git a/fs/ext4/file.c b/fs/ext4/file.c index d938fbe1e08..0b622c0624b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -20,9 +20,9 @@ #include #include -#include +#include #include -#include +#include #include "xattr.h" #include "acl.h" diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 272faa27761..2a167d7131f 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -26,9 +26,9 @@ #include #include #include -#include +#include #include -#include +#include /* * akpm: A new design for ext4_sync_file(). diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index d15bb427442..a67966385e0 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #include diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 4b92066ca08..34d39ae966f 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -14,9 +14,9 @@ #include #include -#include +#include #include -#include +#include #include #include #include @@ -497,7 +497,7 @@ repeat_in_this_group: goto got; } /* we lost it */ - journal_release_buffer(handle, bitmap_bh); + jbd2_journal_release_buffer(handle, bitmap_bh); if (++ino < EXT4_INODES_PER_GROUP(sb)) goto repeat_in_this_group; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7275d60dcc5..0d96c7d3bb5 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -25,8 +25,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -84,7 +84,7 @@ int ext4_forget(handle_t *handle, int is_metadata, struct inode *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"); + BUFFER_TRACE(bh, "call jbd2_journal_forget"); return ext4_journal_forget(handle, bh); } return 0; @@ -657,7 +657,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, failed: /* Allocation failed, free what we already allocated */ for (i = 1; i <= n ; i++) { - BUFFER_TRACE(branch[i].bh, "call journal_forget"); + BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget"); ext4_journal_forget(handle, branch[i].bh); } for (i = 0; i @@ -1135,7 +1135,7 @@ static int walk_page_buffers( handle_t *handle, * 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 + * So what we do is to rely on the fact that jbd2_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. @@ -1184,7 +1184,7 @@ out: int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { - int err = journal_dirty_data(handle, bh); + int err = jbd2_journal_dirty_data(handle, bh); if (err) ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__, bh, handle,err); @@ -1333,9 +1333,9 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) EXT4_I(inode)->i_state &= ~EXT4_STATE_JDATA; journal = EXT4_JOURNAL(inode); - journal_lock_updates(journal); - err = journal_flush(journal); - journal_unlock_updates(journal); + jbd2_journal_lock_updates(journal); + err = jbd2_journal_flush(journal); + jbd2_journal_unlock_updates(journal); if (err) return 0; @@ -1356,7 +1356,7 @@ static int bput_one(handle_t *handle, struct buffer_head *bh) return 0; } -static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) +static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) { if (buffer_mapped(bh)) return ext4_journal_dirty_data(handle, bh); @@ -1464,7 +1464,7 @@ static int ext4_ordered_writepage(struct page *page, */ if (ret == 0) { err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, - NULL, journal_dirty_data_fn); + NULL, jbd2_journal_dirty_data_fn); if (!ret) ret = err; } @@ -1595,7 +1595,7 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset) if (offset == 0) ClearPageChecked(page); - journal_invalidatepage(journal, page, offset); + jbd2_journal_invalidatepage(journal, page, offset); } static int ext4_releasepage(struct page *page, gfp_t wait) @@ -1605,7 +1605,7 @@ static int ext4_releasepage(struct page *page, gfp_t wait) WARN_ON(PageChecked(page)); if (!page_has_buffers(page)) return 0; - return journal_try_to_free_buffers(journal, page, wait); + return jbd2_journal_try_to_free_buffers(journal, page, wait); } /* @@ -1982,11 +1982,11 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, /* * 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() + * them on the hash table so jbd2_journal_revoke() will run jbd2_journal_forget() * on them. We've already detached each block from the file, so - * bforget() in journal_forget() should be safe. + * bforget() in jbd2_journal_forget() should be safe. * - * AKPM: turn on bforget in journal_forget()!!! + * AKPM: turn on bforget in jbd2_journal_forget()!!! */ for (p = first; p < last; p++) { u32 nr = le32_to_cpu(*p); @@ -2132,11 +2132,11 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, * 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(). + * jbd2_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 + * transaction then jbd2_journal_forget() will simply * brelse() it. That means that if the underlying * block is reallocated in ext4_get_block(), * unmap_underlying_metadata() will find this block @@ -2251,7 +2251,7 @@ void ext4_truncate(struct inode *inode) /* * We have to lock the EOF page here, because lock_page() nests - * outside journal_start(). + * outside jbd2_journal_start(). */ if ((inode->i_size & (blocksize - 1)) == 0) { /* Block boundary? Nothing to do */ @@ -3035,7 +3035,7 @@ int ext4_mark_iloc_dirty(handle_t *handle, /* the do_update_inode consumes one bh->b_count */ get_bh(iloc->bh); - /* ext4_do_update_inode() does journal_dirty_metadata */ + /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */ err = ext4_do_update_inode(handle, inode, iloc); put_bh(iloc->bh); return err; @@ -3153,7 +3153,7 @@ static int ext4_pin_inode(handle_t *handle, struct inode *inode) err = ext4_get_inode_loc(inode, &iloc); if (!err) { BUFFER_TRACE(iloc.bh, "get_write_access"); - err = journal_get_write_access(handle, iloc.bh); + err = jbd2_journal_get_write_access(handle, iloc.bh); if (!err) err = ext4_journal_dirty_metadata(handle, iloc.bh); @@ -3185,8 +3185,8 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) if (is_journal_aborted(journal) || IS_RDONLY(inode)) return -EROFS; - journal_lock_updates(journal); - journal_flush(journal); + jbd2_journal_lock_updates(journal); + jbd2_journal_flush(journal); /* * OK, there are no updates running now, and all cached data is @@ -3202,7 +3202,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) EXT4_I(inode)->i_flags &= ~EXT4_JOURNAL_DATA_FL; ext4_set_aops(inode); - journal_unlock_updates(journal); + jbd2_journal_unlock_updates(journal); /* Finally we can mark the inode as dirty. */ diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a567af161b0..a63dce2117b 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -8,10 +8,10 @@ */ #include -#include +#include #include #include -#include +#include #include #include #include @@ -219,9 +219,9 @@ flags_err: return -EFAULT; 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); + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); return err; } @@ -241,9 +241,9 @@ flags_err: return -EFAULT; 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); + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); return err; } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 956b38113f6..f98b9994e36 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -26,10 +26,10 @@ #include #include -#include +#include #include #include -#include +#include #include #include #include diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 4a47895d9d6..5b2828d2118 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9e32a2a8d28..f131bb69b62 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -20,9 +20,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ static void ext4_write_super (struct super_block * sb); static void ext4_write_super_lockfs(struct super_block *sb); /* - * Wrappers for journal_start/end. + * Wrappers for jbd2_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 @@ -87,12 +87,12 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) return ERR_PTR(-EROFS); } - return journal_start(journal, nblocks); + return jbd2_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 + * jbd2_journal_stop calls result in the superblock being marked dirty, so * that sync() will call the filesystem's write_super callback if * appropriate. */ @@ -104,7 +104,7 @@ int __ext4_journal_stop(const char *where, handle_t *handle) sb = handle->h_transaction->t_journal->j_private; err = handle->h_err; - rc = journal_stop(handle); + rc = jbd2_journal_stop(handle); if (!err) err = rc; @@ -131,7 +131,7 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn, printk(KERN_ERR "%s: aborting transaction: %s in %s\n", caller, errstr, err_fn); - journal_abort_handle(handle); + jbd2_journal_abort_handle(handle); } /* Deal with the reporting of failure conditions on a filesystem such as @@ -144,7 +144,7 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn, * 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 + * We'll just use the jbd2_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. */ @@ -164,7 +164,7 @@ static void ext4_handle_error(struct super_block *sb) EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; if (journal) - journal_abort(journal, -EIO); + jbd2_journal_abort(journal, -EIO); } if (test_opt (sb, ERRORS_RO)) { printk (KERN_CRIT "Remounting filesystem read-only\n"); @@ -203,7 +203,7 @@ static const char *ext4_decode_error(struct super_block * sb, int errno, errstr = "Out of memory"; break; case -EROFS: - if (!sb || EXT4_SB(sb)->s_journal->j_flags & JFS_ABORT) + if (!sb || EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT) errstr = "Journal has aborted"; else errstr = "Readonly filesystem"; @@ -279,7 +279,7 @@ void ext4_abort (struct super_block * sb, const char * function, EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; sb->s_flags |= MS_RDONLY; EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; - journal_abort(EXT4_SB(sb)->s_journal, -EIO); + jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); } void ext4_warning (struct super_block * sb, const char * function, @@ -391,7 +391,7 @@ static void ext4_put_super (struct super_block * sb) int i; ext4_xattr_put_super(sb); - journal_destroy(sbi->s_journal); + jbd2_journal_destroy(sbi->s_journal); if (!(sb->s_flags & MS_RDONLY)) { EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); es->s_state = cpu_to_le16(sbi->s_mount_state); @@ -1722,8 +1722,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) /* 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)) + if (jbd2_journal_check_available_features + (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) set_opt(sbi->s_mount_opt, ORDERED_DATA); else set_opt(sbi->s_mount_opt, JOURNAL_DATA); @@ -1731,8 +1731,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) case EXT4_MOUNT_ORDERED_DATA: case EXT4_MOUNT_WRITEBACK_DATA: - if (!journal_check_available_features - (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { + if (!jbd2_journal_check_available_features + (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) { printk(KERN_ERR "EXT4-fs: Journal does not support " "requested data journaling mode\n"); goto failed_mount4; @@ -1749,7 +1749,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) } } /* - * The journal_load will have done any necessary log recovery, + * The jbd2_journal_load will have done any necessary log recovery, * so we can safely mount the rest of the filesystem now. */ @@ -1797,7 +1797,7 @@ cantfind_ext4: goto failed_mount; failed_mount4: - journal_destroy(sbi->s_journal); + jbd2_journal_destroy(sbi->s_journal); failed_mount3: percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); @@ -1837,9 +1837,9 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal) spin_lock(&journal->j_state_lock); if (test_opt(sb, BARRIER)) - journal->j_flags |= JFS_BARRIER; + journal->j_flags |= JBD2_BARRIER; else - journal->j_flags &= ~JFS_BARRIER; + journal->j_flags &= ~JBD2_BARRIER; spin_unlock(&journal->j_state_lock); } @@ -1873,7 +1873,7 @@ static journal_t *ext4_get_journal(struct super_block *sb, return NULL; } - journal = journal_init_inode(journal_inode); + journal = jbd2_journal_init_inode(journal_inode); if (!journal) { printk(KERN_ERR "EXT4-fs: Could not load journal inode\n"); iput(journal_inode); @@ -1945,7 +1945,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, start = sb_block + 1; brelse(bh); /* we're done with the superblock */ - journal = journal_init_dev(bdev, sb->s_bdev, + journal = jbd2_journal_init_dev(bdev, sb->s_bdev, start, len, blocksize); if (!journal) { printk(KERN_ERR "EXT4-fs: failed to create device journal\n"); @@ -1968,7 +1968,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, ext4_init_journal_params(sb, journal); return journal; out_journal: - journal_destroy(journal); + jbd2_journal_destroy(journal); out_bdev: ext4_blkdev_put(bdev); return NULL; @@ -2029,22 +2029,22 @@ static int ext4_load_journal(struct super_block *sb, } if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { - err = journal_update_format(journal); + err = jbd2_journal_update_format(journal); if (err) { printk(KERN_ERR "EXT4-fs: error updating journal.\n"); - journal_destroy(journal); + jbd2_journal_destroy(journal); return err; } } if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) - err = journal_wipe(journal, !really_read_only); + err = jbd2_journal_wipe(journal, !really_read_only); if (!err) - err = journal_load(journal); + err = jbd2_journal_load(journal); if (err) { printk(KERN_ERR "EXT4-fs: error loading journal.\n"); - journal_destroy(journal); + jbd2_journal_destroy(journal); return err; } @@ -2081,9 +2081,9 @@ static int ext4_create_journal(struct super_block * sb, printk(KERN_INFO "EXT4-fs: creating new journal on inode %u\n", journal_inum); - if (journal_create(journal)) { + if (jbd2_journal_create(journal)) { printk(KERN_ERR "EXT4-fs: error creating journal.\n"); - journal_destroy(journal); + jbd2_journal_destroy(journal); return -EIO; } @@ -2130,15 +2130,15 @@ static void ext4_mark_recovery_complete(struct super_block * sb, { journal_t *journal = EXT4_SB(sb)->s_journal; - journal_lock_updates(journal); - journal_flush(journal); + jbd2_journal_lock_updates(journal); + jbd2_journal_flush(journal); if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) && sb->s_flags & MS_RDONLY) { EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); sb->s_dirt = 0; ext4_commit_super(sb, es, 1); } - journal_unlock_updates(journal); + jbd2_journal_unlock_updates(journal); } /* @@ -2160,7 +2160,7 @@ static void ext4_clear_journal_err(struct super_block * sb, * journal by a prior ext4_error() or ext4_abort() */ - j_errno = journal_errno(journal); + j_errno = jbd2_journal_errno(journal); if (j_errno) { char nbuf[16]; @@ -2174,7 +2174,7 @@ static void ext4_clear_journal_err(struct super_block * sb, es->s_state |= cpu_to_le16(EXT4_ERROR_FS); ext4_commit_super (sb, es, 1); - journal_clear_err(journal); + jbd2_journal_clear_err(journal); } } @@ -2217,9 +2217,9 @@ static int ext4_sync_fs(struct super_block *sb, int wait) tid_t target; sb->s_dirt = 0; - if (journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { + if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { if (wait) - log_wait_commit(EXT4_SB(sb)->s_journal, target); + jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); } return 0; } @@ -2236,8 +2236,8 @@ static void ext4_write_super_lockfs(struct super_block *sb) journal_t *journal = EXT4_SB(sb)->s_journal; /* Now we set up the journal barrier. */ - journal_lock_updates(journal); - journal_flush(journal); + jbd2_journal_lock_updates(journal); + jbd2_journal_flush(journal); /* Journal blocked and flushed, clear needs_recovery flag. */ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); @@ -2257,7 +2257,7 @@ static void ext4_unlockfs(struct super_block *sb) 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(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); } } @@ -2438,9 +2438,9 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) * is locked for write. Otherwise the are possible deadlocks: * Process 1 Process 2 * ext4_create() quota_sync() - * journal_start() write_dquot() + * jbd2_journal_start() write_dquot() * DQUOT_INIT() down(dqio_mutex) - * down(dqio_mutex) journal_start() + * down(dqio_mutex) jbd2_journal_start() * */ diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index 9e4c75f912f..fcf527286d7 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include #include "xattr.h" diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index d3a40815410..90f7d5c0bae 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c index d84b1dabeb1..b6a6861951f 100644 --- a/fs/ext4/xattr_security.c +++ b/fs/ext4/xattr_security.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include "xattr.h" diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c index 11bd58c95a6..b76f2dbc82d 100644 --- a/fs/ext4/xattr_trusted.c +++ b/fs/ext4/xattr_trusted.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "xattr.h" diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c index 9c5a665e083..c53cded0761 100644 --- a/fs/ext4/xattr_user.c +++ b/fs/ext4/xattr_user.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include "xattr.h" -- GitLab From c3fcc8137ce4296ad6ab94f88bd60cbe03d21527 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:21:02 -0700 Subject: [PATCH 0985/1619] [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 diff --git a/include/linux/ext4_jbd.h b/include/linux/ext4_jbd.h deleted file mode 100644 index 3dbf6c77903..00000000000 --- 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 */ -- GitLab From a86c61812637c7dd0c57e29880cffd477b62f2e7 Mon Sep 17 00:00:00 2001 From: Alex Tomas Date: Wed, 11 Oct 2006 01:21:03 -0700 Subject: [PATCH 0986/1619] [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 diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 09c487893e4..a6acb96ebeb 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 9833d5d00c4..18ac173af57 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 00000000000..f67b2ef6a71 --- /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 34d39ae966f..e17a6c918d7 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 0d96c7d3bb5..2b81b1324a6 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 a63dce2117b..22a737c306c 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 f131bb69b62..69f87525050 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 f582cd762ca..b61181aadcb 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 00000000000..8029879e29e --- /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 18a6ce98537..40ce04a52b0 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 ce4856d7010..ce7a844d670 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 99d37557cbb..aa273f024ad 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 -- GitLab From 3a5b2ecdd1fa63a8f25bd769223bc1c2564ce45d Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:05 -0700 Subject: [PATCH 0987/1619] [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(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e9e98449137..aa33ff271fa 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 e17a6c918d7..94e1bb4abe3 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 5b2828d2118..c60bfed5f5e 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 69f87525050..1d12e4f7d69 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 b61181aadcb..e952c6db969 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 40ce04a52b0..b2ccd9876bd 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 */ -- GitLab From f65e6fba163dfd0f962efb7d8f5528b6872e2b15 Mon Sep 17 00:00:00 2001 From: Alex Tomas Date: Wed, 11 Oct 2006 01:21:05 -0700 Subject: [PATCH 0988/1619] [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(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index f67b2ef6a71..4a13b56e154 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 8029879e29e..facc76684d4 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 b2ccd9876bd..2bed0effdca 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; }; /* -- GitLab From 471d4011a9862efff02094388b8fe8cd67683c38 Mon Sep 17 00:00:00 2001 From: Suparna Bhattacharya Date: Wed, 11 Oct 2006 01:21:06 -0700 Subject: [PATCH 0989/1619] [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(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 4a13b56e154..32526061a17 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 facc76684d4..0eba0acf6ba 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__)) + \ -- GitLab From d0d856e8bd6e697cb44b2b4dd038f3bec576a70e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2006 01:21:07 -0700 Subject: [PATCH 0990/1619] [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(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 32526061a17..e06e937a52b 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 0eba0acf6ba..a41cc24568c 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 aa273f024ad..f69af60d769 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) \ -- GitLab From b517bea1c74e4773482b3f41b3f493522a8c8e30 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 11 Oct 2006 01:21:08 -0700 Subject: [PATCH 0991/1619] [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(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index b1a4eafc154..44d68a113c7 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 8d0f71e562f..926ebcbf8a7 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 b2012d11243..2486843adda 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 5820a0c5ad2..8aac875bd30 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 3251f7abb57..5e5aa64f126 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 -- GitLab From 299717696d48531d70aeb4614c3939e4a28456c1 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:09 -0700 Subject: [PATCH 0992/1619] [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(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 44d68a113c7..1a9ce888522 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 926ebcbf8a7..259e8365ea1 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 2486843adda..52054a83e71 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 8aac875bd30..3310a1d7ace 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 f69af60d769..72dd631912e 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 5e5aa64f126..3c939c844a7 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); -- GitLab From a1ddeb7eaecea6a924e3a79aa386797020cb436f Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Wed, 11 Oct 2006 01:21:09 -0700 Subject: [PATCH 0993/1619] [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(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2b81b1324a6..9db8cff3baa 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 e952c6db969..63ed89f5b27 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__) */ -- GitLab From bd81d8eec043094d3ff729a8ff6d5b3a06d3c4b1 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 11 Oct 2006 01:21:10 -0700 Subject: [PATCH 0994/1619] [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(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index aa33ff271fa..6887151ccc4 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 94e1bb4abe3..959b7fa8f5d 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 9db8cff3baa..effc38afebe 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 c60bfed5f5e..3dbf91b8220 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 1d12e4f7d69..b91dffd7a03 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 63ed89f5b27..8e5009ee4ad 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 { \ -- GitLab From 2ae0210760aed9d626eaede5b63db95e198f7c8e Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:11 -0700 Subject: [PATCH 0995/1619] [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(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 6887151ccc4..df77ea891f2 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 e06e937a52b..f72b7567bfa 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 effc38afebe..99b82b52b5f 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 3dbf91b8220..3e960677c2f 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 b91dffd7a03..d844175e60e 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 90f7d5c0bae..63233cd946a 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 2bed0effdca..bb42379cb7f 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 */ -- GitLab From 9b8f1f0106ab39ad58765d4e7c57189835f51127 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:13 -0700 Subject: [PATCH 0996/1619] [PATCH] ext4: removesector_t bits check Previously when in-kernel ext4 block type is sector_t, it's only 4 bits long under some 32bit arch (when CONFIG_LBD is not on). So we need to check the size of sector_t before we read 48bit long on-disk blocks to in-kernel blocks. These checks are unnecessary now as we changed the in-kernel blocks to unsigned longlong. Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/extents.c | 12 ++++-------- fs/ext4/inode.c | 10 ++++------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index f72b7567bfa..926186a787a 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -53,8 +53,7 @@ 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; + block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1; return block; } @@ -67,8 +66,7 @@ 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; + block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1; return block; } @@ -80,8 +78,7 @@ static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix) 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); + ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); } /* @@ -92,8 +89,7 @@ static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb 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); + 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, diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 99b82b52b5f..c05dc57148b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2643,9 +2643,8 @@ 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))) + if (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)) { @@ -2781,9 +2780,8 @@ 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))) + if (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); -- GitLab From 18eba7aae080d4a5c0d850ea810e83d11f0a8d77 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:13 -0700 Subject: [PATCH 0997/1619] [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(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 1a9ce888522..70b2ae1ef28 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 259e8365ea1..10db92ced01 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 52054a83e71..9f10acafaf7 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 3310a1d7ace..380d19917f3 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 3c939c844a7..ddb12879578 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); -- GitLab From 0d1ee42f27d30eed1659f3e85bcbbc7b3711f61f Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 11 Oct 2006 01:21:14 -0700 Subject: [PATCH 0998/1619] [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(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index df77ea891f2..3dacb124b8c 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 c05dc57148b..d03e7d85a63 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 d844175e60e..bc8848bff2f 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 8e5009ee4ad..a3df2afc004 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 ce7a844d670..691a713139c 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 */ -- GitLab From 8fadc14323684c547f74cf2f4d13517c6c264731 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 11 Oct 2006 01:21:15 -0700 Subject: [PATCH 0999/1619] [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(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 3dacb124b8c..3e85886a638 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 959b7fa8f5d..75608e1e555 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 d03e7d85a63..0a60ec5a16d 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 3e960677c2f..1e9578052cd 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 bc8848bff2f..811011fc5c9 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 a3df2afc004..296609b9242 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) { -- GitLab From 72b64b594081ef0a0717f6aad77e891c72ed4afa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:18 -0700 Subject: [PATCH 1000/1619] [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(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 3e85886a638..402475a6f3d 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 296609b9242..498503ee613 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 -- GitLab From f4e5bc244f23ee024a4dfa034b591b219b2bfb8f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:19 -0700 Subject: [PATCH 1001/1619] [PATCH] ext4 64 bit divide fix With CONFIG_LBD=n, sector_div() expands to a plain old divide. But ext4 is _not_ passing in a sector_t as the first argument, so... fs/built-in.o: In function `ext4_get_group_no_and_offset': fs/ext4/balloc.c:39: undefined reference to `__umoddi3' fs/ext4/balloc.c:41: undefined reference to `__udivdi3' fs/built-in.o: In function `find_group_orlov': fs/ext4/ialloc.c:278: undefined reference to `__udivdi3' fs/built-in.o: In function `ext4_fill_super': fs/ext4/super.c:1488: undefined reference to `__udivdi3' fs/ext4/super.c:1488: undefined reference to `__umoddi3' fs/ext4/super.c:1594: undefined reference to `__udivdi3' fs/ext4/super.c:1601: undefined reference to `__umoddi3' Fix that up by calling do_div() directly. Also cast the arg to u64. do_div() is only defined on u64, and ext4_fsblk_t is supposed to be opaque. Note especially the changes to find_group_orlov(). It was attempting to do do_div(int, unsigned long long); which is royally screwed up. Switched it to plain old divide. Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 2 +- fs/ext4/ialloc.c | 6 +++--- fs/ext4/super.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 402475a6f3d..5d45582f951 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -34,7 +34,7 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, ext4_grpblk_t offset; blocknr = blocknr - le32_to_cpu(es->s_first_data_block); - offset = sector_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)); + offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)); if (offsetp) *offsetp = offset; if (blockgrpp) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 75608e1e555..c88b439ba5c 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -275,7 +275,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) avefreei = freei / ngroups; freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter); avefreeb = freeb; - sector_div(avefreeb, ngroups); + do_div(avefreeb, ngroups); ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); if ((parent == sb->s_root->d_inode) || @@ -305,14 +305,14 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) } blocks_per_dir = ext4_blocks_count(es) - freeb; - sector_div(blocks_per_dir, ndirs); + do_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); - sector_div(max_debt, max(blocks_per_dir, (ext4_fsblk_t)BLOCK_COST)); + max_debt /= max_t(int, blocks_per_dir, 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/super.c b/fs/ext4/super.c index 811011fc5c9..f7ea0224f53 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1485,7 +1485,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) */ if (blocksize != EXT4_MIN_BLOCK_SIZE) { logic_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; - offset = sector_div(logic_sb_block, blocksize); + offset = do_div(logic_sb_block, blocksize); } else { logic_sb_block = sb_block; } @@ -1591,7 +1591,7 @@ 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; - offset = sector_div(logic_sb_block, blocksize); + offset = do_div(logic_sb_block, blocksize); bh = sb_bread(sb, logic_sb_block); if (!bh) { printk(KERN_ERR -- GitLab From 70bbb3e0a07c1ff2dd383761b12f865b6002a7a0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:20 -0700 Subject: [PATCH 1002/1619] [PATCH] ext4: rename logic_sb_block I assume this means "logical sb block". So call it that. I still don't understand the name though. A block is a block. What's different about this one? Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/super.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f7ea0224f53..6cf1f185b9c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1423,8 +1423,7 @@ static loff_t ext4_max_size(int bits) } static ext4_fsblk_t descriptor_loc(struct super_block *sb, - ext4_fsblk_t logic_sb_block, - int nr) + ext4_fsblk_t logical_sb_block, int nr) { struct ext4_sb_info *sbi = EXT4_SB(sb); unsigned long bg, first_meta_bg; @@ -1434,7 +1433,7 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb, if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) || nr < first_meta_bg) - return (logic_sb_block + nr + 1); + return logical_sb_block + nr + 1; bg = sbi->s_desc_per_block * nr; if (ext4_bg_has_super(sb, bg)) has_super = 1; @@ -1449,7 +1448,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) struct ext4_sb_info *sbi; ext4_fsblk_t block; ext4_fsblk_t sb_block = get_sb_block(&data); - ext4_fsblk_t logic_sb_block; + ext4_fsblk_t logical_sb_block; unsigned long offset = 0; unsigned int journal_inum = 0; unsigned long journal_devnum = 0; @@ -1484,13 +1483,13 @@ 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; - offset = do_div(logic_sb_block, blocksize); + logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; + offset = do_div(logical_sb_block, blocksize); } else { - logic_sb_block = sb_block; + logical_sb_block = sb_block; } - if (!(bh = sb_bread(sb, logic_sb_block))) { + if (!(bh = sb_bread(sb, logical_sb_block))) { printk (KERN_ERR "EXT4-fs: unable to read superblock\n"); goto out_fail; } @@ -1590,9 +1589,9 @@ 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; - offset = do_div(logic_sb_block, blocksize); - bh = sb_bread(sb, logic_sb_block); + logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; + offset = do_div(logical_sb_block, blocksize); + bh = sb_bread(sb, logical_sb_block); if (!bh) { printk(KERN_ERR "EXT4-fs: Can't read superblock on 2nd try.\n"); @@ -1711,7 +1710,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) bgl_lock_init(&sbi->s_blockgroup_lock); for (i = 0; i < db_count; i++) { - block = descriptor_loc(sb, logic_sb_block, i); + block = descriptor_loc(sb, logical_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); if (!sbi->s_group_desc[i]) { printk (KERN_ERR "EXT4-fs: " -- GitLab From ceea16bf85fb46035dda1db263ca29b0e07e22ba Mon Sep 17 00:00:00 2001 From: Dmitry Mishin Date: Wed, 11 Oct 2006 01:21:21 -0700 Subject: [PATCH 1003/1619] [PATCH] ext4: errors behaviour fix Current error behaviour for ext2 and ext3 filesystems does not fully correspond to the documentation and should be fixed. According to man 8 mount, ext2 and ext3 file systems allow to set one of 3 different on-errors behaviours: ---- start of quote man 8 mount ---- errors=continue / errors=remount-ro / errors=panic Define the behaviour when an error is encountered. (Either ignore errors and just mark the file system erroneous and continue, or remount the file system read-only, or panic and halt the system.) The default is set in the filesystem superblock, and can be changed using tune2fs(8). ---- end of quote ---- However EXT3_ERRORS_CONTINUE is not read from the superblock, and thus ERRORS_CONT is not saved on the sbi->s_mount_opt. It leads to the incorrect handle of errors on ext3. Then we've checked corresponding code in ext2 and discovered that it is buggy as well: - EXT2_ERRORS_CONTINUE is not read from the superblock (the same); - parse_option() does not clean the alternative values and thus something like (ERRORS_CONT|ERRORS_RO) can be set; - if options are omitted, parse_option() does not set any of these options. Therefore it is possible to set any combination of these options on the ext2: - none of them may be set: EXT2_ERRORS_CONTINUE on superblock / empty mount options; - any of them may be set using mount options; - 2 any options may be set: by using EXT2_ERRORS_RO/EXT2_ERRORS_PANIC on the superblock and other value in mount options; - and finally all three options may be set by adding third option in remount. Currently ext2 uses these values only in ext2_error() and it is not leading to any noticeable troubles. However somebody may be discouraged when he will try to workaround EXT2_ERRORS_PANIC on the superblock by using errors=continue in mount options. This patch: EXT4_ERRORS_CONTINUE should be taken from the superblock as default value for error behaviour. Signed-off-by: Dmitry Mishin Acked-by: Vasily Averin Acked-by: Kirill Korotaev Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6cf1f185b9c..1fa3bdc3c67 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1526,6 +1526,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, ERRORS_PANIC); else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_RO) set_opt(sbi->s_mount_opt, ERRORS_RO); + else + set_opt(sbi->s_mount_opt, ERRORS_CONT); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); -- GitLab From 63f5793351d821749979e36889f9c089c6028c83 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:24 -0700 Subject: [PATCH 1004/1619] [PATCH] ext4 whitespace cleanups Someone's tab key is emitting spaces. Attempt to repair some of the damage. Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/acl.c | 4 ++-- fs/ext4/dir.c | 7 ++++--- fs/ext4/extents.c | 14 ++++++------- fs/ext4/namei.c | 52 +++++++++++++++++++++++------------------------ fs/ext4/super.c | 14 +++++++------ 5 files changed, 46 insertions(+), 45 deletions(-) diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 0a965dd5664..9e882546d91 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -141,7 +141,7 @@ ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl) static inline void ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl, - struct posix_acl *acl) + struct posix_acl *acl) { spin_lock(&inode->i_lock); if (*i_acl != EXT4_ACL_NOT_CACHED) @@ -375,7 +375,7 @@ int ext4_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; - int error; + int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 18ac173af57..f8595787a70 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -188,8 +188,9 @@ revalidate: 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. */ + /* + * On error, skip the f_pos to the next block + */ filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1)) + 1; brelse (bh); @@ -508,7 +509,7 @@ finished: static int ext4_release_dir (struct inode * inode, struct file * filp) { - if (filp->private_data) + if (filp->private_data) ext4_htree_free_dir_info(filp->private_data); return 0; diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 926186a787a..2608dce18f3 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1014,7 +1014,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) * 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) + struct ext4_ext_path *path) { int depth; @@ -1097,8 +1097,8 @@ static int inline ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, struct ext4_extent *ex2) { - if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) - != le32_to_cpu(ex2->ee_block)) + if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) != + le32_to_cpu(ex2->ee_block)) return 0; /* @@ -1113,7 +1113,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, return 0; #endif - if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2)) + if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2)) return 1; return 0; } @@ -2008,9 +2008,9 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, goto out2; } /* - * Okay, we need to do block allocation. Lazily initialize the block - * allocation info here if necessary. - */ + * 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); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f98b9994e36..8b1bd03d20f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -241,13 +241,13 @@ static inline unsigned dx_node_limit (struct inode *dir) #ifdef DX_DEBUG static void dx_show_index (char * label, struct dx_entry *entries) { - int i, n = dx_get_count (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"); + 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 @@ -688,28 +688,26 @@ static int dx_make_map (struct ext4_dir_entry_2 *de, int size, 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) + 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; + swap(*(q+1), *q); + more = 1; } } while(more); } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1fa3bdc3c67..b4b022aa2bc 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1191,9 +1191,10 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, "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! :) */ + * 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) & ~EXT4_VALID_FS); #endif if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) @@ -1791,8 +1792,9 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) 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 */ + * capabilities: ORDERED_DATA if the journal can + * cope, else JOURNAL_DATA + */ if (jbd2_journal_check_available_features (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) set_opt(sbi->s_mount_opt, ORDERED_DATA); @@ -2802,7 +2804,7 @@ static int __init init_ext4_fs(void) err = init_inodecache(); if (err) goto out1; - err = register_filesystem(&ext4dev_fs_type); + err = register_filesystem(&ext4dev_fs_type); if (err) goto out; return 0; -- GitLab From fc513a333b45f8913d40c8241a0cb61be79e1c60 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:21:25 -0700 Subject: [PATCH 1005/1619] [PATCH] Documentation/filesystems/ext4.txt This file, ext4.txt, was put together with information from Andrew Morton, Andreas Dilger, Suparna Bhattacharya, and Ted Ts'o. I copied the mount options, with the exception of "extents", from ext3.txt, so if anyone is aware of anything out-of-date, please let me know. Signed-off-by: Dave Kleikamp Cc: Theodore Ts'o Cc: Suparna Bhattacharya Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/00-INDEX | 2 + Documentation/filesystems/ext4.txt | 236 +++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 Documentation/filesystems/ext4.txt diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 3c384c0cf86..4dc28cc9350 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -34,6 +34,8 @@ ext2.txt - info, mount options and specifications for the Ext2 filesystem. ext3.txt - info, mount options and specifications for the Ext3 filesystem. +ext4.txt + - info, mount options and specifications for the Ext4 filesystem. files.txt - info on file management in the Linux kernel. fuse.txt diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt new file mode 100644 index 00000000000..6a4adcae9f9 --- /dev/null +++ b/Documentation/filesystems/ext4.txt @@ -0,0 +1,236 @@ + +Ext4 Filesystem +=============== + +This is a development version of the ext4 filesystem, an advanced level +of the ext3 filesystem which incorporates scalability and reliability +enhancements for supporting large filesystems (64 bit) in keeping with +increasing disk capacities and state-of-the-art feature requirements. + +Mailing list: linux-ext4@vger.kernel.org + + +1. Quick usage instructions: +=========================== + + - Grab updated e2fsprogs from + ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs-interim/ + This is a patchset on top of e2fsprogs-1.39, which can be found at + ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/ + + - It's still mke2fs -j /dev/hda1 + + - mount /dev/hda1 /wherever -t ext4dev + + - To enable extents, + + mount /dev/hda1 /wherever -t ext4dev -o extents + + - The filesystem is compatible with the ext3 driver until you add a file + which has extents (ie: `mount -o extents', then create a file). + + NOTE: The "extents" mount flag is temporary. It will soon go away and + extents will be enabled by the "-o extents" flag to mke2fs or tune2fs + + - When comparing performance with other filesystems, remember that + ext3/4 by default offers higher data integrity guarantees than most. So + when comparing with a metadata-only journalling filesystem, use `mount -o + data=writeback'. And you might as well use `mount -o nobh' too along + with it. Making the journal larger than the mke2fs default often helps + performance with metadata-intensive workloads. + +2. Features +=========== + +2.1 Currently available + +* ability to use filesystems > 16TB +* extent format reduces metadata overhead (RAM, IO for access, transactions) +* extent format more robust in face of on-disk corruption due to magics, +* internal redunancy in tree + +2.1 Previously available, soon to be enabled by default by "mkefs.ext4": + +* dir_index and resize inode will be on by default +* large inodes will be used by default for fast EAs, nsec timestamps, etc + +2.2 Candidate features for future inclusion + +There are several under discussion, whether they all make it in is +partly a function of how much time everyone has to work on them: + +* improved file allocation (multi-block alloc, delayed alloc; basically done) +* fix 32000 subdirectory limit (patch exists, needs some e2fsck work) +* nsec timestamps for mtime, atime, ctime, create time (patch exists, + needs some e2fsck work) +* inode version field on disk (NFSv4, Lustre; prototype exists) +* reduced mke2fs/e2fsck time via uninitialized groups (prototype exists) +* journal checksumming for robustness, performance (prototype exists) +* persistent file preallocation (e.g for streaming media, databases) + +Features like metadata checksumming have been discussed and planned for +a bit but no patches exist yet so I'm not sure they're in the near-term +roadmap. + +The big performance win will come with mballoc and delalloc. CFS has +been using mballoc for a few years already with Lustre, and IBM + Bull +did a lot of benchmarking on it. The reason it isn't in the first set of +patches is partly a manageability issue, and partly because it doesn't +directly affect the on-disk format (outside of much better allocation) +so it isn't critical to get into the first round of changes. I believe +Alex is working on a new set of patches right now. + +3. Options +========== + +When mounting an ext4 filesystem, the following option are accepted: +(*) == default + +extents ext4 will use extents to address file data. The + file system will no longer be mountable by ext3. + +journal=update Update the ext4 file system's journal to the current + format. + +journal=inum When a journal already exists, this option is ignored. + Otherwise, it specifies the number of the inode which + will represent the ext4 file system's journal file. + +journal_dev=devnum When the external journal device's major/minor numbers + have changed, this option allows the user to specify + the new journal location. The journal device is + identified through its new major/minor numbers encoded + in devnum. + +noload Don't load the journal on mounting. + +data=journal All data are committed into the journal prior to being + written into the main file system. + +data=ordered (*) All data are forced directly out to the main file + system prior to its metadata being committed to the + journal. + +data=writeback Data ordering is not preserved, data may be written + into the main file system after its metadata has been + committed to the journal. + +commit=nrsec (*) Ext4 can be told to sync all its data and metadata + every 'nrsec' seconds. The default value is 5 seconds. + This means that if you lose your power, you will lose + as much as the latest 5 seconds of work (your + filesystem will not be damaged though, thanks to the + journaling). This default value (or any low value) + will hurt performance, but it's good for data-safety. + Setting it to 0 will have the same effect as leaving + it at the default (5 seconds). + Setting it to very large values will improve + performance. + +barrier=1 This enables/disables barriers. barrier=0 disables + it, barrier=1 enables it. + +orlov (*) This enables the new Orlov block allocator. It is + enabled by default. + +oldalloc This disables the Orlov block allocator and enables + the old block allocator. Orlov should have better + performance - we'd like to get some feedback if it's + the contrary for you. + +user_xattr Enables Extended User Attributes. Additionally, you + need to have extended attribute support enabled in the + kernel configuration (CONFIG_EXT4_FS_XATTR). See the + attr(5) manual page and http://acl.bestbits.at/ to + learn more about extended attributes. + +nouser_xattr Disables Extended User Attributes. + +acl Enables POSIX Access Control Lists support. + Additionally, you need to have ACL support enabled in + the kernel configuration (CONFIG_EXT4_FS_POSIX_ACL). + See the acl(5) manual page and http://acl.bestbits.at/ + for more information. + +noacl This option disables POSIX Access Control List + support. + +reservation + +noreservation + +bsddf (*) Make 'df' act like BSD. +minixdf Make 'df' act like Minix. + +check=none Don't do extra checking of bitmaps on mount. +nocheck + +debug Extra debugging information is sent to syslog. + +errors=remount-ro(*) Remount the filesystem read-only on an error. +errors=continue Keep going on a filesystem error. +errors=panic Panic and halt the machine if an error occurs. + +grpid Give objects the same group ID as their creator. +bsdgroups + +nogrpid (*) New objects have the group ID of their creator. +sysvgroups + +resgid=n The group ID which may use the reserved blocks. + +resuid=n The user ID which may use the reserved blocks. + +sb=n Use alternate superblock at this location. + +quota +noquota +grpquota +usrquota + +bh (*) ext4 associates buffer heads to data pages to +nobh (a) cache disk block mapping information + (b) link pages into transaction to provide + ordering guarantees. + "bh" option forces use of buffer heads. + "nobh" option tries to avoid associating buffer + heads (supported only for "writeback" mode). + + +Data Mode +--------- +There are 3 different data modes: + +* writeback mode +In data=writeback mode, ext4 does not journal data at all. This mode provides +a similar level of journaling as that of XFS, JFS, and ReiserFS in its default +mode - metadata journaling. A crash+recovery can cause incorrect data to +appear in files which were written shortly before the crash. This mode will +typically provide the best ext4 performance. + +* ordered mode +In data=ordered mode, ext4 only officially journals metadata, but it logically +groups metadata and data blocks into a single unit called a transaction. When +it's time to write the new metadata out to disk, the associated data blocks +are written first. In general, this mode performs slightly slower than +writeback but significantly faster than journal mode. + +* journal mode +data=journal mode provides full data and metadata journaling. All new data is +written to the journal first, and then to its final location. +In the event of a crash, the journal can be replayed, bringing both data and +metadata into a consistent state. This mode is the slowest except when data +needs to be read from and written to disk at the same time where it +outperforms all others modes. + +References +========== + +kernel source: + + +programs: http://e2fsprogs.sourceforge.net/ + http://ext2resize.sourceforge.net + +useful links: http://fedoraproject.org/wiki/ext3-devel + http://www.bullopensource.org/ext4/ -- GitLab From 469340236a7c9673df3e6a2425f559517f01464e Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 11 Oct 2006 01:21:26 -0700 Subject: [PATCH 1006/1619] [PATCH] mm: kevent threads: use MPOL_DEFAULT Switch the memory policy of the kevent threads to MPOL_DEFAULT while leaving the kzalloc of the workqueue structure on interleave. This means that all code executed in the context of the kevent thread is allocating node local. Signed-off-by: Christoph Lameter Cc: Christoph Lameter Cc: Alok Kataria Cc: Andi Kleen Cc: Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/workqueue.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index cfc737bffe6..3df9bfc7ff7 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -28,6 +28,7 @@ #include #include #include +#include /* * The per-CPU workqueue (if single thread, we always use the first @@ -245,6 +246,12 @@ static int worker_thread(void *__cwq) sigprocmask(SIG_BLOCK, &blocked, NULL); flush_signals(current); + /* + * We inherited MPOL_INTERLEAVE from the booting kernel. + * Set MPOL_DEFAULT to insure node local allocations. + */ + numa_default_policy(); + /* SIG_IGN makes children autoreap: see do_notify_parent(). */ sa.sa.sa_handler = SIG_IGN; sa.sa.sa_flags = 0; -- GitLab From b16bc64d1aed40fb9cff9187061005b2a89b5d5d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 11 Oct 2006 01:21:27 -0700 Subject: [PATCH 1007/1619] [PATCH] move rmap BUG_ON outside DEBUG_VM We have a persistent dribble of reports of this BUG triggering. Its extended diagnostics were recently made conditional on CONFIG_DEBUG_VM, which was a bad idea - we want to know about it. Signed-off-by: Dave Jones Cc: Nick Piggin Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/rmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index e2155d791d9..a9136d8b757 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -576,15 +576,14 @@ void page_add_file_rmap(struct page *page) void page_remove_rmap(struct page *page) { if (atomic_add_negative(-1, &page->_mapcount)) { -#ifdef CONFIG_DEBUG_VM if (unlikely(page_mapcount(page) < 0)) { printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page)); printk (KERN_EMERG " page->flags = %lx\n", page->flags); printk (KERN_EMERG " page->count = %x\n", page_count(page)); printk (KERN_EMERG " page->mapping = %p\n", page->mapping); + BUG(); } -#endif - BUG_ON(page_mapcount(page) < 0); + /* * It would be tidy to reset the PageAnon mapping here, * but that might overwrite a racing page_add_anon_rmap -- GitLab From 699397499742d1245ea5d677a08fa265df666d2d Mon Sep 17 00:00:00 2001 From: Keith Owens Date: Wed, 11 Oct 2006 01:21:28 -0700 Subject: [PATCH 1008/1619] [PATCH] Fix do_mbind warning with CONFIG_MIGRATION=n With CONFIG_MIGRATION=n mm/mempolicy.c: In function 'do_mbind': mm/mempolicy.c:796: warning: passing argument 2 of 'migrate_pages' from incompatible pointer type Signed-off-by: Keith Owens Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 25788b1b7fc..617fb31086e 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -727,7 +727,7 @@ int do_migrate_pages(struct mm_struct *mm, return -ENOSYS; } -static struct page *new_vma_page(struct page *page, unsigned long private) +static struct page *new_vma_page(struct page *page, unsigned long private, int **x) { return NULL; } -- GitLab From dafb13673c463bc2aade4a4819704dde0f5fa37f Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 11 Oct 2006 01:21:30 -0700 Subject: [PATCH 1009/1619] [PATCH] mm: arch_free_page fix After the PG_reserved check was added, arch_free_page was being called in the wrong place (it could be called for a page we don't actually want to free). Fix that. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8246e834b2f..c5caac2c3c5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -495,7 +495,6 @@ static void __free_pages_ok(struct page *page, unsigned int order) int i; int reserved = 0; - arch_free_page(page, order); if (!PageHighMem(page)) debug_check_no_locks_freed(page_address(page), PAGE_SIZE<mapping = NULL; if (free_pages_check(page)) return; + arch_free_page(page, 0); kernel_map_pages(page, 1, 0); pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; -- GitLab From 9858db504caedb2424b9a32744c23f9a81ec1731 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 11 Oct 2006 01:21:30 -0700 Subject: [PATCH 1010/1619] [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(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 26146623be2..5a6068ff555 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 c5caac2c3c5..40db96a655d 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:31 -0700 Subject: [PATCH 1011/1619] [PATCH] uml: revert wrong patch Andi Kleen pointed out that -mcmodel=kernel does not make sense for userspace code and would stop everything from working, and pointed out the correct fix for the original bug (not easy to do for me). Reverts part of commit 06837504de7b4883e92af207dbbab4310d0db0ed. Cc: Andi Kleen Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Makefile-x86_64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 11154b6773e..87d63737eb7 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -4,7 +4,7 @@ core-y += arch/um/sys-x86_64/ START := 0x60000000 -_extra_flags_ = -fno-builtin -m64 -mcmodel=kernel +_extra_flags_ = -fno-builtin -m64 #We #undef __x86_64__ for kernelspace, not for userspace where #it's needed for headers to work! -- GitLab From 21c935e5298a3bc4f16cdff7ce3b1efab92b995e Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:32 -0700 Subject: [PATCH 1012/1619] [PATCH] uml: correct removal of pte_mkexec Correct commit 5906e4171ad61ce68de95e51b773146707671f80 - this makes more sense: we turn pte_mkexec + pte_wrprotect to pte_mkread. However, due to a bug in pte_mkread, it does the exact same thing as pte_mkwrite, so this patch improves the code but does not change anything in practice. The pte_mkread bug is fixed separately, as it may have big impact. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/skas/mmu.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index c17eddcf89b..2c6d090a2e8 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -60,10 +60,7 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, #endif *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); - /* This is wrong for the code page, but it doesn't matter since the - * stub is mapped by hand with the correct permissions. - */ - *pte = pte_mkwrite(*pte); + *pte = pte_mkread(*pte); return(0); out_pmd: -- GitLab From e27e80b3da7ad6b90185bd689879888907104a40 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:33 -0700 Subject: [PATCH 1013/1619] [PATCH] uml: readd forgot prototype This was forgot in a previous patch so UML does not compile with TT mode enabled. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/os.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 120ca21a513..6516f6dca96 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -201,6 +201,7 @@ extern int os_getpgrp(void); #ifdef UML_CONFIG_MODE_TT extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); +extern void stop(void); #endif extern void init_new_thread_signals(void); extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); -- GitLab From d875f9fd3f2369bf6f4d0e9989f00fe610eac470 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:34 -0700 Subject: [PATCH 1014/1619] [PATCH] uml: make TT mode compile after setjmp-related changes Make TT mode compile after the introduction of klibc's implementation of setjmp. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/tt/uaccess_user.c | 6 +++--- arch/um/os-Linux/tt.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index 6c92bbccb49..ed1abcf4d05 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -4,13 +4,13 @@ * Licensed under the GPL */ -#include #include #include "user_util.h" #include "uml_uaccess.h" #include "task.h" #include "kern_util.h" #include "os.h" +#include "longjmp.h" int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher) @@ -80,10 +80,10 @@ int __do_strnlen_user(const char *str, unsigned long n, struct tt_regs save = TASK_REGS(get_current())->tt; int ret; unsigned long *faddrp = (unsigned long *)fault_addr; - sigjmp_buf jbuf; + jmp_buf jbuf; *fault_catcher = &jbuf; - if(sigsetjmp(jbuf, 1) == 0) + if(UML_SETJMP(&jbuf) == 0) ret = strlen(str) + 1; else ret = *faddrp - (unsigned long) str; diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index 5461a065bbb..3dc3a02d626 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- GitLab From b5cdb5797d364a112879e49cc708083853ffc592 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:34 -0700 Subject: [PATCH 1015/1619] [PATCH] uml: make UML_SETJMP always safe If enable is moved by GCC in a register its value may not be preserved after coming back there with longjmp(). So, mark it as volatile to prevent this; this is suggested (it seems) in info gcc, when it talks about -Wuninitialized. I re-read this and it seems to say something different, but I still believe this may be needed. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/longjmp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h index e93c6d3e893..e860bc5848e 100644 --- a/arch/um/include/longjmp.h +++ b/arch/um/include/longjmp.h @@ -12,7 +12,8 @@ extern void longjmp(jmp_buf, int); } while(0) #define UML_SETJMP(buf) ({ \ - int n, enable; \ + int n; \ + volatile int enable; \ enable = get_signals(); \ n = setjmp(*buf); \ if(n != 0) \ -- GitLab From 1b4ad242fcfcf1e261604cb91ee5fb8032900997 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:35 -0700 Subject: [PATCH 1016/1619] [PATCH] uml: fix processor selection to exclude unsupported processors and features Makes UML compile on any possible processor choice. The two problems were: *) x86 code, when 386 is selected, checks at runtime boot_cpuflags, which we do not have. *) 3Dnow support for memcpy() et al. does not compile currently and fixing this is not trivial, so simply disable it; with this change, if one selects MK7 UML compiles (while it did not). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/Kconfig.cpu | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu index 21c9a4e7110..fc4f2abccf0 100644 --- a/arch/i386/Kconfig.cpu +++ b/arch/i386/Kconfig.cpu @@ -7,6 +7,7 @@ choice config M386 bool "386" + depends on !UML ---help--- This is the processor type of your CPU. This information is used for optimizing purposes. In order to compile a kernel that can run on @@ -301,7 +302,7 @@ config X86_USE_PPRO_CHECKSUM config X86_USE_3DNOW bool - depends on MCYRIXIII || MK7 || MGEODE_LX + depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML default y config X86_OOSTORE -- GitLab From 69fada32d868d7f4be128ea4df8fbe4fd897fc34 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:36 -0700 Subject: [PATCH 1017/1619] [PATCH] uml: fix uname under setarch i386 On a 64bit Uml, if run under "setarch i386" (which a user did), uname() currently returns the obtained i686 as machine - fix that. Btw, I'm quite surprised that under setarch i386 a 64-bit binary can run. Cc: Andi Kleen Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/util.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 3f5b1514e8a..56b8a50e8bc 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -80,11 +80,18 @@ void setup_machinename(char *machine_out) struct utsname host; uname(&host); -#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT) +#ifdef UML_CONFIG_UML_X86 +# ifndef UML_CONFIG_64BIT if (!strcmp(host.machine, "x86_64")) { strcpy(machine_out, "i686"); return; } +# else + if (!strcmp(host.machine, "i686")) { + strcpy(machine_out, "x86_64"); + return; + } +# endif #endif strcpy(machine_out, host.machine); } -- GitLab From 711553efa5b8581365084cacf3585a36ca253bab Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:37 -0700 Subject: [PATCH 1018/1619] [PATCH] uml: declare in Kconfig our partial LOCKDEP support Declare UML partial support for LOCKDEP - however IRQFLAGS tracing requires some coding which nobody did yet, so we cannot run full lockdep on UML. Grep for CONFIG_TRACE_IRQFLAGS on i386 code to find their implementation. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index d75307589d7..450547a4b3b 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -25,6 +25,19 @@ config PCI config PCMCIA bool +# Yet to do! +config TRACE_IRQFLAGS_SUPPORT + bool + default n + +config LOCKDEP_SUPPORT + bool + default y + +config STACKTRACE_SUPPORT + bool + default y + config GENERIC_CALIBRATE_DELAY bool default y -- GitLab From 2465b8580a5649ee789f213d39c1b49d84fefe8f Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:38 -0700 Subject: [PATCH 1019/1619] [PATCH] uml: allow using again x86/x86_64 crypto code Enable compilation of x86_64 crypto code;, and add the needed constant to make the code compile again (that macro was added to i386 asm-offsets between 2.6.17 and 2.6.18, in 6c2bb98bc33ae33c7a33a133a4cd5a06395fece5). Cc: Herbert Xu Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Makefile-x86_64 | 2 +- arch/um/include/common-offsets.h | 1 + arch/um/include/sysdep-i386/kernel-offsets.h | 1 + arch/um/include/sysdep-x86_64/kernel-offsets.h | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 87d63737eb7..d278682dd79 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -1,7 +1,7 @@ # Copyright 2003 - 2004 Pathscale, Inc # Released under the GPL -core-y += arch/um/sys-x86_64/ +core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/ START := 0x60000000 _extra_flags_ = -fno-builtin -m64 diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 356390d1f8b..39bb2107862 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -15,3 +15,4 @@ DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); DEFINE(UM_ELF_CLASS, ELF_CLASS); DEFINE(UM_ELFCLASS32, ELFCLASS32); DEFINE(UM_ELFCLASS64, ELFCLASS64); +DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); diff --git a/arch/um/include/sysdep-i386/kernel-offsets.h b/arch/um/include/sysdep-i386/kernel-offsets.h index 2c13de321f2..2e58c4c6ebf 100644 --- a/arch/um/include/sysdep-i386/kernel-offsets.h +++ b/arch/um/include/sysdep-i386/kernel-offsets.h @@ -1,6 +1,7 @@ #include #include #include +#include #include #define DEFINE(sym, val) \ diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h index 91d129fb393..4cbfbb9d426 100644 --- a/arch/um/include/sysdep-x86_64/kernel-offsets.h +++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include -- GitLab From d27ecef7c63064c1f2eadf413e694e65a34f1f79 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:40 -0700 Subject: [PATCH 1020/1619] [PATCH] uml: asm offsets duplication removal Unify macros common to x86 and x86_64 kernel-offsets.h files. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/common-offsets.h | 10 ++++++++++ arch/um/include/sysdep-i386/kernel-offsets.h | 4 ---- arch/um/include/sysdep-x86_64/kernel-offsets.h | 4 ---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 39bb2107862..461175f8b1d 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -1,9 +1,16 @@ /* for use by sys-$SUBARCH/kernel-offsets.c */ +DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); +#ifdef CONFIG_MODE_TT +OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid); +#endif + OFFSET(HOST_TASK_REGS, task_struct, thread.regs); OFFSET(HOST_TASK_PID, task_struct, pid); + DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); + DEFINE_STR(UM_KERN_EMERG, KERN_EMERG); DEFINE_STR(UM_KERN_ALERT, KERN_ALERT); DEFINE_STR(UM_KERN_CRIT, KERN_CRIT); @@ -12,7 +19,10 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING); DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE); DEFINE_STR(UM_KERN_INFO, KERN_INFO); DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); + DEFINE(UM_ELF_CLASS, ELF_CLASS); DEFINE(UM_ELFCLASS32, ELFCLASS32); DEFINE(UM_ELFCLASS64, ELFCLASS64); + +/* For crypto assembler code. */ DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); diff --git a/arch/um/include/sysdep-i386/kernel-offsets.h b/arch/um/include/sysdep-i386/kernel-offsets.h index 2e58c4c6ebf..97ec9d894d7 100644 --- a/arch/um/include/sysdep-i386/kernel-offsets.h +++ b/arch/um/include/sysdep-i386/kernel-offsets.h @@ -18,9 +18,5 @@ void foo(void) { OFFSET(HOST_TASK_DEBUGREGS, task_struct, thread.arch.debugregs); - DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); -#ifdef CONFIG_MODE_TT - OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid); -#endif #include } diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h index 4cbfbb9d426..a307237b796 100644 --- a/arch/um/include/sysdep-x86_64/kernel-offsets.h +++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h @@ -19,9 +19,5 @@ void foo(void) { - DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); -#ifdef CONFIG_MODE_TT - OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid); -#endif #include } -- GitLab From f2d57151bd3110ae3f0db3e5770ab1a46d1b647a Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:40 -0700 Subject: [PATCH 1021/1619] [PATCH] uml: remove duplicate export The export is together with the definition, in arch/x86_64/lib/csum-partial.c, which is compiled in by arch/um/sys-x86_64/Makefile. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/sys-x86_64/ksyms.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c index 85927380820..12c593607c5 100644 --- a/arch/um/sys-x86_64/ksyms.c +++ b/arch/um/sys-x86_64/ksyms.c @@ -14,6 +14,3 @@ EXPORT_SYMBOL(__up_wakeup); /*XXX: we need them because they would be exported by x86_64 */ EXPORT_SYMBOL(__memcpy); - -/* Networking helper routines. */ -EXPORT_SYMBOL(ip_compute_csum); -- GitLab From ca316fcf641532ee70dfc59daf632d1685b7d902 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:41 -0700 Subject: [PATCH 1022/1619] [PATCH] uml: deprecate CONFIG_MODE_TT Deprecate TT mode in Kconfig so that users won't select it, update the MODE_SKAS description (it was largely obsolete and misleadin) and btw describe advantages for high memory usage with CONFIG_STATIC_LINK. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 450547a4b3b..78fb619bdb7 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -50,13 +50,15 @@ config IRQ_RELEASE_METHOD menu "UML-specific options" config MODE_TT - bool "Tracing thread support" + bool "Tracing thread support (DEPRECATED)" default n help This option controls whether tracing thread support is compiled - into UML. This option is largely obsolete, given that skas0 provides + into UML. This option is largely obsolete, given that skas0 provides skas security and performance without needing to patch the host. - It is safe to say 'N' here. + It is safe to say 'N' here; saying 'Y' may cause additional problems + with the resulting binary even if you run UML in SKAS mode, and running + in TT mode is strongly *NOT RECOMMENDED*. config STATIC_LINK bool "Force a static link" @@ -69,6 +71,9 @@ config STATIC_LINK for use in a chroot jail. So, if you intend to run UML inside a chroot, and you disable CONFIG_MODE_TT, you probably want to say Y here. + Additionally, this option enables using higher memory spaces (up to + 2.75G) for UML - disabling CONFIG_MODE_TT and enabling this option leads + to best results for this. config KERNEL_HALF_GIGS int "Kernel address space size (in .5G units)" @@ -85,10 +90,13 @@ config MODE_SKAS default y help This option controls whether skas (separate kernel address space) - support is compiled in. If you have applied the skas patch to the - host, then you certainly want to say Y here (and consider saying N - to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this - option will shrink the UML binary slightly. + support is compiled in. + Unless you have specific needs to use TT mode (which applies almost only + to developers), you should say Y here. + SKAS mode will make use of the SKAS3 patch if it is applied on the host + (and your UML will run in SKAS3 mode), but if no SKAS patch is applied + on the host it will run in SKAS0 mode, which is anyway faster than TT + mode. source "arch/um/Kconfig.arch" source "mm/Kconfig" -- GitLab From c21be1c9c1ab42fe285a74f184e1acbc37ee084b Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Wed, 11 Oct 2006 01:21:42 -0700 Subject: [PATCH 1023/1619] [PATCH] uml: allow finer tuning for host VMSPLIT setting Now that various memory splits are enabled, add a config option allowing the user to compile UML for its need - HOST_2G_2G allowed to choose either 3G/1G or 2G/2G, and enabling it reduced the usable virtual memory. Detecting this at run time should be implemented in the future, but we must make the stop-gap measure work well enough (this is valid in _many_ cases). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig.i386 | 49 ++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 index f6eb72d117b..f191a550a07 100644 --- a/arch/um/Kconfig.i386 +++ b/arch/um/Kconfig.i386 @@ -16,23 +16,42 @@ config SEMAPHORE_SLEEPERS bool default y -config HOST_2G_2G - bool "2G/2G host address space split" - default n - help - This is needed when the host on which you run has a 2G/2G memory - split, instead of the customary 3G/1G. - - Note that to enable such a host - configuration, which makes sense only in some cases, you need special - host patches. - - So, if you do not know what to do here, say 'N'. +choice + prompt "Host memory split" + default HOST_VMSPLIT_3G + ---help--- + This is needed when the host kernel on which you run has a non-default + (like 2G/2G) memory split, instead of the customary 3G/1G. If you did + not recompile your own kernel but use the default distro's one, you can + safely accept the "Default split" option. + + It can be enabled on recent (>=2.6.16-rc2) vanilla kernels via + CONFIG_VM_SPLIT_*, or on previous kernels with special patches (-ck + patchset by Con Kolivas, or other ones) - option names match closely the + host CONFIG_VM_SPLIT_* ones. + + A lower setting (where 1G/3G is lowest and 3G/1G is higher) will + tolerate even more "normal" host kernels, but an higher setting will be + stricter. + + So, if you do not know what to do here, say 'Default split'. + + config HOST_VMSPLIT_3G + bool "Default split (3G/1G user/kernel host split)" + config HOST_VMSPLIT_3G_OPT + bool "3G/1G user/kernel host split (for full 1G low memory)" + config HOST_VMSPLIT_2G + bool "2G/2G user/kernel host split" + config HOST_VMSPLIT_1G + bool "1G/3G user/kernel host split" +endchoice config TOP_ADDR - hex - default 0xc0000000 if !HOST_2G_2G - default 0x80000000 if HOST_2G_2G + hex + default 0xB0000000 if HOST_VMSPLIT_3G_OPT + default 0x78000000 if HOST_VMSPLIT_2G + default 0x40000000 if HOST_VMSPLIT_1G + default 0xC0000000 config 3_LEVEL_PGTABLES bool "Three-level pagetables (EXPERIMENTAL)" -- GitLab From 0f836e5fecf59d0d0353e9af11fd14a32a3001ae Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 11 Oct 2006 01:21:43 -0700 Subject: [PATCH 1024/1619] [PATCH] Add CONFIG_HEADERS_CHECK option to automatically run 'make headers_check' In order to encourage people to notice when they break the exported headers, add a config option which automatically runs the sanity checks when building vmlinux. That way, those who use allyesconfig will notice failures. Signed-off-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Makefile | 3 +++ lib/Kconfig.debug | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Makefile b/Makefile index 274b780029b..f242829c4f0 100644 --- a/Makefile +++ b/Makefile @@ -741,6 +741,9 @@ endif # ifdef CONFIG_KALLSYMS # vmlinux image - including updated kernel symbols vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE +ifdef CONFIG_HEADERS_CHECK + $(Q)$(MAKE) headers_check +endif $(call if_changed_rule,vmlinux__) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@ $(Q)rm -f .old_version diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2d7cb0d04fc..8fd2dbf7eb5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -371,6 +371,19 @@ config FORCED_INLINING become the default in the future, until then this option is there to test gcc for this. +config HEADERS_CHECK + bool "Run 'make headers_check' when building vmlinux" + help + This option will extract the user-visible kernel headers whenever + building the kernel, and will run basic sanity checks on them to + ensure that exported files do not attempt to include files which + were not exported, etc. + + If you're making modifications to header files which are + relevant for userspace, say 'Y', and check the headers + exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in + your build tree), to make sure they're suitable. + config RCU_TORTURE_TEST tristate "torture tests for RCU" depends on DEBUG_KERNEL -- GitLab From b611967de4dc5c52049676c4369dcac622a7cdfe Mon Sep 17 00:00:00 2001 From: Davide Libenzi Date: Wed, 11 Oct 2006 01:21:44 -0700 Subject: [PATCH 1025/1619] [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(-) diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 7e639f78b0b..2697e9210e9 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 557d5b614fa..ae228ec54e9 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 3ca7ab963d7..beeeaf6b054 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 b0ace3fd7eb..1912c6cbef5 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); -- GitLab From e0ab2928cc2202f13f0574d4c6f567f166d307eb Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 11 Oct 2006 01:21:45 -0700 Subject: [PATCH 1026/1619] [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 diff --git a/include/linux/carta_random32.h b/include/linux/carta_random32.h new file mode 100644 index 00000000000..f6f3bd9f20b --- /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 8e6662bb9c3..59070dbfbeb 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 00000000000..ca82df70eee --- /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); -- GitLab From e5657933863f43cc6bb76a54d659303dafaa9e58 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:46 -0700 Subject: [PATCH 1027/1619] [PATCH] grow_buffers() infinite loop fix If grow_buffers() is for some reason passed a block number which wants to lie outside the maximum-addressable pagecache range (PAGE_SIZE * 4G bytes) then it will accidentally truncate `index' and will then instnatiate a page at the wrong pagecache offset. This causes __getblk_slow() to go into an infinite loop. This can happen with corrupted disks, or with software errors elsewhere. Detect that, and handle it. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index eeb8ac1aa85..2a7828c0e59 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1042,8 +1042,21 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) } while ((size << sizebits) < PAGE_SIZE); index = block >> sizebits; - block = index << sizebits; + /* + * Check for a block which wants to lie outside our maximum possible + * pagecache index. (this comparison is done using sector_t types). + */ + if (unlikely(index != block >> sizebits)) { + char b[BDEVNAME_SIZE]; + + printk(KERN_ERR "%s: requested out-of-range block %llu for " + "device %s\n", + __FUNCTION__, (unsigned long long)block, + bdevname(bdev, b)); + return -EIO; + } + block = index << sizebits; /* Create a page with the proper size buffers.. */ page = grow_dev_page(bdev, block, index, size); if (!page) @@ -1070,12 +1083,16 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) for (;;) { struct buffer_head * bh; + int ret; bh = __find_get_block(bdev, block, size); if (bh) return bh; - if (!grow_buffers(bdev, block, size)) + ret = grow_buffers(bdev, block, size); + if (ret < 0) + return NULL; + if (ret == 0) free_more_memory(); } } -- GitLab From 3719bc5c22c9025bf1c909fe8b527ebf1de9a153 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 11 Oct 2006 01:21:47 -0700 Subject: [PATCH 1028/1619] [PATCH] ide-generic: jmicron fix Some people find their Jmicron pata port reports its disabled even though it has devices on it and was boot probed. Fix this (Candidate for 2.6.18.*, less so for 2.6.19 as we've got a proper jmicron driver on the merge for that to replace ide-generic support) Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/pci/generic.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 965c43659e3..5b77a5bcbf0 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -237,10 +237,12 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1) goto out; - pci_read_config_word(dev, PCI_COMMAND, &command); - if (!(command & PCI_COMMAND_IO)) { - printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); - goto out; + if (dev->vendor != PCI_VENDOR_ID_JMICRON) { + pci_read_config_word(dev, PCI_COMMAND, &command); + if (!(command & PCI_COMMAND_IO)) { + printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); + goto out; + } } ret = ide_setup_pci_device(dev, d); out: -- GitLab From fa3ba2e81ea23416272a22009bba95954c81969c Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Wed, 11 Oct 2006 01:21:48 -0700 Subject: [PATCH 1029/1619] [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(-) diff --git a/include/linux/module.h b/include/linux/module.h index 4b2d8091a41..d1d00ce8f4e 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 7f60e782de1..67009bd56c5 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) { -- GitLab From 2245d7c21f5bb1f104ee1226ebcb3dd5b9acfff6 Mon Sep 17 00:00:00 2001 From: Dmitry Mishin Date: Wed, 11 Oct 2006 01:21:49 -0700 Subject: [PATCH 1030/1619] [PATCH] ext3: errors behaviour fix Current error behaviour for ext2 and ext3 filesystems does not fully correspond to the documentation and should be fixed. According to man 8 mount, ext2 and ext3 file systems allow to set one of 3 different on-errors behaviours: ---- start of quote man 8 mount ---- errors=continue / errors=remount-ro / errors=panic Define the behaviour when an error is encountered. (Either ignore errors and just mark the file system erroneous and continue, or remount the file system read-only, or panic and halt the system.) The default is set in the filesystem superblock, and can be changed using tune2fs(8). ---- end of quote ---- However EXT3_ERRORS_CONTINUE is not read from the superblock, and thus ERRORS_CONT is not saved on the sbi->s_mount_opt. It leads to the incorrect handle of errors on ext3. Then we've checked corresponding code in ext2 and discovered that it is buggy as well: - EXT2_ERRORS_CONTINUE is not read from the superblock (the same); - parse_option() does not clean the alternative values and thus something like (ERRORS_CONT|ERRORS_RO) can be set; - if options are omitted, parse_option() does not set any of these options. Therefore it is possible to set any combination of these options on the ext2: - none of them may be set: EXT2_ERRORS_CONTINUE on superblock / empty mount options; - any of them may be set using mount options; - 2 any options may be set: by using EXT2_ERRORS_RO/EXT2_ERRORS_PANIC on the superblock and other value in mount options; - and finally all three options may be set by adding third option in remount. Currently ext2 uses these values only in ext2_error() and it is not leading to any noticeable troubles. However somebody may be discouraged when he will try to workaround EXT2_ERRORS_PANIC on the superblock by using errors=continue in mount options. This patch: EXT3_ERRORS_CONTINUE should be taken from the superblock as default value for error behaviour. Signed-off-by: Dmitry Mishin Acked-by: Vasily Averin Acked-by: Kirill Korotaev Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 8bfd56ef18c..afc2d4f42d7 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1470,6 +1470,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) 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); + else + set_opt(sbi->s_mount_opt, ERRORS_CONT); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); -- GitLab From 5a2b4062f5adf2218b9b021e1c33f374bf142cb2 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Wed, 11 Oct 2006 01:21:50 -0700 Subject: [PATCH 1031/1619] [PATCH] ext2: errors behaviour fix Current error behaviour for ext2 and ext3 filesystems does not fully correspond to the documentation and should be fixed. According to man 8 mount, ext2 and ext3 file systems allow to set one of 3 different on-errors behaviours: ---- start of quote man 8 mount ---- errors=continue / errors=remount-ro / errors=panic Define the behaviour when an error is encountered. (Either ignore errors and just mark the file system erroneous and continue, or remount the file system read-only, or panic and halt the system.) The default is set in the filesystem superblock, and can be changed using tune2fs(8). ---- end of quote ---- However EXT3_ERRORS_CONTINUE is not read from the superblock, and thus ERRORS_CONT is not saved on the sbi->s_mount_opt. It leads to the incorrect handle of errors on ext3. Then we've checked corresponding code in ext2 and discovered that it is buggy as well: - EXT2_ERRORS_CONTINUE is not read from the superblock (the same); - parse_option() does not clean the alternative values and thus something like (ERRORS_CONT|ERRORS_RO) can be set; - if options are omitted, parse_option() does not set any of these options. Therefore it is possible to set any combination of these options on the ext2: - none of them may be set: EXT2_ERRORS_CONTINUE on superblock / empty mount options; - any of them may be set using mount options; - 2 any options may be set: by using EXT2_ERRORS_RO/EXT2_ERRORS_PANIC on the superblock and other value in mount options; - and finally all three options may be set by adding third option in remount. Currently ext2 uses these values only in ext2_error() and it is not leading to any noticeable troubles. However somebody may be discouraged when he will try to workaround EXT2_ERRORS_PANIC on the superblock by using errors=continue in mount options. This patch: EXT2_ERRORS_CONTINUE should be read from the superblock as default value for error behaviour. parse_option() should clean the alternative options and should not change default value taken from the superblock. Signed-off-by: Vasily Averin Acked-by: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext2/super.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 513cd421ac0..d8b9abd95d0 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -364,7 +364,6 @@ static int parse_options (char * options, { char * p; substring_t args[MAX_OPT_ARGS]; - unsigned long kind = EXT2_MOUNT_ERRORS_CONT; int option; if (!options) @@ -404,13 +403,19 @@ static int parse_options (char * options, /* *sb_block = match_int(&args[0]); */ break; case Opt_err_panic: - kind = EXT2_MOUNT_ERRORS_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: - kind = EXT2_MOUNT_ERRORS_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: - kind = EXT2_MOUNT_ERRORS_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); @@ -489,7 +494,6 @@ static int parse_options (char * options, return 0; } } - sbi->s_mount_opt |= kind; return 1; } @@ -715,6 +719,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, ERRORS_PANIC); else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO) set_opt(sbi->s_mount_opt, ERRORS_RO); + else + set_opt(sbi->s_mount_opt, ERRORS_CONT); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); -- GitLab From f33d9bd50478c9a969b65f58feb6b69a3ad478cb Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:21:51 -0700 Subject: [PATCH 1032/1619] [PATCH] tpm: fix error handling - handle sysfs error - handle driver model errors - de-obfuscate platform_device_register_simple() call, which included an assignment in between two function calls, in the same C statement. Signed-off-by: Jeff Garzik Acked-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 9 ++++++++- drivers/char/tpm/tpm_atmel.c | 10 +++++----- drivers/char/tpm/tpm_nsc.c | 6 ++++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index a082a2e3425..6ad2d3bb945 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1153,7 +1153,14 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend spin_unlock(&driver_lock); - sysfs_create_group(&dev->kobj, chip->vendor.attr_group); + if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { + list_del(&chip->list); + put_device(dev); + clear_bit(chip->dev_num, dev_mask); + kfree(chip); + kfree(devname); + return NULL; + } chip->bios_dir = tpm_bios_log_setup(devname); diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index ad8ffe49256..1ab0896070b 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -184,7 +184,9 @@ static int __init init_atmel(void) unsigned long base; struct tpm_chip *chip; - driver_register(&atml_drv); + rc = driver_register(&atml_drv); + if (rc) + return rc; if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { rc = -ENODEV; @@ -195,10 +197,8 @@ static int __init init_atmel(void) (atmel_request_region (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; - - if (IS_ERR - (pdev = - platform_device_register_simple("tpm_atmel", -1, NULL, 0))) { + pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0); + if (IS_ERR(pdev)) { rc = PTR_ERR(pdev); goto err_rel_reg; } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 26287aace87..608f73071be 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -284,7 +284,7 @@ static struct device_driver nsc_drv = { static int __init init_nsc(void) { int rc = 0; - int lo, hi; + int lo, hi, err; int nscAddrBase = TPM_ADDR; struct tpm_chip *chip; unsigned long base; @@ -297,7 +297,9 @@ static int __init init_nsc(void) return -ENODEV; } - driver_register(&nsc_drv); + err = driver_register(&nsc_drv); + if (err) + return err; hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); -- GitLab From beed33a816204cb402c69266475b6a60a2433ceb Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 11 Oct 2006 01:21:52 -0700 Subject: [PATCH 1033/1619] [PATCH] sched: likely profiling This likely profiling is pretty fun. I found a few possible problems in sched.c. This patch may be not measurable, but when I did measure long ago, nooping (un)likely cost a couple of % on scheduler heavy benchmarks, so it all adds up. Tweak some branch hints: - the 2nd 64 bits in the bitmask is likely to be populated, because it contains the first 28 bits (nearly 3/4) of the normal priorities. (ratio of 669669:691 ~= 1000:1). - it isn't unlikely that context switching switches to another process. it might be very rapidly switching to and from the idle process (ratio of 475815:419004 and 471330:423544). Let the branch predictor decide. - preempt_enable seems to be very often called in a nested preempt_disable or with interrupts disabled (ratio of 3567760:87965 ~= 40:1) Signed-off-by: Nick Piggin Acked-by: Ingo Molnar Cc: Daniel Walker Cc: Hua Zhong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/bitops/sched.h | 2 +- kernel/sched.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-generic/bitops/sched.h b/include/asm-generic/bitops/sched.h index 5ef93a4d009..815bb014806 100644 --- a/include/asm-generic/bitops/sched.h +++ b/include/asm-generic/bitops/sched.h @@ -15,7 +15,7 @@ static inline int sched_find_first_bit(const unsigned long *b) #if BITS_PER_LONG == 64 if (unlikely(b[0])) return __ffs(b[0]); - if (unlikely(b[1])) + if (likely(b[1])) return __ffs(b[1]) + 64; return __ffs(b[2]) + 128; #elif BITS_PER_LONG == 32 diff --git a/kernel/sched.c b/kernel/sched.c index 53608a59d6e..094b5687eef 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1822,14 +1822,14 @@ context_switch(struct rq *rq, struct task_struct *prev, struct mm_struct *mm = next->mm; struct mm_struct *oldmm = prev->active_mm; - if (unlikely(!mm)) { + if (!mm) { next->active_mm = oldmm; atomic_inc(&oldmm->mm_count); enter_lazy_tlb(oldmm, next); } else switch_mm(oldmm, mm, next); - if (unlikely(!prev->mm)) { + if (!prev->mm) { prev->active_mm = NULL; WARN_ON(rq->prev_mm); rq->prev_mm = oldmm; @@ -3491,7 +3491,7 @@ asmlinkage void __sched preempt_schedule(void) * If there is a non-zero preempt_count or interrupts are disabled, * we do not want to preempt the current task. Just return.. */ - if (unlikely(ti->preempt_count || irqs_disabled())) + if (likely(ti->preempt_count || irqs_disabled())) return; need_resched: -- GitLab From 8258d4a574d3a8c01f0ef68aa26b969398a0e140 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:53 -0700 Subject: [PATCH 1034/1619] [PATCH] invalidate_inode_pages2_range() debug A failure in invalidate_inode_pages2_range() can result in unpleasant things happening in NFS (at least). Stick a WARN_ON_ONCE() in there so we can find out if it happens, and maybe why. (akpm: might be a -mm-only patch, we'll see..) Cc: Chuck Lever Cc: Trond Myklebust Cc: Steve Dickson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/truncate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/truncate.c b/mm/truncate.c index f4edbc179d1..fca28839c46 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -396,6 +396,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping, pagevec_release(&pvec); cond_resched(); } + WARN_ON_ONCE(ret); return ret; } EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range); -- GitLab From 2e3ad8af43c2f555c1be6c02581f6cc939dcb71c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:21:53 -0700 Subject: [PATCH 1035/1619] [PATCH] x86/microcode: handle sysfs error Signed-off-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/microcode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 9b9479768d5..c4d0291b519 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -656,14 +656,18 @@ static struct attribute_group mc_attr_group = { static int mc_sysdev_add(struct sys_device *sys_dev) { - int cpu = sys_dev->id; + int err, cpu = sys_dev->id; struct ucode_cpu_info *uci = ucode_cpu_info + cpu; if (!cpu_online(cpu)) return 0; + pr_debug("Microcode:CPU %d added\n", cpu); memset(uci, 0, sizeof(*uci)); - sysfs_create_group(&sys_dev->kobj, &mc_attr_group); + + err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); + if (err) + return err; microcode_init_cpu(cpu); return 0; -- GitLab From 39484e53bb00f55b6303a908070db133608ef2a5 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 11 Oct 2006 01:21:54 -0700 Subject: [PATCH 1036/1619] [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(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 27ca1aa3056..a91f2628c98 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 4e1663d7691..cfdb4f6a89d 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) -- GitLab From 01a3ee2b203e511e20f98b85a9172fd32c53e87c Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 11 Oct 2006 01:21:55 -0700 Subject: [PATCH 1037/1619] [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(-) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index dcc5de7cc48..64b4641904f 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 b268a3c0c37..d0e8c8b0e34 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 5dce5c21822..b1063e9cdb1 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 607c7809ad0..9a352667007 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 857300a2afe..f940b462eec 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 d71e38c54ea..037fa9aa2ed 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) -- GitLab From cd0810410beb86c570aeb3dcd3dc1fc5ab9e6077 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Wed, 11 Oct 2006 01:21:57 -0700 Subject: [PATCH 1038/1619] [PATCH] document the core-dump-to-a-pipe patch The pipe-a-coredump-to-a-program feature was undocumented. *Grumble*. NB: a good enhancement to that patch would be: save all the stuff that a core file can get from the %x expansions in the environment. Signed-off-by: Matthias Urlichs Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/kernel.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 89bf8c20a58..0bc7f1e3c9e 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -86,7 +86,7 @@ valid for 30 seconds. core_pattern: core_pattern is used to specify a core dumpfile pattern name. -. max length 64 characters; default value is "core" +. max length 128 characters; default value is "core" . core_pattern is used as a pattern template for the output filename; certain string patterns (beginning with '%') are substituted with their actual values. @@ -105,6 +105,9 @@ core_pattern is used to specify a core dumpfile pattern name. %h hostname %e executable filename % both are dropped +. If the first character of the pattern is a '|', the kernel will treat + the rest of the pattern as a command to run. The core dump will be + written to the standard input of that program instead of to a file. ============================================================== -- GitLab From 887ed2f3aecde2ff24e06666932dc5f144745044 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 11 Oct 2006 01:21:58 -0700 Subject: [PATCH 1039/1619] [PATCH] VM: Fix the gfp_mask in invalidate_complete_page2 If try_to_release_page() is called with a zero gfp mask, then the filesystem is effectively denied the possibility of sleeping while attempting to release the page. There doesn't appear to be any valid reason why this should be banned, given that we're not calling this from a memory allocation context. For this reason, change the gfp_mask argument of the call to GFP_KERNEL. Signed-off-by: Trond Myklebust Cc: Steve Dickson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/truncate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/truncate.c b/mm/truncate.c index fca28839c46..11ca480701d 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -302,7 +302,7 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page) if (page->mapping != mapping) return 0; - if (PagePrivate(page) && !try_to_release_page(page, 0)) + if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL)) return 0; write_lock_irq(&mapping->tree_lock); -- GitLab From 97e860d364aa9d08e895ecb619b9122ae2c70df8 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Wed, 11 Oct 2006 01:21:59 -0700 Subject: [PATCH 1040/1619] [PATCH] Remove unnecessary check in fs/fat/inode.c Aince all callers dereference sb, and this function does so earlier too, we dont need the check. Signed-off-by: Eric Sesterhenn Acked-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 4613cb20217..78945b53b0f 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1472,7 +1472,7 @@ int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2) ret = writeback_inode(i1); if (!ret && i2) ret = writeback_inode(i2); - if (!ret && sb) { + if (!ret) { struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; ret = filemap_flush(mapping); } -- GitLab From 8c58165108e26d18849a0138c719e680f281197a Mon Sep 17 00:00:00 2001 From: Monakhov Dmitriy Date: Wed, 11 Oct 2006 01:22:00 -0700 Subject: [PATCH 1041/1619] [PATCH] D-cache aliasing issue in __block_prepare_write A couple of flush_dcache_page()s are missing on the I/O-error paths. Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/buffer.c b/fs/buffer.c index 2a7828c0e59..f65ef8821c7 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1854,6 +1854,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page, clear_buffer_new(bh); kaddr = kmap_atomic(page, KM_USER0); memset(kaddr+block_start, 0, bh->b_size); + flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); set_buffer_uptodate(bh); mark_buffer_dirty(bh); @@ -2360,6 +2361,7 @@ failed: */ kaddr = kmap_atomic(page, KM_USER0); memset(kaddr, 0, PAGE_CACHE_SIZE); + flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); SetPageUptodate(page); set_page_dirty(page); -- GitLab From 53d5ed627df852ba8bab7f70df25290bd733792c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 11 Oct 2006 01:22:01 -0700 Subject: [PATCH 1042/1619] [PATCH] Use linux/io.h instead of asm/io.h In preparation for moving check_signature, change these users from asm/io.h to linux/io.h Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/xd.c | 2 +- drivers/input/misc/wistron_btns.c | 2 +- drivers/net/eth16i.c | 2 +- drivers/scsi/aha152x.c | 2 +- drivers/scsi/dtc.c | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/seagate.c | 2 +- drivers/scsi/t128.c | 2 +- drivers/scsi/wd7000.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 10cc38783bd..0d97b7eb818 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -48,9 +48,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 4639537336f..7b9d1c1da41 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -17,7 +17,7 @@ * 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 diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 8cc3c331aca..b7b8bc2a630 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -162,9 +162,9 @@ static char *version = #include #include #include +#include #include -#include #include diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index a0d1cee0be7..306f46b85a5 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -238,7 +238,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 0d5713dfa20..54756722dd5 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -82,7 +82,7 @@ #include #include #include -#include +#include #include "scsi.h" #include #include "dtc.h" diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 41b05fc4538..72794a7b6dc 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -278,9 +278,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 8ff1f2866f7..5ffec2721b2 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -97,8 +97,8 @@ #include #include #include +#include -#include #include #include diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index 2df6747cb76..0b7a70f61e0 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -109,7 +109,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 331e1cf159b..30be76514c4 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -178,10 +178,10 @@ #include #include #include +#include #include #include -#include #include #include -- GitLab From e50190a8341485b413f599033cb74649f849d939 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 11 Oct 2006 01:22:02 -0700 Subject: [PATCH 1043/1619] [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(-) diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h index f5ae98c25d1..5d15af24573 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 34aaaac4f61..ae999fd5dc6 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 7765f552889..20e44fe00ab 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 b3724fe93ff..68df0dc3ab8 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 70ad1c949c2..d06933bd631 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 df624e1ee6e..c2d124badbe 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 cbbd8c648df..3baff8b0fd5 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 3d9a9e6f332..a4c411b753e 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 ed12d38e8c0..a0e55b09e4f 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 252fedbb662..14d8e7b4bf4 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 0056770e83a..30b912d8e8b 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 70e91fe7634..6ee9fadaaac 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 2ad96c3f0e4..81877ea3930 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 */ -- GitLab From 53bc5b2db16ceefdd972b9ffd1f7bde5c427939e Mon Sep 17 00:00:00 2001 From: Aneesh Kumar Date: Wed, 11 Oct 2006 01:22:03 -0700 Subject: [PATCH 1044/1619] [PATCH] Fix typos in mm/shmem_acl.c Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/shmem_acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c index c946bf46871..f5664c5b9eb 100644 --- a/mm/shmem_acl.c +++ b/mm/shmem_acl.c @@ -35,7 +35,7 @@ shmem_get_acl(struct inode *inode, int type) } /** - * shmem_get_acl - generic_acl_operations->setacl() operation + * shmem_set_acl - generic_acl_operations->setacl() operation */ static void shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl) -- GitLab From fbab41ccc479b6b0ba15c137af9e0b1c100bff24 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 11 Oct 2006 01:22:04 -0700 Subject: [PATCH 1045/1619] [PATCH] HT_IRQ must depend on PCI CONFIG_PCI=n, CONFIG_HT_IRQ=y results in the following compile error: ... LD vmlinux arch/i386/mach-generic/built-in.o: In function `apicid_to_node': summit.c:(.text+0x53): undefined reference to `apicid_2_node' arch/i386/kernel/built-in.o: In function `arch_setup_ht_irq': (.text+0xcf79): undefined reference to `write_ht_irq_low' arch/i386/kernel/built-in.o: In function `arch_setup_ht_irq': (.text+0xcf85): undefined reference to `write_ht_irq_high' arch/i386/kernel/built-in.o: In function `k7nops': alternative.c:(.data+0x1358): undefined reference to `mask_ht_irq' alternative.c:(.data+0x1360): undefined reference to `unmask_ht_irq' make[1]: *** [vmlinux] Error 1 Bug report by Jesper Juhl. Signed-off-by: Adrian Bunk Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 30294127a0a..ecc50db8585 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -55,7 +55,7 @@ config PCI_DEBUG config HT_IRQ bool "Interrupts on hypertransport devices" default y - depends on X86_LOCAL_APIC && X86_IO_APIC + depends on PCI && X86_LOCAL_APIC && X86_IO_APIC help This allows native hypertransport devices to use interrupts. -- GitLab From 2ecd05ae68a903761e736e9e0aca40d6ace4319e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 11 Oct 2006 01:22:05 -0700 Subject: [PATCH 1046/1619] [PATCH] fs/*: use BUILD_BUG_ON Signed-off-by: Alexey Dobriyan Cc: David Woodhouse Cc: David Howells Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/dir.c | 8 ++++---- fs/jffs2/super.c | 8 ++++---- fs/minix/inode.c | 8 ++------ fs/ocfs2/super.c | 2 +- fs/sysv/super.c | 15 +++++---------- 5 files changed, 16 insertions(+), 25 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index cf8a2cb2850..a6ec75c56fc 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -211,8 +211,8 @@ static int afs_dir_open(struct inode *inode, struct file *file) { _enter("{%lu}", inode->i_ino); - BUG_ON(sizeof(union afs_dir_block) != 2048); - BUG_ON(sizeof(union afs_dirent) != 32); + BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); + BUILD_BUG_ON(sizeof(union afs_dirent) != 32); if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) return -ENOENT; @@ -446,8 +446,8 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); /* insanity checks first */ - BUG_ON(sizeof(union afs_dir_block) != 2048); - BUG_ON(sizeof(union afs_dirent) != 32); + BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); + BUILD_BUG_ON(sizeof(union afs_dirent) != 32); if (dentry->d_name.len > 255) { _leave(" = -ENAMETOOLONG"); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 6de374513c0..bc4b8106a49 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -334,10 +334,10 @@ static int __init init_jffs2_fs(void) which means just 'no padding', without the alignment thing. But GCC doesn't have that -- we have to just hope the structs are the right sizes, instead. */ - BUG_ON(sizeof(struct jffs2_unknown_node) != 12); - BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); - BUG_ON(sizeof(struct jffs2_raw_inode) != 68); - BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); + BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); printk(KERN_INFO "JFFS2 version 2.2." #ifdef CONFIG_JFFS2_FS_WRITEBUFFER diff --git a/fs/minix/inode.c b/fs/minix/inode.c index c11a4b9fb86..1e36bae4d0e 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -149,12 +149,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) return -ENOMEM; s->s_fs_info = sbi; - /* N.B. These should be compile-time tests. - Unfortunately that is impossible. */ - if (32 != sizeof (struct minix_inode)) - panic("bad V1 i-node size"); - if (64 != sizeof(struct minix2_inode)) - panic("bad V2 i-node size"); + BUILD_BUG_ON(32 != sizeof (struct minix_inode)); + BUILD_BUG_ON(64 != sizeof(struct minix2_inode)); if (!sb_set_blocksize(s, BLOCK_SIZE)) goto out_bad_hblock; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 4c29cd7cc8e..76b46ebbb10 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -339,7 +339,7 @@ static unsigned long long ocfs2_max_file_offset(unsigned int blockshift) #if BITS_PER_LONG == 32 # if defined(CONFIG_LBD) - BUG_ON(sizeof(sector_t) != 8); + BUILD_BUG_ON(sizeof(sector_t) != 8); pagefactor = PAGE_CACHE_SIZE; bitshift = BITS_PER_LONG; # else diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 350cba5d680..dc9e7dc07fb 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -358,16 +358,11 @@ static int sysv_fill_super(struct super_block *sb, void *data, int silent) unsigned long blocknr; int size = 0, i; - if (1024 != sizeof (struct xenix_super_block)) - panic("Xenix FS: bad superblock size"); - if (512 != sizeof (struct sysv4_super_block)) - panic("SystemV FS: bad superblock size"); - if (512 != sizeof (struct sysv2_super_block)) - panic("SystemV FS: bad superblock size"); - if (500 != sizeof (struct coh_super_block)) - panic("Coherent FS: bad superblock size"); - if (64 != sizeof (struct sysv_inode)) - panic("sysv fs: bad inode size"); + BUILD_BUG_ON(1024 != sizeof (struct xenix_super_block)); + BUILD_BUG_ON(512 != sizeof (struct sysv4_super_block)); + BUILD_BUG_ON(512 != sizeof (struct sysv2_super_block)); + BUILD_BUG_ON(500 != sizeof (struct coh_super_block)); + BUILD_BUG_ON(64 != sizeof (struct sysv_inode)); sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL); if (!sbi) -- GitLab From 39913b31d0cd11b5b18a303e220c95ffbd9e1a88 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 11 Oct 2006 01:22:06 -0700 Subject: [PATCH 1047/1619] [PATCH] DAC960: use memmove for overlapping areas Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/DAC960.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index cec539e601f..6148073532b 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -4379,8 +4379,8 @@ static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry) static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState) { memcpy(DeviceState + 2, DeviceState + 3, 1); - memcpy(DeviceState + 4, DeviceState + 5, 2); - memcpy(DeviceState + 6, DeviceState + 8, 4); + memmove(DeviceState + 4, DeviceState + 5, 2); + memmove(DeviceState + 6, DeviceState + 8, 4); } static inline -- GitLab From 3dc3099a9b2c346b16383597fadaa79a05a52388 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 11 Oct 2006 01:22:06 -0700 Subject: [PATCH 1048/1619] [PATCH] lockdep: use BUILD_BUG_ON Signed-off-by: Alexey Dobriyan Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/lockdep.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 4c055346100..805a322a565 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1114,8 +1114,6 @@ static int count_matching_names(struct lock_class *new_class) return count + 1; } -extern void __error_too_big_MAX_LOCKDEP_SUBCLASSES(void); - /* * Register a lock's class in the hash-table, if the class is not present * yet. Otherwise we look it up. We cache the result in the lock object @@ -1153,8 +1151,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass) * (or spin_lock_init()) call - which acts as the key. For static * locks we use the lock object itself as the key. */ - if (sizeof(struct lock_class_key) > sizeof(struct lock_class)) - __error_too_big_MAX_LOCKDEP_SUBCLASSES(); + BUILD_BUG_ON(sizeof(struct lock_class_key) > sizeof(struct lock_class)); key = lock->key->subkeys + subclass; -- GitLab From 5fcce7432a731e67f1cd3ef1e71dca9ea84dedb1 Mon Sep 17 00:00:00 2001 From: Aneesh Kumar Date: Wed, 11 Oct 2006 01:22:07 -0700 Subject: [PATCH 1049/1619] [PATCH] fix lockdep-design.txt I was looking at lockdep-desing.txt and i guess i am confused with the changes with respect to fd7bcea35e7efb108c34ee2b3840942a3749cadb. It says + '.' acquired while irqs enabled + '+' acquired in irq context + '-' acquired in process context with irqs disabled + '?' read-acquired both with irqs enabled and in irq context + But the get_usage_chars() function does this for '-' if (class->usage_mask & LOCKF_ENABLED_HARDIRQS) *c1 = '-'; So i guess what would be correct would be '.' acquired while irqs disabled '+' acquired in irq context '-' acquired with irqs enabled '?' read acquired in irq context with irqs enabled. Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/lockdep-design.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/lockdep-design.txt b/Documentation/lockdep-design.txt index dab123db5a4..48877301815 100644 --- a/Documentation/lockdep-design.txt +++ b/Documentation/lockdep-design.txt @@ -50,10 +50,10 @@ The bit position indicates hardirq, softirq, hardirq-read, softirq-read respectively, and the character displayed in each indicates: - '.' acquired while irqs enabled + '.' acquired while irqs disabled '+' acquired in irq context - '-' acquired in process context with irqs disabled - '?' read-acquired both with irqs enabled and in irq context + '-' acquired with irqs enabled + '?' read acquired in irq context with irqs enabled. Unused mutexes cannot be part of the cause of an error. -- GitLab From 256a6b41365e17cebe5c2fc91ddff716c9aa055a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 11 Oct 2006 01:22:08 -0700 Subject: [PATCH 1050/1619] [PATCH] lockdep: fix printk recursion logic Bug reported and fixed by Tilman Schmidt : if lockdep is enabled then log messages make it to /var/log/messages belatedly. The reason is a missed wakeup of klogd. Initially there was only a lockdep_internal() protection against lockdep recursion within vprintk() - it grew the 'outer' lockdep_off()/on() protection only later on. But that lockdep_off() made the release_console_sem() within vprintk() always happen under the lockdep_internal() condition, causing the bug. The right solution to remove the inner protection against recursion here - the outer one is enough. Signed-off-by: Ingo Molnar Cc: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/printk.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/kernel/printk.c b/kernel/printk.c index 771f5e861bc..f7d427ef503 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -820,15 +820,8 @@ void release_console_sem(void) console_locked = 0; up(&console_sem); spin_unlock_irqrestore(&logbuf_lock, flags); - if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) { - /* - * If we printk from within the lock dependency code, - * from within the scheduler code, then do not lock - * up due to self-recursion: - */ - if (!lockdep_internal()) - wake_up_interruptible(&log_wait); - } + if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) + wake_up_interruptible(&log_wait); } EXPORT_SYMBOL(release_console_sem); -- GitLab From 35e38a6e03bedba7c633ae03d286accd85ab6a42 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2006 01:22:09 -0700 Subject: [PATCH 1051/1619] [PATCH] kernel-doc: fix function name in usercopy.c Fix kernel-doc function name in usercopy.c. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/lib/usercopy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 08502fc6d0c..258df6b4d7d 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -179,7 +179,7 @@ __clear_user(void __user *to, unsigned long n) EXPORT_SYMBOL(__clear_user); /** - * strlen_user: - Get the size of a string in user space. + * strnlen_user: - Get the size of a string in user space. * @s: The string to measure. * @n: The maximum valid length * -- GitLab From 9c7fff6ef36526fb54694ee8201870f98b6a1747 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2006 01:22:10 -0700 Subject: [PATCH 1052/1619] [PATCH] uaccess.h: match kernel-doc and function names Place kernel-doc function comment header immediately before the function that is being documented. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/uaccess.h | 67 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 54d905ebc63..eef5133b9ce 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -404,20 +404,6 @@ unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to, * anything, so this is accurate. */ -/** - * __copy_to_user: - Copy a block of data into user space, with less checking. - * @to: Destination address, in user space. - * @from: Source address, in kernel space. - * @n: Number of bytes to copy. - * - * Context: User context only. This function may sleep. - * - * Copy data from kernel space to user space. Caller must check - * the specified block with access_ok() before calling this function. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - */ static __always_inline unsigned long __must_check __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) { @@ -439,35 +425,27 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) return __copy_to_user_ll(to, from, n); } -static __always_inline unsigned long __must_check -__copy_to_user(void __user *to, const void *from, unsigned long n) -{ - might_sleep(); - return __copy_to_user_inatomic(to, from, n); -} - /** - * __copy_from_user: - Copy a block of data from user space, with less checking. - * @to: Destination address, in kernel space. - * @from: Source address, in user space. + * __copy_to_user: - Copy a block of data into user space, with less checking. + * @to: Destination address, in user space. + * @from: Source address, in kernel space. * @n: Number of bytes to copy. * * Context: User context only. This function may sleep. * - * Copy data from user space to kernel space. Caller must check + * Copy data from kernel space to user space. Caller must check * the specified block with access_ok() before calling this function. * * Returns number of bytes that could not be copied. * On success, this will be zero. - * - * If some data could not be copied, this function will pad the copied - * data to the requested size using zero bytes. - * - * An alternate version - __copy_from_user_inatomic() - may be called from - * atomic context and will fail rather than sleep. In this case the - * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h - * for explanation of why this is needed. */ +static __always_inline unsigned long __must_check +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + might_sleep(); + return __copy_to_user_inatomic(to, from, n); +} + static __always_inline unsigned long __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) { @@ -493,6 +471,29 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) } return __copy_from_user_ll_nozero(to, from, n); } + +/** + * __copy_from_user: - Copy a block of data from user space, with less checking. + * @to: Destination address, in kernel space. + * @from: Source address, in user space. + * @n: Number of bytes to copy. + * + * Context: User context only. This function may sleep. + * + * Copy data from user space to kernel space. Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + * + * If some data could not be copied, this function will pad the copied + * data to the requested size using zero bytes. + * + * An alternate version - __copy_from_user_inatomic() - may be called from + * atomic context and will fail rather than sleep. In this case the + * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h + * for explanation of why this is needed. + */ static __always_inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) { -- GitLab From 32e794015aa698fd6bf1ec21b713f900a707fb15 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2006 01:22:10 -0700 Subject: [PATCH 1053/1619] [PATCH] kernel-doc: drop various "inline" qualifiers Drop __inline, __always_inline, and noinline in the produced kernel-doc output, similar to other pseudo directives. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 00d1ad19b2c..7bc53a94faa 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1518,6 +1518,9 @@ sub dump_function($$) { $prototype =~ s/^asmlinkage +//; $prototype =~ s/^inline +//; $prototype =~ s/^__inline__ +//; + $prototype =~ s/^__inline +//; + $prototype =~ s/^__always_inline +//; + $prototype =~ s/^noinline +//; $prototype =~ s/__devinit +//; $prototype =~ s/^#define +//; #ak added $prototype =~ s/__attribute__ \(\([a-z,]*\)\)//; -- GitLab From c751c1dbb1289d220a8a175ba0df47706ce95a7e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 11 Oct 2006 01:22:11 -0700 Subject: [PATCH 1054/1619] [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(+) diff --git a/include/linux/nbd.h b/include/linux/nbd.h index e712e7d47cc..d6b6dc09ad9 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 ) -- GitLab From 272057447f646c51bc77c60044eb21c683fa366d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2006 01:22:12 -0700 Subject: [PATCH 1055/1619] [PATCH] kernel-doc: make parameter description indentation uniform - In parameter descriptions, strip all whitespace between the parameter name (e.g., @len) and its description so that the description is indented uniformly in text and man page modes. Previously, spaces or tabs (which are used for cleaner source code viewing) affected the produced output in a negative way. Before (man mode): to Destination address, in user space. from Source address, in kernel space. n Number of bytes to copy. After (man mode): to Destination address, in user space. from Source address, in kernel space. n Number of bytes to copy. - Fix/clarify a few function description comments. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 7bc53a94faa..187f5de4612 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1262,7 +1262,9 @@ sub output_intro_text(%) { } ## -# generic output function for typedefs +# generic output function for all types (function, struct/union, typedef, enum); +# calls the generated, variable output_ function name based on +# functype and output_mode sub output_declaration { no strict 'refs'; my $name = shift; @@ -1278,8 +1280,7 @@ sub output_declaration { } ## -# generic output function - calls the right one based -# on current output mode. +# generic output function - calls the right one based on current output mode. sub output_intro { no strict 'refs'; my $func = "output_intro_".$output_mode; @@ -1781,8 +1782,9 @@ sub process_file($) { $in_doc_sect = 1; $contents = $newcontents; if ($contents ne "") { - if (substr($contents, 0, 1) eq " ") { - $contents = substr($contents, 1); + while ((substr($contents, 0, 1) eq " ") || + substr($contents, 0, 1) eq "\t") { + $contents = substr($contents, 1); } $contents .= "\n"; } -- GitLab From 9e42ef777f62277ea9bb70976be65bb374e00b9c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:22:13 -0700 Subject: [PATCH 1056/1619] [PATCH] dell_rbu: printk() warning fix drivers/firmware/dell_rbu.c: In function 'packetize_data': drivers/firmware/dell_rbu.c:252: warning: format '%lu' expects type 'long unsigned int', but argument 3 has type 'int' Cc: Matt Domsch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/dell_rbu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index fc17599c905..8136d779ddc 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -249,7 +249,7 @@ static int packetize_data(void *data, size_t length) if ((rc = create_packet(temp, packet_length))) return rc; - pr_debug("%p:%lu\n", temp, (end - temp)); + pr_debug("%p:%td\n", temp, (end - temp)); temp += packet_length; } -- GitLab From edc666e2ff9ec2e4e9510f1127c68c22cffc93f6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 11 Oct 2006 01:22:14 -0700 Subject: [PATCH 1057/1619] [PATCH] ReiserFS: Make sure all dentries refs are released before calling kill_block_super() Make sure all dentries refs are released before calling kill_block_super() so that the assumption that generic_shutdown_super() can completely destroy the dentry tree for there will be no external references holds true. What was being done in the put_super() superblock op, is now done in the kill_sb() filesystem op instead, prior to calling kill_block_super(). Changes made in [try #2]: (*) reiserfs_kill_sb() now checks that the superblock FS info pointer is set before trying to dereference it. Signed-off-by: David Howells Cc: "Rafael J. Wysocki" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/super.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index c89aa233819..9041802df83 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -430,20 +430,29 @@ int remove_save_link(struct inode *inode, int truncate) return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); } -static void reiserfs_put_super(struct super_block *s) +static void reiserfs_kill_sb(struct super_block *s) { - struct reiserfs_transaction_handle th; - th.t_trans_id = 0; + if (REISERFS_SB(s)) { + if (REISERFS_SB(s)->xattr_root) { + d_invalidate(REISERFS_SB(s)->xattr_root); + dput(REISERFS_SB(s)->xattr_root); + REISERFS_SB(s)->xattr_root = NULL; + } - if (REISERFS_SB(s)->xattr_root) { - d_invalidate(REISERFS_SB(s)->xattr_root); - dput(REISERFS_SB(s)->xattr_root); + if (REISERFS_SB(s)->priv_root) { + d_invalidate(REISERFS_SB(s)->priv_root); + dput(REISERFS_SB(s)->priv_root); + REISERFS_SB(s)->priv_root = NULL; + } } - if (REISERFS_SB(s)->priv_root) { - d_invalidate(REISERFS_SB(s)->priv_root); - dput(REISERFS_SB(s)->priv_root); - } + kill_block_super(s); +} + +static void reiserfs_put_super(struct super_block *s) +{ + struct reiserfs_transaction_handle th; + th.t_trans_id = 0; /* change file system state to current state if it was mounted with read-write permissions */ if (!(s->s_flags & MS_RDONLY)) { @@ -2156,7 +2165,7 @@ struct file_system_type reiserfs_fs_type = { .owner = THIS_MODULE, .name = "reiserfs", .get_sb = get_super_block, - .kill_sb = kill_block_super, + .kill_sb = reiserfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; -- GitLab From 6ce315234aefcbc599dea390c15672156ebf9e7b Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 11 Oct 2006 01:22:15 -0700 Subject: [PATCH 1058/1619] [PATCH] AUTOFS: Make sure all dentries refs are released before calling kill_anon_super() Make sure all dentries refs are released before calling kill_anon_super() so that the assumption that generic_shutdown_super() can completely destroy the dentry tree for there will be no external references holds true. What was being done in the put_super() superblock op, is now done in the kill_sb() filesystem op instead, prior to calling kill_anon_super(). This makes the struct autofs_sb_info::root member variable redundant (since sb->s_root is still available), and so that is removed. The calls to shrink_dcache_sb() are also removed since they're also redundant as shrink_dcache_for_umount() will now be called after the cleanup routine. Signed-off-by: David Howells Acked-by: Ian Kent Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/autofs4/autofs_i.h | 3 +-- fs/autofs4/init.c | 2 +- fs/autofs4/inode.c | 22 ++++------------------ fs/autofs4/waitq.c | 1 - 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 480ab178cba..b13f32c8aee 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -94,7 +94,6 @@ struct autofs_wait_queue { struct autofs_sb_info { u32 magic; - struct dentry *root; int pipefd; struct file *pipe; pid_t oz_pgrp; @@ -229,4 +228,4 @@ out: } void autofs4_dentry_release(struct dentry *); - +extern void autofs4_kill_sb(struct super_block *); diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c index 5d9193332be..723a1c5e361 100644 --- a/fs/autofs4/init.c +++ b/fs/autofs4/init.c @@ -24,7 +24,7 @@ static struct file_system_type autofs_fs_type = { .owner = THIS_MODULE, .name = "autofs", .get_sb = autofs_get_sb, - .kill_sb = kill_anon_super, + .kill_sb = autofs4_kill_sb, }; static int __init init_autofs4_fs(void) diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 800ce876cae..51fd8595bf8 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -96,7 +96,7 @@ void autofs4_free_ino(struct autofs_info *ino) */ static void autofs4_force_release(struct autofs_sb_info *sbi) { - struct dentry *this_parent = sbi->root; + struct dentry *this_parent = sbi->sb->s_root; struct list_head *next; spin_lock(&dcache_lock); @@ -127,7 +127,7 @@ resume: spin_lock(&dcache_lock); } - if (this_parent != sbi->root) { + if (this_parent != sbi->sb->s_root) { struct dentry *dentry = this_parent; next = this_parent->d_u.d_child.next; @@ -140,15 +140,9 @@ resume: goto resume; } spin_unlock(&dcache_lock); - - dput(sbi->root); - sbi->root = NULL; - shrink_dcache_sb(sbi->sb); - - return; } -static void autofs4_put_super(struct super_block *sb) +void autofs4_kill_sb(struct super_block *sb) { struct autofs_sb_info *sbi = autofs4_sbi(sb); @@ -163,6 +157,7 @@ static void autofs4_put_super(struct super_block *sb) kfree(sbi); DPRINTK("shutting down"); + kill_anon_super(sb); } static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) @@ -189,7 +184,6 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) } static struct super_operations autofs4_sops = { - .put_super = autofs4_put_super, .statfs = simple_statfs, .show_options = autofs4_show_options, }; @@ -315,7 +309,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) s->s_fs_info = sbi; sbi->magic = AUTOFS_SBI_MAGIC; - sbi->root = NULL; sbi->pipefd = -1; sbi->catatonic = 0; sbi->exp_timeout = 0; @@ -396,13 +389,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) sbi->pipe = pipe; sbi->pipefd = pipefd; - /* - * Take a reference to the root dentry so we get a chance to - * clean up the dentry tree on umount. - * See autofs4_force_release. - */ - sbi->root = dget(root); - /* * Success! Install the root dentry now to indicate completion. */ diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index ce103e7b0bc..c0a6c8d445c 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) fput(sbi->pipe); /* Close the pipe */ sbi->pipe = NULL; } - shrink_dcache_sb(sbi->sb); } static int autofs4_write(struct file *file, const void *addr, int bytes) -- GitLab From c636ebdb186bf37f98d3839f69293597723edb36 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 11 Oct 2006 01:22:19 -0700 Subject: [PATCH 1059/1619] [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(-) diff --git a/fs/dcache.c b/fs/dcache.c index 2355bddad8d..2bac4ba1d1d 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 aec99ddbe53..47e554c12e7 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 44605be5940..63f64a9a5bf 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 */ -- GitLab From 41bfcfd9ac0fbb59aaaa18e3ed5774e85b716de4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:22:20 -0700 Subject: [PATCH 1060/1619] [PATCH] firmware/dell_rbu: handle sysfs errors Signed-off-by: Jeff Garzik Cc: Matt Domsch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/dell_rbu.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 8136d779ddc..08b16179844 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -718,14 +718,27 @@ static int __init dcdrbu_init(void) return -EIO; } - sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); - sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); - sysfs_create_bin_file(&rbu_device->dev.kobj, + rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); + if (rc) + goto out_devreg; + rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); + if (rc) + goto out_data; + rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_packet_size_attr); + if (rc) + goto out_imtype; rbu_data.entry_created = 0; - return rc; + return 0; +out_imtype: + sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); +out_data: + sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); +out_devreg: + platform_device_unregister(rbu_device); + return rc; } static __exit void dcdrbu_exit(void) -- GitLab From 5e59393ec242d7b772356c95e2be48384cd0c5d7 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:22:21 -0700 Subject: [PATCH 1061/1619] [PATCH] ipmi: handle sysfs errors Signed-off-by: Jeff Garzik Acked-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 122 +++++++++++++++++++++------- 1 file changed, 93 insertions(+), 29 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 2455e8d478a..34a4fd13fa8 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -1928,13 +1928,8 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, (long long) bmc->guid[8]); } -static void -cleanup_bmc_device(struct kref *ref) +static void remove_files(struct bmc_device *bmc) { - struct bmc_device *bmc; - - bmc = container_of(ref, struct bmc_device, refcount); - device_remove_file(&bmc->dev->dev, &bmc->device_id_attr); device_remove_file(&bmc->dev->dev, @@ -1951,12 +1946,23 @@ cleanup_bmc_device(struct kref *ref) &bmc->manufacturer_id_attr); device_remove_file(&bmc->dev->dev, &bmc->product_id_attr); + if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); if (bmc->guid_set) device_remove_file(&bmc->dev->dev, &bmc->guid_attr); +} + +static void +cleanup_bmc_device(struct kref *ref) +{ + struct bmc_device *bmc; + + bmc = container_of(ref, struct bmc_device, refcount); + + remove_files(bmc); platform_device_unregister(bmc->dev); kfree(bmc); } @@ -1977,6 +1983,79 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) mutex_unlock(&ipmidriver_mutex); } +static int create_files(struct bmc_device *bmc) +{ + int err; + + err = device_create_file(&bmc->dev->dev, + &bmc->device_id_attr); + if (err) goto out; + err = device_create_file(&bmc->dev->dev, + &bmc->provides_dev_sdrs_attr); + if (err) goto out_devid; + err = device_create_file(&bmc->dev->dev, + &bmc->revision_attr); + if (err) goto out_sdrs; + err = device_create_file(&bmc->dev->dev, + &bmc->firmware_rev_attr); + if (err) goto out_rev; + err = device_create_file(&bmc->dev->dev, + &bmc->version_attr); + if (err) goto out_firm; + err = device_create_file(&bmc->dev->dev, + &bmc->add_dev_support_attr); + if (err) goto out_version; + err = device_create_file(&bmc->dev->dev, + &bmc->manufacturer_id_attr); + if (err) goto out_add_dev; + err = device_create_file(&bmc->dev->dev, + &bmc->product_id_attr); + if (err) goto out_manu; + if (bmc->id.aux_firmware_revision_set) { + err = device_create_file(&bmc->dev->dev, + &bmc->aux_firmware_rev_attr); + if (err) goto out_prod_id; + } + if (bmc->guid_set) { + err = device_create_file(&bmc->dev->dev, + &bmc->guid_attr); + if (err) goto out_aux_firm; + } + + return 0; + +out_aux_firm: + if (bmc->id.aux_firmware_revision_set) + device_remove_file(&bmc->dev->dev, + &bmc->aux_firmware_rev_attr); +out_prod_id: + device_remove_file(&bmc->dev->dev, + &bmc->product_id_attr); +out_manu: + device_remove_file(&bmc->dev->dev, + &bmc->manufacturer_id_attr); +out_add_dev: + device_remove_file(&bmc->dev->dev, + &bmc->add_dev_support_attr); +out_version: + device_remove_file(&bmc->dev->dev, + &bmc->version_attr); +out_firm: + device_remove_file(&bmc->dev->dev, + &bmc->firmware_rev_attr); +out_rev: + device_remove_file(&bmc->dev->dev, + &bmc->revision_attr); +out_sdrs: + device_remove_file(&bmc->dev->dev, + &bmc->provides_dev_sdrs_attr); +out_devid: + device_remove_file(&bmc->dev->dev, + &bmc->device_id_attr); +out: + return err; +} + static int ipmi_bmc_register(ipmi_smi_t intf) { int rv; @@ -2051,7 +2130,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf) bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; - bmc->revision_attr.attr.name = "revision"; bmc->revision_attr.attr.owner = THIS_MODULE; bmc->revision_attr.attr.mode = S_IRUGO; @@ -2093,28 +2171,14 @@ static int ipmi_bmc_register(ipmi_smi_t intf) bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; - device_create_file(&bmc->dev->dev, - &bmc->device_id_attr); - device_create_file(&bmc->dev->dev, - &bmc->provides_dev_sdrs_attr); - device_create_file(&bmc->dev->dev, - &bmc->revision_attr); - device_create_file(&bmc->dev->dev, - &bmc->firmware_rev_attr); - device_create_file(&bmc->dev->dev, - &bmc->version_attr); - device_create_file(&bmc->dev->dev, - &bmc->add_dev_support_attr); - device_create_file(&bmc->dev->dev, - &bmc->manufacturer_id_attr); - device_create_file(&bmc->dev->dev, - &bmc->product_id_attr); - if (bmc->id.aux_firmware_revision_set) - device_create_file(&bmc->dev->dev, - &bmc->aux_firmware_rev_attr); - if (bmc->guid_set) - device_create_file(&bmc->dev->dev, - &bmc->guid_attr); + rv = create_files(bmc); + if (rv) { + mutex_lock(&ipmidriver_mutex); + platform_device_unregister(bmc->dev); + mutex_unlock(&ipmidriver_mutex); + + return rv; + } printk(KERN_INFO "ipmi: Found new BMC (man_id: 0x%6.6x, " -- GitLab From 42ddfd6859b9d57490c94d26e29a43ffd78366e5 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:22:22 -0700 Subject: [PATCH 1062/1619] [PATCH] EISA: handle sysfs errors Signed-off-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/eisa/eisa-bus.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 3a365e159d8..d944647c82c 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -226,14 +226,26 @@ static int __init eisa_init_device (struct eisa_root_device *root, static int __init eisa_register_device (struct eisa_device *edev) { - if (device_register (&edev->dev)) - return -1; + int rc = device_register (&edev->dev); + if (rc) + return rc; - device_create_file (&edev->dev, &dev_attr_signature); - device_create_file (&edev->dev, &dev_attr_enabled); - device_create_file (&edev->dev, &dev_attr_modalias); + rc = device_create_file (&edev->dev, &dev_attr_signature); + if (rc) goto err_devreg; + rc = device_create_file (&edev->dev, &dev_attr_enabled); + if (rc) goto err_sig; + rc = device_create_file (&edev->dev, &dev_attr_modalias); + if (rc) goto err_enab; return 0; + +err_enab: + device_remove_file (&edev->dev, &dev_attr_enabled); +err_sig: + device_remove_file (&edev->dev, &dev_attr_signature); +err_devreg: + device_unregister(&edev->dev); + return rc; } static int __init eisa_request_resources (struct eisa_root_device *root, -- GitLab From 69b2186c5fcb335e29c558e3b4e410e1939b5cc8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:22:23 -0700 Subject: [PATCH 1063/1619] [PATCH] firmware/efivars: handle error Signed-off-by: Jeff Garzik Acked-by: Matt Domsch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/efivars.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 8ebce1c03ad..5ab5e393b88 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -639,7 +639,12 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, kobject_set_name(&new_efivar->kobj, "%s", short_name); kobj_set_kset_s(new_efivar, vars_subsys); - kobject_register(&new_efivar->kobj); + i = kobject_register(&new_efivar->kobj); + if (i) { + kfree(short_name); + kfree(new_efivar); + return 1; + } kfree(short_name); short_name = NULL; -- GitLab From 49a6cbe1cd8a72451d9d6ab5b1e163f17c1bbee3 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:22:23 -0700 Subject: [PATCH 1064/1619] [PATCH] drivers/mca: handle sysfs errors Also includes a kmalloc->kzalloc cleanup. Signed-off-by: Jeff Garzik Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mca/mca-bus.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c index 09baa43b259..da862e4632d 100644 --- a/drivers/mca/mca-bus.c +++ b/drivers/mca/mca-bus.c @@ -100,6 +100,7 @@ static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL); int __init mca_register_device(int bus, struct mca_device *mca_dev) { struct mca_bus *mca_bus = mca_root_busses[bus]; + int rc; mca_dev->dev.parent = &mca_bus->dev; mca_dev->dev.bus = &mca_bus_type; @@ -108,13 +109,23 @@ int __init mca_register_device(int bus, struct mca_device *mca_dev) mca_dev->dev.dma_mask = &mca_dev->dma_mask; mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask; - if (device_register(&mca_dev->dev)) - return 0; + rc = device_register(&mca_dev->dev); + if (rc) + goto err_out; - device_create_file(&mca_dev->dev, &dev_attr_id); - device_create_file(&mca_dev->dev, &dev_attr_pos); + rc = device_create_file(&mca_dev->dev, &dev_attr_id); + if (rc) goto err_out_devreg; + rc = device_create_file(&mca_dev->dev, &dev_attr_pos); + if (rc) goto err_out_id; return 1; + +err_out_id: + device_remove_file(&mca_dev->dev, &dev_attr_id); +err_out_devreg: + device_unregister(&mca_dev->dev); +err_out: + return 0; } /* */ @@ -130,13 +141,16 @@ struct mca_bus * __devinit mca_attach_bus(int bus) return NULL; } - mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL); + mca_bus = kzalloc(sizeof(struct mca_bus), GFP_KERNEL); if (!mca_bus) return NULL; - memset(mca_bus, 0, sizeof(struct mca_bus)); + sprintf(mca_bus->dev.bus_id,"mca%d",bus); sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary"); - device_register(&mca_bus->dev); + if (device_register(&mca_bus->dev)) { + kfree(mca_bus); + return NULL; + } mca_root_busses[bus] = mca_bus; -- GitLab From bf02c082bf7a464518d45b9c178b8aa83f74dd5d Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Wed, 11 Oct 2006 01:22:24 -0700 Subject: [PATCH 1065/1619] [PATCH] fs/bio.c: tweaks - Calculate a variable in bvec_alloc_bs() only once needed, not earlier (bio.o down from 18408 to 18376 Bytes, 32 Bytes saved, probably due to data locality improvements). - Init variable idx to silence a gcc warning which already existed in the unmodified original base file (bvec_alloc_bs() handles idx correctly, so there's no need for the warning): fs/bio.c: In function `bio_alloc_bioset': fs/bio.c:169: warning: `idx' may be used uninitialized in this function Signed-off-by: Andreas Mohr Acked-by: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/bio.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/bio.c b/fs/bio.c index 8f93e939f21..f95c8749499 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -79,7 +79,6 @@ static struct bio_set *fs_bio_set; static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs) { struct bio_vec *bvl; - struct biovec_slab *bp; /* * see comment near bvec_array define! @@ -98,10 +97,12 @@ static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned lon * idx now points to the pool we want to allocate from */ - bp = bvec_slabs + *idx; bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask); - if (bvl) + if (bvl) { + struct biovec_slab *bp = bvec_slabs + *idx; + memset(bvl, 0, bp->nr_vecs * sizeof(struct bio_vec)); + } return bvl; } @@ -166,7 +167,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs) bio_init(bio); if (likely(nr_iovecs)) { - unsigned long idx; + unsigned long idx = 0; /* shut up gcc */ bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs); if (unlikely(!bvl)) { -- GitLab From 76fd020937f2d09f76a4cd8dbae1f3bec640ff0b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 01:22:25 -0700 Subject: [PATCH 1066/1619] [PATCH] ISDN: several minor fixes pcbit: kill 'may be used uninitialized' warning. although the code does eventually fill the 32 bits it cares about, the variable truly is accessed uninitialized in each macro. Easier to just clean it up now. sc: fix a ton of obviously incorrect printk's (some with missing arguments even) Signed-off-by: Jeff Garzik Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/pcbit/layer2.c | 1 + drivers/isdn/sc/init.c | 23 ++++++++++++----------- drivers/isdn/sc/packet.c | 14 +++++++------- drivers/isdn/sc/shmem.c | 2 +- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 13e7d219d1c..937fd212038 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -311,6 +311,7 @@ pcbit_deliver(void *data) dev->read_queue = frame->next; spin_unlock_irqrestore(&dev->lock, flags); + msg = 0; SET_MSG_CPU(msg, 0); SET_MSG_PROC(msg, 0); SET_MSG_CMD(msg, frame->skb->data[2]); diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index 222ca7c08ba..06c9872e8c6 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -98,13 +98,14 @@ static int __init sc_init(void) * Confirm the I/O Address with a test */ if(io[b] == 0) { - pr_debug("I/O Address 0x%x is in use.\n"); + pr_debug("I/O Address invalid.\n"); continue; } outb(0x18, io[b] + 0x400 * EXP_PAGE0); if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { - pr_debug("I/O Base 0x%x fails test\n"); + pr_debug("I/O Base 0x%x fails test\n", + io[b] + 0x400 * EXP_PAGE0); continue; } } @@ -158,8 +159,8 @@ static int __init sc_init(void) outb(0xFF, io[b] + RESET_OFFSET); msleep_interruptible(10000); } - pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b], - ram[b] == 0 ? "will" : "won't"); + pr_debug("RAM Base for board %d is 0x%lx, %s probe\n", b, + ram[b], ram[b] == 0 ? "will" : "won't"); if(ram[b]) { /* @@ -168,7 +169,7 @@ static int __init sc_init(void) * board model */ if(request_region(ram[b], SRAM_PAGESIZE, "sc test")) { - pr_debug("request_region for RAM base 0x%x succeeded\n", ram[b]); + pr_debug("request_region for RAM base 0x%lx succeeded\n", ram[b]); model = identify_board(ram[b], io[b]); release_region(ram[b], SRAM_PAGESIZE); } @@ -204,7 +205,7 @@ static int __init sc_init(void) * Nope, there was no place in RAM for the * board, or it couldn't be identified */ - pr_debug("Failed to find an adapter at 0x%x\n", ram[b]); + pr_debug("Failed to find an adapter at 0x%lx\n", ram[b]); continue; } @@ -451,7 +452,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) HWConfig_pl hwci; int x; - pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n", + pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n", rambase, iobase); /* @@ -490,7 +491,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) outb(PRI_BASEPG_VAL, pgport); msleep_interruptible(1000); sig = readl(rambase + SIG_OFFSET); - pr_debug("Looking for a signature, got 0x%x\n", sig); + pr_debug("Looking for a signature, got 0x%lx\n", sig); if(sig == SIGNATURE) return PRI_BOARD; @@ -500,7 +501,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) outb(BRI_BASEPG_VAL, pgport); msleep_interruptible(1000); sig = readl(rambase + SIG_OFFSET); - pr_debug("Looking for a signature, got 0x%x\n", sig); + pr_debug("Looking for a signature, got 0x%lx\n", sig); if(sig == SIGNATURE) return BRI_BOARD; @@ -510,7 +511,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) * Try to spot a card */ sig = readl(rambase + SIG_OFFSET); - pr_debug("Looking for a signature, got 0x%x\n", sig); + pr_debug("Looking for a signature, got 0x%lx\n", sig); if(sig != SIGNATURE) return -1; @@ -540,7 +541,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN); pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status); memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl)); - pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n" + pr_debug("Hardware Config: Interface: %s, RAM Size: %ld, Serial: %s\n" " Part: %s, Rev: %s\n", hwci.st_u_sense ? "S/T" : "U", hwci.ram_size, hwci.serial_no, hwci.part_no, hwci.rev_no); diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c index f50defc38ae..1e04676b016 100644 --- a/drivers/isdn/sc/packet.c +++ b/drivers/isdn/sc/packet.c @@ -44,7 +44,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data) return -ENODEV; } - pr_debug("%s: sndpkt: frst = 0x%x nxt = %d f = %d n = %d\n", + pr_debug("%s: sndpkt: frst = 0x%lx nxt = %d f = %d n = %d\n", sc_adapter[card]->devicename, sc_adapter[card]->channel[channel].first_sendbuf, sc_adapter[card]->channel[channel].next_sendbuf, @@ -66,7 +66,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data) ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf * BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf; ReqLnkWrite.msg_len = data->len; /* sk_buff size */ - pr_debug("%s: writing %d bytes to buffer offset 0x%x\n", + pr_debug("%s: writing %d bytes to buffer offset 0x%lx\n", sc_adapter[card]->devicename, ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset); memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len); @@ -74,7 +74,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data) /* * sendmessage */ - pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n", + pr_debug("%s: sndpkt size=%d, buf_offset=0x%lx buf_indx=%d\n", sc_adapter[card]->devicename, ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset, sc_adapter[card]->channel[channel].next_sendbuf); @@ -124,7 +124,7 @@ void rcvpkt(int card, RspMessage *rcvmsg) return; } skb_put(skb, rcvmsg->msg_data.response.msg_len); - pr_debug("%s: getting data from offset: 0x%x\n", + pr_debug("%s: getting data from offset: 0x%lx\n", sc_adapter[card]->devicename, rcvmsg->msg_data.response.buff_offset); memcpy_fromshmem(card, @@ -143,7 +143,7 @@ void rcvpkt(int card, RspMessage *rcvmsg) /* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */ newll.buff_offset = rcvmsg->msg_data.response.buff_offset; newll.msg_len = BUFFER_SIZE; - pr_debug("%s: recycled buffer at offset 0x%x size %d\n", + pr_debug("%s: recycled buffer at offset 0x%lx size %d\n", sc_adapter[card]->devicename, newll.buff_offset, newll.msg_len); sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead, @@ -186,7 +186,7 @@ int setup_buffers(int card, int c) sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2; sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2; sc_adapter[card]->channel[c-1].next_sendbuf = 0; - pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n", + pr_debug("%s: send buffer setup complete: first=0x%lx n=%d f=%d, nxt=%d\n", sc_adapter[card]->devicename, sc_adapter[card]->channel[c-1].first_sendbuf, sc_adapter[card]->channel[c-1].num_sendbufs, @@ -203,7 +203,7 @@ int setup_buffers(int card, int c) ((sc_adapter[card]->channel[c-1].first_sendbuf + (nBuffers / 2) * buffer_size) + (buffer_size * i)); RcvBuffOffset.msg_len = buffer_size; - pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n", + pr_debug("%s: adding RcvBuffer #%d offset=0x%lx sz=%d bufsz:%d\n", sc_adapter[card]->devicename, i + 1, RcvBuffOffset.buff_offset, RcvBuffOffset.msg_len,buffer_size); diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c index 24854826ca4..6f58862992d 100644 --- a/drivers/isdn/sc/shmem.c +++ b/drivers/isdn/sc/shmem.c @@ -61,7 +61,7 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n) spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename, ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80); - pr_debug("%s: copying %d bytes from %#x to %#x\n", + pr_debug("%s: copying %d bytes from %#lx to %#lx\n", sc_adapter[card]->devicename, n, (unsigned long) src, sc_adapter[card]->rambase + ((unsigned long) dest %0x4000)); -- GitLab From 5f6e3c836508926e50cebe17ad87f59666a7fb47 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 11 Oct 2006 01:22:26 -0700 Subject: [PATCH 1067/1619] [PATCH] md: use BUILD_BUG_ON Signed-off-by: Alexey Dobriyan Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 8e67634e79a..d47d38ac71b 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1413,7 +1413,7 @@ int bitmap_create(mddev_t *mddev) int err; sector_t start; - BUG_ON(sizeof(bitmap_super_t) != 256); + BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */ return 0; -- GitLab From 35d59fc5d6f318a28a99c5936171afd4edef28c8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:22:44 +0100 Subject: [PATCH 1068/1619] [PATCH] arm __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index dedbb449632..a657a28f08d 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -90,7 +90,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) info.si_signo = SIGFPE; info.si_code = sicode; - info.si_addr = (void *)(instruction_pointer(regs) - 4); + info.si_addr = (void __user *)(instruction_pointer(regs) - 4); /* * This is the same as NWFPE, because it's not clear what -- GitLab From fc048b5b0f2554bc953a8ada5b2e3b82bde2fcb0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:22:54 +0100 Subject: [PATCH 1069/1619] [PATCH] arm: use unsigned long instead of unsigned int in get_user() Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/asm-arm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h index 87aba57a66c..09ad0cab901 100644 --- a/include/asm-arm/uaccess.h +++ b/include/asm-arm/uaccess.h @@ -110,7 +110,7 @@ extern int __get_user_4(void *); #define get_user(x,p) \ ({ \ const register typeof(*(p)) __user *__p asm("r0") = (p);\ - register unsigned int __r2 asm("r2"); \ + register unsigned long __r2 asm("r2"); \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ -- GitLab From 399ad77b9098ed2eb27cbfbeb6449c1caab3c18e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:22:34 +0100 Subject: [PATCH 1070/1619] [PATCH] arm-versatile iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/arm/mach-versatile/core.c | 4 +-- arch/arm/mach-versatile/pci.c | 32 +++++++++++------------ include/asm-arm/arch-versatile/hardware.h | 4 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 2aa150b57ba..3b8576111c1 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -188,12 +188,12 @@ static struct map_desc versatile_io_desc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = VERSATILE_PCI_VIRT_BASE, + .virtual = (unsigned long)VERSATILE_PCI_VIRT_BASE, .pfn = __phys_to_pfn(VERSATILE_PCI_BASE), .length = VERSATILE_PCI_BASE_SIZE, .type = MT_DEVICE }, { - .virtual = VERSATILE_PCI_CFG_VIRT_BASE, + .virtual = (unsigned long)VERSATILE_PCI_CFG_VIRT_BASE, .pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE), .length = VERSATILE_PCI_CFG_BASE_SIZE, .type = MT_DEVICE diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c index 13bbd08ff84..5cd0b5d9e7e 100644 --- a/arch/arm/mach-versatile/pci.c +++ b/arch/arm/mach-versatile/pci.c @@ -40,14 +40,15 @@ * Cfg 42000000 - 42FFFFFF PCI config * */ -#define SYS_PCICTL IO_ADDRESS(VERSATILE_SYS_PCICTL) -#define PCI_IMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0) -#define PCI_IMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4) -#define PCI_IMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8) -#define PCI_SMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10) -#define PCI_SMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14) -#define PCI_SMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18) -#define PCI_SELFID IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc) +#define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n)) +#define SYS_PCICTL __IO_ADDRESS(VERSATILE_SYS_PCICTL) +#define PCI_IMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0) +#define PCI_IMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4) +#define PCI_IMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8) +#define PCI_SMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10) +#define PCI_SMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14) +#define PCI_SMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18) +#define PCI_SELFID __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc) #define DEVICE_ID_OFFSET 0x00 #define CSR_OFFSET 0x04 @@ -76,7 +77,7 @@ static int __init versatile_pci_slot_ignore(char *str) __setup("pci_slot_ignore=", versatile_pci_slot_ignore); -static unsigned long __pci_addr(struct pci_bus *bus, +static void __iomem *__pci_addr(struct pci_bus *bus, unsigned int devfn, int offset) { unsigned int busnr = bus->number; @@ -91,14 +92,14 @@ static unsigned long __pci_addr(struct pci_bus *bus, if (devfn > 255) BUG(); - return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) | + return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) | (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset); } static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - unsigned long addr = __pci_addr(bus, devfn, where); + void __iomem *addr = __pci_addr(bus, devfn, where & ~3); u32 v; int slot = PCI_SLOT(devfn); @@ -121,13 +122,12 @@ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int wh break; case 2: - v = __raw_readl(addr & ~3); - if (addr & 2) v >>= 16; + v = __raw_readl(addr); + if (where & 2) v >>= 16; v &= 0xffff; break; default: - addr &= ~3; v = __raw_readl(addr); break; } @@ -140,7 +140,7 @@ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int wh static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - unsigned long addr = __pci_addr(bus, devfn, where); + void __iomem *addr = __pci_addr(bus, devfn, where); int slot = PCI_SLOT(devfn); if (pci_slot_ignore & (1 << slot)) { @@ -279,7 +279,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys) printk("PCI core found (slot %d)\n",myslot); __raw_writel(myslot, PCI_SELFID); - local_pci_cfg_base = (void *) VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11); + local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11); val = __raw_readl(local_pci_cfg_base + CSR_OFFSET); val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; diff --git a/include/asm-arm/arch-versatile/hardware.h b/include/asm-arm/arch-versatile/hardware.h index 41c1bee342a..edc06598d18 100644 --- a/include/asm-arm/arch-versatile/hardware.h +++ b/include/asm-arm/arch-versatile/hardware.h @@ -28,8 +28,8 @@ /* * PCI space virtual addresses */ -#define VERSATILE_PCI_VIRT_BASE 0xe8000000 -#define VERSATILE_PCI_CFG_VIRT_BASE 0xe9000000 +#define VERSATILE_PCI_VIRT_BASE (void __iomem *)0xe8000000ul +#define VERSATILE_PCI_CFG_VIRT_BASE (void __iomem *)0xe9000000ul #if 0 #define VERSATILE_PCI_VIRT_MEM_BASE0 0xf4000000 -- GitLab From 7857a7f59d5d0b4e8c15606a79c0bcdbdef18ab6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:24:25 +0100 Subject: [PATCH 1071/1619] [PATCH] m32r: C99 initializers in setup.c Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/setup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c index 3f35ab3d2dc..0e7778be33c 100644 --- a/arch/m32r/kernel/setup.c +++ b/arch/m32r/kernel/setup.c @@ -369,10 +369,10 @@ static void c_stop(struct seq_file *m, void *v) } struct seq_operations cpuinfo_op = { - start: c_start, - next: c_next, - stop: c_stop, - show: show_cpuinfo, + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; #endif /* CONFIG_PROC_FS */ -- GitLab From 870e75a2930a1db02c7a5c09a13edcb4e3b07838 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:24:45 +0100 Subject: [PATCH 1072/1619] [PATCH] m32r: signal __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/signal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index a9174efe80c..b60cea4aeba 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -33,7 +33,7 @@ int do_signal(struct pt_regs *, sigset_t *); asmlinkage int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, +sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, struct pt_regs *regs) { @@ -78,8 +78,8 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct rt_sigframe { int sig; - struct siginfo *pinfo; - void *puc; + struct siginfo __user *pinfo; + void __user *puc; struct siginfo info; struct ucontext uc; // struct _fpstate fpstate; -- GitLab From 12ea59e8109d7192ecb2ac994588e24b11ab0428 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:24:35 +0100 Subject: [PATCH 1073/1619] [PATCH] m32r: NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/setup_mappi.c | 16 ++++++++-------- arch/m32r/kernel/smp.c | 2 +- arch/m32r/kernel/traps.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c index 67dbbdc9d11..6b2d77da068 100644 --- a/arch/m32r/kernel/setup_mappi.c +++ b/arch/m32r/kernel/setup_mappi.c @@ -86,7 +86,7 @@ void __init init_IRQ(void) /* INT0 : LAN controller (RTL8019AS) */ irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_INT0].action = 0; + irq_desc[M32R_IRQ_INT0].action = NULL; irq_desc[M32R_IRQ_INT0].depth = 1; icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; disable_mappi_irq(M32R_IRQ_INT0); @@ -95,7 +95,7 @@ void __init init_IRQ(void) /* MFT2 : system timer */ irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].action = NULL; irq_desc[M32R_IRQ_MFT2].depth = 1; icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; disable_mappi_irq(M32R_IRQ_MFT2); @@ -104,7 +104,7 @@ void __init init_IRQ(void) /* SIO0_R : uart receive data */ irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].action = NULL; irq_desc[M32R_IRQ_SIO0_R].depth = 1; icu_data[M32R_IRQ_SIO0_R].icucr = 0; disable_mappi_irq(M32R_IRQ_SIO0_R); @@ -112,7 +112,7 @@ void __init init_IRQ(void) /* SIO0_S : uart send data */ irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].action = NULL; irq_desc[M32R_IRQ_SIO0_S].depth = 1; icu_data[M32R_IRQ_SIO0_S].icucr = 0; disable_mappi_irq(M32R_IRQ_SIO0_S); @@ -120,7 +120,7 @@ void __init init_IRQ(void) /* SIO1_R : uart receive data */ irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].action = NULL; irq_desc[M32R_IRQ_SIO1_R].depth = 1; icu_data[M32R_IRQ_SIO1_R].icucr = 0; disable_mappi_irq(M32R_IRQ_SIO1_R); @@ -128,7 +128,7 @@ void __init init_IRQ(void) /* SIO1_S : uart send data */ irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].action = NULL; irq_desc[M32R_IRQ_SIO1_S].depth = 1; icu_data[M32R_IRQ_SIO1_S].icucr = 0; disable_mappi_irq(M32R_IRQ_SIO1_S); @@ -138,7 +138,7 @@ void __init init_IRQ(void) /* INT1 : pccard0 interrupt */ irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_INT1].action = 0; + irq_desc[M32R_IRQ_INT1].action = NULL; irq_desc[M32R_IRQ_INT1].depth = 1; icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; disable_mappi_irq(M32R_IRQ_INT1); @@ -146,7 +146,7 @@ void __init init_IRQ(void) /* INT2 : pccard1 interrupt */ irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED; irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type; - irq_desc[M32R_IRQ_INT2].action = 0; + irq_desc[M32R_IRQ_INT2].action = NULL; irq_desc[M32R_IRQ_INT2].depth = 1; icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; disable_mappi_irq(M32R_IRQ_INT2); diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index 722e21f556d..360129174b2 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -231,7 +231,7 @@ void smp_flush_tlb_all(void) local_irq_save(flags); __flush_tlb_all(); local_irq_restore(flags); - smp_call_function(flush_tlb_all_ipi, 0, 1, 1); + smp_call_function(flush_tlb_all_ipi, NULL, 1, 1); preempt_enable(); } diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c index c1daf2c40c7..97e0b1c0830 100644 --- a/arch/m32r/kernel/traps.c +++ b/arch/m32r/kernel/traps.c @@ -268,7 +268,7 @@ static __inline__ void do_trap(int trapnr, int signr, const char * str, #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ - do_trap(trapnr, signr, 0, regs, error_code, NULL); \ + do_trap(trapnr, signr, NULL, regs, error_code, NULL); \ } #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ -- GitLab From fd2c903b89a6c3cec9388eb24a134ebc1be20747 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:24:55 +0100 Subject: [PATCH 1074/1619] [PATCH] m32r: more __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/sys_m32r.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index b567351f3c5..b4e7bcb4354 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c @@ -31,7 +31,7 @@ /* * sys_tas() - test-and-set */ -asmlinkage int sys_tas(int *addr) +asmlinkage int sys_tas(int __user *addr) { int oldval; @@ -90,7 +90,7 @@ sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2, error = do_pipe(fd); if (!error) { - if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int))) + if (copy_to_user((void __user *)r0, fd, 2*sizeof(int))) error = -EFAULT; } return error; @@ -201,7 +201,7 @@ asmlinkage int sys_ipc(uint call, int first, int second, } } -asmlinkage int sys_uname(struct old_utsname * name) +asmlinkage int sys_uname(struct old_utsname __user * name) { int err; if (!name) -- GitLab From 4b4fcaa1a9eec90b44b66a67af6e130349ba008e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:25:45 +0100 Subject: [PATCH 1075/1619] [PATCH] misuse of strstr Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/gfs2/locking/dlm/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 1f94dd35a94..cdd1694e889 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -45,7 +45,7 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp, strncpy(buf, table_name, 256); buf[255] = '\0'; - p = strstr(buf, ":"); + p = strchr(buf, ':'); if (!p) { log_info("invalid table_name \"%s\"", table_name); kfree(ls); -- GitLab From b971018bae94bb43ae2402f884684ad69e85f931 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:27:57 +0100 Subject: [PATCH 1076/1619] [PATCH] m68k uaccess __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/asm-m68k/uaccess.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h index 88b1f47400e..e4c9f080ff2 100644 --- a/include/asm-m68k/uaccess.h +++ b/include/asm-m68k/uaccess.h @@ -76,7 +76,7 @@ asm volatile ("\n" \ break; \ case 8: \ { \ - const void *__pu_ptr = (ptr); \ + const void __user *__pu_ptr = (ptr); \ asm volatile ("\n" \ "1: moves.l %2,(%1)+\n" \ "2: moves.l %R2,(%1)\n" \ @@ -125,7 +125,7 @@ asm volatile ("\n" \ " .previous" \ : "+d" (res), "=&" #reg (__gu_val) \ : "m" (*(ptr)), "i" (err)); \ - (x) = (typeof(*(ptr)))(long)__gu_val; \ + (x) = (typeof(*(ptr)))(unsigned long)__gu_val; \ }) #define __get_user(x, ptr) \ @@ -221,16 +221,16 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n) switch (n) { case 1: - __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1); + __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1); break; case 2: - __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2); + __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2); break; case 3: __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,); break; case 4: - __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4); + __get_user_asm(res, *(u32 *)to, (u32 __user *)from, u32, l, r, 4); break; case 5: __constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,); @@ -302,16 +302,16 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n) switch (n) { case 1: - __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1); + __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1); break; case 2: - __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2); + __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2); break; case 3: __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,); break; case 4: - __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4); + __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4); break; case 5: __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,); -- GitLab From 1e5c374d3833f816b4840227c6949f689af0cb44 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:28:07 +0100 Subject: [PATCH 1077/1619] [PATCH] misc m68k __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m68k/kernel/process.c | 8 ++++---- arch/m68k/kernel/traps.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 45a46646c1b..24e83d54dce 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -221,13 +221,13 @@ asmlinkage int m68k_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; - int *parent_tidptr, *child_tidptr; + int __user *parent_tidptr, *child_tidptr; /* syscall2 puts clone_flags in d1 and usp in d2 */ clone_flags = regs->d1; newsp = regs->d2; - parent_tidptr = (int *)regs->d3; - child_tidptr = (int *)regs->d4; + parent_tidptr = (int __user *)regs->d3; + child_tidptr = (int __user *)regs->d4; if (!newsp) newsp = rdusp(); return do_fork(clone_flags, newsp, regs, 0, @@ -361,7 +361,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(char *name, char **argv, char **envp) +asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp) { int error; char * filename; diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 4569406a2e1..759fa244e6c 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -326,13 +326,13 @@ static inline int do_040writeback1(unsigned short wbs, unsigned long wba, switch (wbs & WBSIZ_040) { case BA_SIZE_BYTE: - res = put_user(wbd & 0xff, (char *)wba); + res = put_user(wbd & 0xff, (char __user *)wba); break; case BA_SIZE_WORD: - res = put_user(wbd & 0xffff, (short *)wba); + res = put_user(wbd & 0xffff, (short __user *)wba); break; case BA_SIZE_LONG: - res = put_user(wbd, (int *)wba); + res = put_user(wbd, (int __user *)wba); break; } -- GitLab From 437111ca381263520d23c877e55e0a83558e79da Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:28:17 +0100 Subject: [PATCH 1078/1619] [PATCH] sun3 __iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m68k/mm/sun3kmap.c | 8 ++++---- drivers/net/sun3_82586.c | 2 +- drivers/net/sun3lance.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c index 7f0d86f3fe7..8caa45908cb 100644 --- a/arch/m68k/mm/sun3kmap.c +++ b/arch/m68k/mm/sun3kmap.c @@ -59,7 +59,7 @@ static inline void do_pmeg_mapin(unsigned long phys, unsigned long virt, } } -void *sun3_ioremap(unsigned long phys, unsigned long size, +void __iomem *sun3_ioremap(unsigned long phys, unsigned long size, unsigned long type) { struct vm_struct *area; @@ -101,19 +101,19 @@ void *sun3_ioremap(unsigned long phys, unsigned long size, virt += seg_pages * PAGE_SIZE; } - return (void *)ret; + return (void __iomem *)ret; } -void *__ioremap(unsigned long phys, unsigned long size, int cache) +void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache) { return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO); } -void iounmap(void *addr) +void iounmap(void __iomem *addr) { vfree((void *)(PAGE_MASK & (unsigned long)addr)); } diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index d1d1885b029..a3220a96524 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -330,7 +330,7 @@ out2: out1: free_netdev(dev); out: - iounmap((void *)ioaddr); + iounmap((void __iomem *)ioaddr); return ERR_PTR(err); } diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 91c76544e4d..b865db363ba 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -286,7 +286,7 @@ struct net_device * __init sun3lance_probe(int unit) out1: #ifdef CONFIG_SUN3 - iounmap((void *)dev->base_addr); + iounmap((void __iomem *)dev->base_addr); #endif out: free_netdev(dev); @@ -326,7 +326,7 @@ static int __init lance_probe( struct net_device *dev) ioaddr_probe[1] = tmp2; #ifdef CONFIG_SUN3 - iounmap((void *)ioaddr); + iounmap((void __iomem *)ioaddr); #endif return 0; } @@ -956,7 +956,7 @@ void cleanup_module(void) { unregister_netdev(sun3lance_dev); #ifdef CONFIG_SUN3 - iounmap((void *)sun3lance_dev->base_addr); + iounmap((void __iomem *)sun3lance_dev->base_addr); #endif free_netdev(sun3lance_dev); } -- GitLab From 2e811488cedddefb9d1df97c260b6048ea8ef835 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:28:27 +0100 Subject: [PATCH 1079/1619] [PATCH] clean m68k ksyms sun3_ksyms gone, m68k_ksyms trimmed down to exports of the assembler ones, for sun3 added the missing exports of __ioremap() and iounmap(). Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m68k/kernel/m68k_ksyms.c | 51 ----------------------------------- arch/m68k/kernel/process.c | 3 +++ arch/m68k/kernel/setup.c | 15 +++++++++++ arch/m68k/mm/kmap.c | 4 +++ arch/m68k/mm/memory.c | 8 ++++-- arch/m68k/mm/sun3kmap.c | 3 +++ arch/m68k/sun3/Makefile | 2 +- arch/m68k/sun3/idprom.c | 3 +++ arch/m68k/sun3/sun3_ksyms.c | 13 --------- arch/m68k/sun3/sun3dvma.c | 6 ++++- 10 files changed, 40 insertions(+), 68 deletions(-) delete mode 100644 arch/m68k/sun3/sun3_ksyms.c diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index f9636e84e6a..6fc69c74fe2 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -1,61 +1,10 @@ #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include #include -#include asmlinkage long long __ashldi3 (long long, int); asmlinkage long long __ashrdi3 (long long, int); asmlinkage long long __lshrdi3 (long long, int); asmlinkage long long __muldi3 (long long, long long); -extern char m68k_debug_device[]; - -/* platform dependent support */ - -EXPORT_SYMBOL(m68k_machtype); -EXPORT_SYMBOL(m68k_cputype); -EXPORT_SYMBOL(m68k_is040or060); -EXPORT_SYMBOL(m68k_realnum_memory); -EXPORT_SYMBOL(m68k_memory); -#ifndef CONFIG_SUN3 -EXPORT_SYMBOL(cache_push); -EXPORT_SYMBOL(cache_clear); -#ifndef CONFIG_SINGLE_MEMORY_CHUNK -EXPORT_SYMBOL(mm_vtop); -EXPORT_SYMBOL(mm_ptov); -EXPORT_SYMBOL(mm_end_of_chunk); -#else -EXPORT_SYMBOL(m68k_memoffset); -#endif /* !CONFIG_SINGLE_MEMORY_CHUNK */ -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(kernel_set_cachemode); -#endif /* !CONFIG_SUN3 */ -EXPORT_SYMBOL(m68k_debug_device); -EXPORT_SYMBOL(mach_hwclk); -EXPORT_SYMBOL(mach_get_ss); -EXPORT_SYMBOL(mach_get_rtc_pll); -EXPORT_SYMBOL(mach_set_rtc_pll); -#ifdef CONFIG_INPUT_M68K_BEEP_MODULE -EXPORT_SYMBOL(mach_beep); -#endif -EXPORT_SYMBOL(dump_fpu); -EXPORT_SYMBOL(dump_thread); -EXPORT_SYMBOL(kernel_thread); -#ifdef CONFIG_VME -EXPORT_SYMBOL(vme_brdtype); -#endif /* The following are special because they're not called explicitly (the C compiler generates them). Fortunately, diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 24e83d54dce..99fc1226f7f 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -187,6 +187,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) set_fs (fs); return pid; } +EXPORT_SYMBOL(kernel_thread); void flush_thread(void) { @@ -311,6 +312,7 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) : "memory"); return 1; } +EXPORT_SYMBOL(dump_fpu); /* * fill in the user structure for a core dump.. @@ -357,6 +359,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) /* dump floating point stuff */ dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); } +EXPORT_SYMBOL(dump_thread); /* * sys_execve() executes a new program. diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 42d5b85f335..9af3ee0e555 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -42,27 +42,37 @@ unsigned long m68k_machtype; unsigned long m68k_cputype; +EXPORT_SYMBOL(m68k_machtype); +EXPORT_SYMBOL(m68k_cputype); unsigned long m68k_fputype; unsigned long m68k_mmutype; #ifdef CONFIG_VME unsigned long vme_brdtype; +EXPORT_SYMBOL(vme_brdtype); #endif int m68k_is040or060; +EXPORT_SYMBOL(m68k_is040or060); extern int end; extern unsigned long availmem; int m68k_num_memory; int m68k_realnum_memory; +EXPORT_SYMBOL(m68k_realnum_memory); +#ifdef CONFIG_SINGLE_MEMORY_CHUNK unsigned long m68k_memoffset; +EXPORT_SYMBOL(m68k_memoffset); +#endif struct mem_info m68k_memory[NUM_MEMINFO]; +EXPORT_SYMBOL(m68k_memory); static struct mem_info m68k_ramdisk; static char m68k_command_line[CL_SIZE]; char m68k_debug_device[6] = ""; +EXPORT_SYMBOL(m68k_debug_device); void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; /* machine dependent irq functions */ @@ -72,10 +82,14 @@ int (*mach_get_hardware_list) (char *buffer); /* machine dependent timer functions */ unsigned long (*mach_gettimeoffset) (void); int (*mach_hwclk) (int, struct rtc_time*); +EXPORT_SYMBOL(mach_hwclk); int (*mach_set_clock_mmss) (unsigned long); unsigned int (*mach_get_ss)(void); int (*mach_get_rtc_pll)(struct rtc_pll_info *); int (*mach_set_rtc_pll)(struct rtc_pll_info *); +EXPORT_SYMBOL(mach_get_ss); +EXPORT_SYMBOL(mach_get_rtc_pll); +EXPORT_SYMBOL(mach_set_rtc_pll); void (*mach_reset)( void ); void (*mach_halt)( void ); void (*mach_power_off)( void ); @@ -89,6 +103,7 @@ void (*mach_l2_flush) (int); #endif #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) void (*mach_beep)(unsigned int, unsigned int); +EXPORT_SYMBOL(mach_beep); #endif #if defined(CONFIG_ISA) && defined(MULTI_ISA) int isa_type; diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c index f46f049d29f..b54ef1726c5 100644 --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -7,6 +7,7 @@ * used by other architectures /Roman Zippel */ +#include #include #include #include @@ -219,6 +220,7 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla return (void __iomem *)retaddr; } +EXPORT_SYMBOL(__ioremap); /* * Unmap a ioremap()ed region again @@ -234,6 +236,7 @@ void iounmap(void __iomem *addr) free_io_area((__force void *)addr); #endif } +EXPORT_SYMBOL(iounmap); /* * __iounmap unmaps nearly everything, so be careful @@ -360,3 +363,4 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode) flush_tlb_all(); } +EXPORT_SYMBOL(kernel_set_cachemode); diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index a0c095e1722..0f88812822b 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -4,6 +4,7 @@ * Copyright (C) 1995 Hamish Macdonald */ +#include #include #include #include @@ -157,9 +158,8 @@ unsigned long mm_vtop(unsigned long vaddr) return -1; } -#endif +EXPORT_SYMBOL(mm_vtop); -#ifndef CONFIG_SINGLE_MEMORY_CHUNK unsigned long mm_ptov (unsigned long paddr) { int i = 0; @@ -185,6 +185,7 @@ unsigned long mm_ptov (unsigned long paddr) #endif return -1; } +EXPORT_SYMBOL(mm_ptov); #endif /* invalidate page in both caches */ @@ -298,6 +299,7 @@ void cache_clear (unsigned long paddr, int len) mach_l2_flush(0); #endif } +EXPORT_SYMBOL(cache_clear); /* probably can be unexported */ /* @@ -350,6 +352,7 @@ void cache_push (unsigned long paddr, int len) mach_l2_flush(1); #endif } +EXPORT_SYMBOL(cache_push); /* probably can be unexported */ #ifndef CONFIG_SINGLE_MEMORY_CHUNK int mm_end_of_chunk (unsigned long addr, int len) @@ -361,4 +364,5 @@ int mm_end_of_chunk (unsigned long addr, int len) return 1; return 0; } +EXPORT_SYMBOL(mm_end_of_chunk); #endif diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c index 8caa45908cb..1af24cb5bfe 100644 --- a/arch/m68k/mm/sun3kmap.c +++ b/arch/m68k/mm/sun3kmap.c @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include @@ -112,11 +113,13 @@ void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache) return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO); } +EXPORT_SYMBOL(__ioremap); void iounmap(void __iomem *addr) { vfree((void *)(PAGE_MASK & (unsigned long)addr)); } +EXPORT_SYMBOL(iounmap); /* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val, * trapping the potential read fault. Returns 0 if the access faulted, diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile index 4d4f0695d98..be1a8470d63 100644 --- a/arch/m68k/sun3/Makefile +++ b/arch/m68k/sun3/Makefile @@ -2,6 +2,6 @@ # Makefile for Linux arch/m68k/sun3 source directory # -obj-y := sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o +obj-y := sun3ints.o sun3dvma.o sbus.o idprom.o obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c index 02c1fee6fe7..dca6ab6a4ed 100644 --- a/arch/m68k/sun3/idprom.c +++ b/arch/m68k/sun3/idprom.c @@ -6,6 +6,7 @@ * Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au) */ +#include #include #include #include @@ -16,6 +17,8 @@ #include /* Fun with Sun released architectures. */ struct idprom *idprom; +EXPORT_SYMBOL(idprom); + static struct idprom idprom_buffer; /* Here is the master table of Sun machines which use some implementation diff --git a/arch/m68k/sun3/sun3_ksyms.c b/arch/m68k/sun3/sun3_ksyms.c deleted file mode 100644 index 43e5a9af8ab..00000000000 --- a/arch/m68k/sun3/sun3_ksyms.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include -#include - -/* - * Add things here when you find the need for it. - */ -EXPORT_SYMBOL(dvma_map_align); -EXPORT_SYMBOL(dvma_unmap); -EXPORT_SYMBOL(dvma_malloc_align); -EXPORT_SYMBOL(dvma_free); -EXPORT_SYMBOL(idprom); diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c index a2bc2da7f8f..8709677fa02 100644 --- a/arch/m68k/sun3/sun3dvma.c +++ b/arch/m68k/sun3/sun3dvma.c @@ -6,6 +6,7 @@ * Contains common routines for sun3/sun3x DVMA management. */ +#include #include #include #include @@ -312,6 +313,7 @@ inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align) BUG(); return 0; } +EXPORT_SYMBOL(dvma_map_align); void dvma_unmap(void *baddr) { @@ -327,7 +329,7 @@ void dvma_unmap(void *baddr) return; } - +EXPORT_SYMBOL(dvma_unmap); void *dvma_malloc_align(unsigned long len, unsigned long align) { @@ -367,6 +369,7 @@ void *dvma_malloc_align(unsigned long len, unsigned long align) return (void *)vaddr; } +EXPORT_SYMBOL(dvma_malloc_align); void dvma_free(void *vaddr) { @@ -374,3 +377,4 @@ void dvma_free(void *vaddr) return; } +EXPORT_SYMBOL(dvma_free); -- GitLab From 2db5f59ca74d911f93c39494db1581c3c93d5a29 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:28:37 +0100 Subject: [PATCH 1080/1619] [PATCH] amiga_floppy_init() in non-modular case It used to be called directly, but that got lost in 2.1.87-pre1. Similar breakage in ataflop got fixed 3 years ago, this one had gone unnoticed. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/amiflop.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 5d254b71450..5d656217153 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1709,10 +1709,13 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) return get_disk(unit[drive].gendisk); } -int __init amiga_floppy_init(void) +static int __init amiga_floppy_init(void) { int i, ret; + if (!MACH_IS_AMIGA) + return -ENXIO; + if (!AMIGAHW_PRESENT(AMI_FLOPPY)) return -ENXIO; @@ -1809,15 +1812,9 @@ out_blkdev: return ret; } +module_init(amiga_floppy_init); #ifdef MODULE -int init_module(void) -{ - if (!MACH_IS_AMIGA) - return -ENXIO; - return amiga_floppy_init(); -} - #if 0 /* not safe to unload */ void cleanup_module(void) { -- GitLab From f39d88adc5daf544cf9ae666a097b595b212871e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:28:47 +0100 Subject: [PATCH 1081/1619] [PATCH] z2_init() in non-modular case ... another victim - this time of 2.5.1-pre2 Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/z2ram.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 82ddbdd7bd4..7cc2685ca84 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -329,7 +329,7 @@ static struct kobject *z2_find(dev_t dev, int *part, void *data) static struct request_queue *z2_queue; -int __init +static int __init z2_init(void) { int ret; @@ -370,26 +370,7 @@ err: return ret; } -#if defined(MODULE) - -MODULE_LICENSE("GPL"); - -int -init_module( void ) -{ - int error; - - error = z2_init(); - if ( error == 0 ) - { - printk( KERN_INFO DEVICE_NAME ": loaded as module\n" ); - } - - return error; -} - -void -cleanup_module( void ) +static void __exit z2_exit(void) { int i, j; blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256); @@ -425,4 +406,7 @@ cleanup_module( void ) return; } -#endif + +module_init(z2_init); +module_exit(z2_exit); +MODULE_LICENSE("GPL"); -- GitLab From 9ab6a45394715918b025f2d3b799477295af4cc0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:40:22 +0100 Subject: [PATCH 1082/1619] [PATCH] remove bogus arch-specific syscall exports Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/arm/kernel/armksyms.c | 6 ------ arch/arm26/kernel/armksyms.c | 8 -------- arch/parisc/kernel/parisc_ksyms.c | 4 ---- arch/s390/kernel/s390_ksyms.c | 1 - 4 files changed, 19 deletions(-) diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index da69e660574..4779f474f91 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -178,9 +178,3 @@ EXPORT_SYMBOL(_find_next_zero_bit_be); EXPORT_SYMBOL(_find_first_bit_be); EXPORT_SYMBOL(_find_next_bit_be); #endif - - /* syscalls */ -EXPORT_SYMBOL(sys_write); -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_exit); -EXPORT_SYMBOL(sys_wait4); diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c index 07907b6ecb6..93293d04b30 100644 --- a/arch/arm26/kernel/armksyms.c +++ b/arch/arm26/kernel/armksyms.c @@ -202,14 +202,6 @@ EXPORT_SYMBOL(_find_next_zero_bit_le); EXPORT_SYMBOL(elf_platform); EXPORT_SYMBOL(elf_hwcap); - /* syscalls */ -EXPORT_SYMBOL(sys_write); -EXPORT_SYMBOL(sys_read); -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_open); -EXPORT_SYMBOL(sys_exit); -EXPORT_SYMBOL(sys_wait4); - #ifdef CONFIG_PREEMPT EXPORT_SYMBOL(kernel_flag); #endif diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 6d57553d8ef..8f6a0b312f7 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -69,10 +69,6 @@ EXPORT_SYMBOL(memcpy_toio); EXPORT_SYMBOL(memcpy_fromio); EXPORT_SYMBOL(memset_io); -#include -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_write); - #include EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 9f19e833a56..90b5ef529eb 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -51,4 +51,3 @@ EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_devno); EXPORT_SYMBOL(console_irq); -EXPORT_SYMBOL(sys_wait4); -- GitLab From cff52daffa080eff6353f44df418b080dacefb96 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:40:22 +0100 Subject: [PATCH 1083/1619] [PATCH] alpha_ksyms.c cleanup taken exports to actual definitions of symbols being exported. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/alpha_ksyms.c | 93 +------------------------------ arch/alpha/kernel/core_irongate.c | 2 + arch/alpha/kernel/irq_alpha.c | 3 + arch/alpha/kernel/pci-noop.c | 1 + arch/alpha/kernel/pci_iommu.c | 17 +++++- arch/alpha/kernel/process.c | 5 ++ arch/alpha/kernel/setup.c | 6 ++ arch/alpha/kernel/smp.c | 8 +++ arch/alpha/kernel/time.c | 1 + arch/alpha/mm/numa.c | 2 + 10 files changed, 44 insertions(+), 94 deletions(-) diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 8b02420f732..692809e4aec 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -6,41 +6,14 @@ */ #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 -#include -#include #include -extern struct hwrpb_struct *hwrpb; -extern spinlock_t rtc_lock; - /* these are C runtime functions with special calling conventions: */ extern void __divl (void); extern void __reml (void); @@ -52,14 +25,9 @@ extern void __divqu (void); extern void __remqu (void); EXPORT_SYMBOL(alpha_mv); -EXPORT_SYMBOL(screen_info); -EXPORT_SYMBOL(perf_irq); EXPORT_SYMBOL(callback_getenv); EXPORT_SYMBOL(callback_setenv); EXPORT_SYMBOL(callback_save_env); -#ifdef CONFIG_ALPHA_GENERIC -EXPORT_SYMBOL(alpha_using_srm); -#endif /* CONFIG_ALPHA_GENERIC */ /* platform dependent support */ EXPORT_SYMBOL(strcat); @@ -77,47 +45,14 @@ EXPORT_SYMBOL(__constant_c_memset); EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(clear_page); -EXPORT_SYMBOL(__direct_map_base); -EXPORT_SYMBOL(__direct_map_size); - -#ifdef CONFIG_PCI -EXPORT_SYMBOL(pci_alloc_consistent); -EXPORT_SYMBOL(pci_free_consistent); -EXPORT_SYMBOL(pci_map_single); -EXPORT_SYMBOL(pci_map_page); -EXPORT_SYMBOL(pci_unmap_single); -EXPORT_SYMBOL(pci_unmap_page); -EXPORT_SYMBOL(pci_map_sg); -EXPORT_SYMBOL(pci_unmap_sg); -EXPORT_SYMBOL(pci_dma_supported); -EXPORT_SYMBOL(pci_dac_dma_supported); -EXPORT_SYMBOL(pci_dac_page_to_dma); -EXPORT_SYMBOL(pci_dac_dma_to_page); -EXPORT_SYMBOL(pci_dac_dma_to_offset); -EXPORT_SYMBOL(alpha_gendev_to_pci); -#endif -EXPORT_SYMBOL(dma_set_mask); - -EXPORT_SYMBOL(dump_thread); -EXPORT_SYMBOL(dump_elf_thread); -EXPORT_SYMBOL(dump_elf_task); -EXPORT_SYMBOL(dump_elf_task_fp); -EXPORT_SYMBOL(hwrpb); -EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(alpha_read_fp_reg); EXPORT_SYMBOL(alpha_read_fp_reg_s); EXPORT_SYMBOL(alpha_write_fp_reg); EXPORT_SYMBOL(alpha_write_fp_reg_s); -/* In-kernel system calls. */ +/* entry.S */ EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(sys_dup); -EXPORT_SYMBOL(sys_exit); -EXPORT_SYMBOL(sys_write); -EXPORT_SYMBOL(sys_lseek); EXPORT_SYMBOL(kernel_execve); -EXPORT_SYMBOL(sys_setsid); -EXPORT_SYMBOL(sys_wait4); /* Networking helper routines. */ EXPORT_SYMBOL(csum_tcpudp_magic); @@ -134,10 +69,6 @@ EXPORT_SYMBOL(alpha_fp_emul_imprecise); EXPORT_SYMBOL(alpha_fp_emul); #endif -#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK -EXPORT_SYMBOL(__min_ipl); -#endif - /* * The following are specially called from the uaccess assembly stubs. */ @@ -160,26 +91,9 @@ EXPORT_SYMBOL(up); */ #ifdef CONFIG_SMP -EXPORT_SYMBOL(flush_tlb_mm); -EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(flush_tlb_page); -EXPORT_SYMBOL(smp_imb); -EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(smp_num_cpus); -EXPORT_SYMBOL(smp_call_function); -EXPORT_SYMBOL(smp_call_function_on_cpu); EXPORT_SYMBOL(_atomic_dec_and_lock); #endif /* CONFIG_SMP */ -/* - * NUMA specific symbols - */ -#ifdef CONFIG_DISCONTIGMEM -EXPORT_SYMBOL(node_data); -#endif /* CONFIG_DISCONTIGMEM */ - -EXPORT_SYMBOL(rtc_lock); - /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in @@ -200,8 +114,3 @@ EXPORT_SYMBOL(__remqu); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memchr); - -#ifdef CONFIG_ALPHA_IRONGATE -EXPORT_SYMBOL(irongate_ioremap); -EXPORT_SYMBOL(irongate_iounmap); -#endif diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c index 138d497d1cc..e4a0bcf1d28 100644 --- a/arch/alpha/kernel/core_irongate.c +++ b/arch/alpha/kernel/core_irongate.c @@ -404,6 +404,7 @@ irongate_ioremap(unsigned long addr, unsigned long size) #endif return (void __iomem *)vaddr; } +EXPORT_SYMBOL(irongate_ioremap); void irongate_iounmap(volatile void __iomem *xaddr) @@ -414,3 +415,4 @@ irongate_iounmap(volatile void __iomem *xaddr) if (addr) return vfree((void *)(PAGE_MASK & addr)); } +EXPORT_SYMBOL(irongate_iounmap); diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 6dd126b8be8..e16aeb6e79e 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ /* Hack minimum IPL during interrupt processing for broken hardware. */ #ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK int __min_ipl; +EXPORT_SYMBOL(__min_ipl); #endif /* @@ -30,6 +32,7 @@ dummy_perf(unsigned long vector, struct pt_regs *regs) } void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf; +EXPORT_SYMBOL(perf_irq); /* * The main interrupt entry point. diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c index fff5cf93e81..174b729c504 100644 --- a/arch/alpha/kernel/pci-noop.c +++ b/arch/alpha/kernel/pci-noop.c @@ -201,6 +201,7 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } +EXPORT_SYMBOL(dma_set_mask); void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) { diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index c468e312e5f..6e7d1fe6e93 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -300,6 +300,7 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int dir) dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; return pci_map_single_1(pdev, cpu_addr, size, dac_allowed); } +EXPORT_SYMBOL(pci_map_single); dma_addr_t pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset, @@ -314,6 +315,7 @@ pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset, return pci_map_single_1(pdev, (char *)page_address(page) + offset, size, dac_allowed); } +EXPORT_SYMBOL(pci_map_page); /* Unmap a single streaming mode DMA translation. The DMA_ADDR and SIZE must match what was provided for in a previous pci_map_single @@ -379,6 +381,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n", dma_addr, size, npages, __builtin_return_address(0)); } +EXPORT_SYMBOL(pci_unmap_single); void pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr, @@ -386,6 +389,7 @@ pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr, { pci_unmap_single(pdev, dma_addr, size, direction); } +EXPORT_SYMBOL(pci_unmap_page); /* Allocate and map kernel buffer using consistent mode DMA for PCI device. Returns non-NULL cpu-view pointer to the buffer if @@ -427,6 +431,7 @@ try_again: return cpu_addr; } +EXPORT_SYMBOL(pci_alloc_consistent); /* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must be values that were returned from pci_alloc_consistent. SIZE must @@ -444,7 +449,7 @@ pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr, DBGA2("pci_free_consistent: [%x,%lx] from %p\n", dma_addr, size, __builtin_return_address(0)); } - +EXPORT_SYMBOL(pci_free_consistent); /* Classify the elements of the scatterlist. Write dma_address of each element with: @@ -672,6 +677,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, pci_unmap_sg(pdev, start, out - start, direction); return 0; } +EXPORT_SYMBOL(pci_map_sg); /* Unmap a set of streaming mode DMA translations. Again, cpu read rules concerning calls here are the same as for pci_unmap_single() @@ -752,6 +758,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, DBGA("pci_unmap_sg: %ld entries\n", nents - (end - sg)); } +EXPORT_SYMBOL(pci_unmap_sg); /* Return whether the given PCI device DMA address mask can be @@ -786,6 +793,7 @@ pci_dma_supported(struct pci_dev *pdev, u64 mask) return 0; } +EXPORT_SYMBOL(pci_dma_supported); /* @@ -908,6 +916,7 @@ pci_dac_dma_supported(struct pci_dev *dev, u64 mask) return ok; } +EXPORT_SYMBOL(pci_dac_dma_supported); dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, @@ -917,6 +926,7 @@ pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, + __pa(page_address(page)) + (dma64_addr_t) offset); } +EXPORT_SYMBOL(pci_dac_page_to_dma); struct page * pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) @@ -924,13 +934,14 @@ pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset; return virt_to_page(__va(paddr)); } +EXPORT_SYMBOL(pci_dac_dma_to_page); unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) { return (dma_addr & ~PAGE_MASK); } - +EXPORT_SYMBOL(pci_dac_dma_to_offset); /* Helper for generic DMA-mapping functions. */ @@ -957,6 +968,7 @@ alpha_gendev_to_pci(struct device *dev) /* This assumes ISA bus master with dma_mask 0xffffff. */ return NULL; } +EXPORT_SYMBOL(alpha_gendev_to_pci); int dma_set_mask(struct device *dev, u64 mask) @@ -969,3 +981,4 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } +EXPORT_SYMBOL(dma_set_mask); diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index b3a8a298036..3370e6faeae 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -205,6 +205,7 @@ start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) regs->ps = 8; wrusp(sp); } +EXPORT_SYMBOL(start_thread); /* * Free current thread data structures etc.. @@ -376,6 +377,7 @@ dump_thread(struct pt_regs * pt, struct user * dump) dump->regs[EF_A2] = pt->r18; memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8); } +EXPORT_SYMBOL(dump_thread); /* * Fill in the user structure for a ELF core dump. @@ -424,6 +426,7 @@ dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti) useful value of the thread's UNIQUE field. */ dest[32] = ti->pcb.unique; } +EXPORT_SYMBOL(dump_elf_thread); int dump_elf_task(elf_greg_t *dest, struct task_struct *task) @@ -431,6 +434,7 @@ dump_elf_task(elf_greg_t *dest, struct task_struct *task) dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task)); return 1; } +EXPORT_SYMBOL(dump_elf_task); int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) @@ -439,6 +443,7 @@ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) memcpy(dest, sw->fp, 32 * 8); return 1; } +EXPORT_SYMBOL(dump_elf_task_fp); /* * sys_execve() executes a new program. diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index a94e6d93e2e..1aea7c7c683 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -66,6 +66,7 @@ static struct notifier_block alpha_panic_block = { struct hwrpb_struct *hwrpb; +EXPORT_SYMBOL(hwrpb); unsigned long srm_hae; int alpha_l1i_cacheshape; @@ -111,6 +112,7 @@ unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE; #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; int alpha_using_srm; +EXPORT_SYMBOL(alpha_using_srm); #endif static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long, @@ -137,6 +139,8 @@ struct screen_info screen_info = { .orig_video_points = 16 }; +EXPORT_SYMBOL(screen_info); + /* * The direct map I/O window, if any. This should be the same * for all busses, since it's used by virt_to_bus. @@ -144,6 +148,8 @@ struct screen_info screen_info = { unsigned long __direct_map_base; unsigned long __direct_map_size; +EXPORT_SYMBOL(__direct_map_base); +EXPORT_SYMBOL(__direct_map_size); /* * Declare all of the machine vectors. diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 596780e2c7d..d1ec4f51df1 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -52,6 +52,7 @@ /* A collection of per-processor data. */ struct cpuinfo_alpha cpu_data[NR_CPUS]; +EXPORT_SYMBOL(cpu_data); /* A collection of single bit ipi messages. */ static struct { @@ -74,6 +75,7 @@ EXPORT_SYMBOL(cpu_online_map); int smp_num_probed; /* Internal processor count */ int smp_num_cpus = 1; /* Number that came online. */ +EXPORT_SYMBOL(smp_num_cpus); extern void calibrate_delay(void); @@ -790,6 +792,7 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry, return 0; } +EXPORT_SYMBOL(smp_call_function_on_cpu); int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) @@ -797,6 +800,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait) return smp_call_function_on_cpu (func, info, retry, wait, cpu_online_map); } +EXPORT_SYMBOL(smp_call_function); static void ipi_imb(void *ignored) @@ -811,6 +815,7 @@ smp_imb(void) if (on_each_cpu(ipi_imb, NULL, 1, 1)) printk(KERN_CRIT "smp_imb: timed out\n"); } +EXPORT_SYMBOL(smp_imb); static void ipi_flush_tlb_all(void *ignored) @@ -866,6 +871,7 @@ flush_tlb_mm(struct mm_struct *mm) preempt_enable(); } +EXPORT_SYMBOL(flush_tlb_mm); struct flush_tlb_page_struct { struct vm_area_struct *vma; @@ -918,6 +924,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) preempt_enable(); } +EXPORT_SYMBOL(flush_tlb_page); void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) @@ -925,6 +932,7 @@ flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long e /* On the Alpha we always flush the whole user tlb. */ flush_tlb_mm(vma->vm_mm); } +EXPORT_SYMBOL(flush_tlb_range); static void ipi_flush_icache_page(void *x) diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index cf066652398..d7053eb4ffc 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -57,6 +57,7 @@ static int set_rtc_mmss(unsigned long); DEFINE_SPINLOCK(rtc_lock); +EXPORT_SYMBOL(rtc_lock); #define TICK_SIZE (tick_nsec / 1000) diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c index b826f58c6e7..e3e3806a6f2 100644 --- a/arch/alpha/mm/numa.c +++ b/arch/alpha/mm/numa.c @@ -13,12 +13,14 @@ #include #include #include +#include #include #include pg_data_t node_data[MAX_NUMNODES]; bootmem_data_t node_bdata[MAX_NUMNODES]; +EXPORT_SYMBOL(node_data); #undef DEBUG_DISCONTIG #ifdef DEBUG_DISCONTIG -- GitLab From f061c5847bcc72eebf6a783f458d42092eac1b6a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2006 17:45:47 +0100 Subject: [PATCH 1084/1619] [PATCH] i2Output always takes kernel data now Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/ip2/i2lib.c | 11 +++-------- drivers/char/ip2/i2lib.h | 2 +- drivers/char/ip2/ip2main.c | 4 ++-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index fc944d375be..54d93f0345e 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -1007,7 +1007,7 @@ i2InputAvailable(i2ChanStrPtr pCh) // applications that one cannot break out of. //****************************************************************************** static int -i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) +i2Output(i2ChanStrPtr pCh, const char *pSource, int count) { i2eBordStrPtr pB; unsigned char *pInsert; @@ -1020,7 +1020,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) int bailout = 10; - ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user ); + ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, 0 ); // Ensure channel structure seems real if ( !i2Validate ( pCh ) ) @@ -1087,12 +1087,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) DATA_COUNT_OF(pInsert) = amountToMove; // Move the data - if ( user ) { - rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource, - amountToMove ); - } else { - memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); - } + memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); // Adjust pointers and indices pSource += amountToMove; pCh->Obuf_char_count += amountToMove; diff --git a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h index 952e113ccd8..e559e9bac06 100644 --- a/drivers/char/ip2/i2lib.h +++ b/drivers/char/ip2/i2lib.h @@ -332,7 +332,7 @@ static int i2QueueCommands(int, i2ChanStrPtr, int, int, cmdSyntaxPtr,...); static int i2GetStatus(i2ChanStrPtr, int); static int i2Input(i2ChanStrPtr); static int i2InputFlush(i2ChanStrPtr); -static int i2Output(i2ChanStrPtr, const char *, int, int); +static int i2Output(i2ChanStrPtr, const char *, int); static int i2OutputFree(i2ChanStrPtr); static int i2ServiceBoard(i2eBordStrPtr); static void i2DrainOutput(i2ChanStrPtr, int); diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 858ba5432c9..a3f32d46d2f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1704,7 +1704,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count) /* This is the actual move bit. Make sure it does what we need!!!!! */ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); - bytesSent = i2Output( pCh, pData, count, 0 ); + bytesSent = i2Output( pCh, pData, count); WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent ); @@ -1764,7 +1764,7 @@ ip2_flush_chars( PTTY tty ) // // We may need to restart i2Output if it does not fullfill this request // - strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 ); + strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff); if ( strip != pCh->Pbuf_stuff ) { memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip ); } -- GitLab From ea5742830ada301de22a68e604b48fb6107c270f Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 10 Oct 2006 16:56:11 +0900 Subject: [PATCH 1085/1619] [MIPS] Fix timer setup for Jazz Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/jazz/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 6dc4135d6e1..d848f1a0778 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -37,7 +37,7 @@ extern void jazz_machine_restart(char *command); extern void jazz_machine_halt(void); extern void jazz_machine_power_off(void); -void __init plat_time_init(struct irqaction *irq) +void __init plat_timer_setup(struct irqaction *irq) { /* set the clock to 100 Hz */ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); -- GitLab From f94054121efcba573f12101a75a4be93e871b309 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 10 Oct 2006 15:44:10 +0100 Subject: [PATCH 1086/1619] [MIPS] Workaround for bug in gcc -EB / -EL options. Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of 2006-10-10 don't properly change the the predefined symbols if -EB / -EL are used, so we kludge that here. A bug has been filed at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413. Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 2124350ab94..641aa30b363 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -91,8 +91,17 @@ cflags-y += -ffreestanding # carefully avoid to add it redundantly because gcc 3.3/3.4 complains # when fed the toolchain default! # -cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB -D__MIPSEB__) -cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL -D__MIPSEL__) +# Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of +# 2006-10-10 don't properly change the the predefined symbols if -EB / -EL +# are used, so we kludge that here. A bug has been filed at +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413. +# +undef-all += -UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ +undef-all += -UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ +predef-be += -DMIPSEB -D_MIPSEB -D__MIPSEB -D__MIPSEB__ +predef-le += -DMIPSEL -D_MIPSEL -D__MIPSEL -D__MIPSEL__ +cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB $(undef-all) $(predef-be)) +cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le)) cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \ -fno-omit-frame-pointer -- GitLab From dff9262ed1491a1e531dc56e687605b5e4cd488d Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Wed, 11 Oct 2006 01:07:01 +0900 Subject: [PATCH 1087/1619] [MIPS] does not need pt_regs anymore. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- include/asm-mips/irq.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index 1a9804c6536..0ce2a80b689 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -24,8 +24,6 @@ static inline int irq_canonicalize(int irq) #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */ #endif -struct pt_regs; - extern asmlinkage unsigned int do_IRQ(unsigned int irq); #ifdef CONFIG_MIPS_MT_SMTC -- GitLab From 9b95e629eab59ee140fe2b17bbd7fea6821c6085 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 10 Oct 2006 22:46:52 +0900 Subject: [PATCH 1088/1619] [MIPS] Optimize and cleanup get_saved_sp, set_saved_sp If CONFIG_BUILD_ELF64 was not selected and gcc had -msym32 option (i.e. 4.0 or newer), there is no point to use %highest, %higher for kernel symbols. This patch also fixes 64-bit SMTC version of get_saved_sp() which is broken but harmless since there is no such CPUs for now. A bonus is set_saved_sp() and SMP version of get_saved_sp() are more readable now. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- include/asm-mips/stackframe.h | 64 +++++++++++------------------------ 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index 158a4cd12e4..1fae5dc5813 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -59,69 +59,43 @@ .endm #ifdef CONFIG_SMP - .macro get_saved_sp /* SMP variation */ -#ifdef CONFIG_32BIT #ifdef CONFIG_MIPS_MT_SMTC - .set mips32 - mfc0 k0, CP0_TCBIND; - .set mips0 - lui k1, %hi(kernelsp) - srl k0, k0, 19 - /* No need to shift down and up to clear bits 0-1 */ +#define PTEBASE_SHIFT 19 /* TCBIND */ #else - mfc0 k0, CP0_CONTEXT - lui k1, %hi(kernelsp) - srl k0, k0, 23 -#endif - addu k1, k0 - LONG_L k1, %lo(kernelsp)(k1) +#define PTEBASE_SHIFT 23 /* CONTEXT */ #endif -#ifdef CONFIG_64BIT + .macro get_saved_sp /* SMP variation */ #ifdef CONFIG_MIPS_MT_SMTC - .set mips64 - mfc0 k0, CP0_TCBIND; - .set mips0 - lui k0, %highest(kernelsp) - dsrl k1, 19 - /* No need to shift down and up to clear bits 0-2 */ + mfc0 k0, CP0_TCBIND #else - MFC0 k1, CP0_CONTEXT - lui k0, %highest(kernelsp) - dsrl k1, 23 - daddiu k0, %higher(kernelsp) - dsll k0, k0, 16 - daddiu k0, %hi(kernelsp) - dsll k0, k0, 16 -#endif /* CONFIG_MIPS_MT_SMTC */ - daddu k1, k1, k0 + MFC0 k0, CP0_CONTEXT +#endif +#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4) + lui k1, %highest(kernelsp) + daddiu k1, %higher(kernelsp) + dsll k1, 16 + daddiu k1, %hi(kernelsp) + dsll k1, 16 +#else + lui k1, %hi(kernelsp) +#endif + LONG_SRL k0, PTEBASE_SHIFT + LONG_ADDU k1, k0 LONG_L k1, %lo(kernelsp)(k1) -#endif /* CONFIG_64BIT */ .endm .macro set_saved_sp stackp temp temp2 -#ifdef CONFIG_32BIT -#ifdef CONFIG_MIPS_MT_SMTC - mfc0 \temp, CP0_TCBIND - srl \temp, 19 -#else - mfc0 \temp, CP0_CONTEXT - srl \temp, 23 -#endif -#endif -#ifdef CONFIG_64BIT #ifdef CONFIG_MIPS_MT_SMTC mfc0 \temp, CP0_TCBIND - dsrl \temp, 19 #else MFC0 \temp, CP0_CONTEXT - dsrl \temp, 23 -#endif #endif + LONG_SRL \temp, PTEBASE_SHIFT LONG_S \stackp, kernelsp(\temp) .endm #else .macro get_saved_sp /* Uniprocessor variation */ -#ifdef CONFIG_64BIT +#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4) lui k1, %highest(kernelsp) daddiu k1, %higher(kernelsp) dsll k1, k1, 16 -- GitLab From 472f291df59fc1c5eb3ade74a50bfa222030e736 Mon Sep 17 00:00:00 2001 From: Mark Mason Date: Tue, 10 Oct 2006 17:03:10 -0700 Subject: [PATCH 1089/1619] [MIPS] Fix compilation warnings in arch/mips/sibyte/bcm1480/smp.c Signed-off-by: Mark Mason Signed-off-by: Ralf Baechle --- arch/mips/sibyte/bcm1480/smp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 6eac36d1b8c..bf328277c77 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -34,21 +34,21 @@ extern void smp_call_function_interrupt(void); * independent of board/firmware */ -static void *mailbox_0_set_regs[] = { +static volatile void *mailbox_0_set_regs[] = { IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU), IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU), IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU), IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU), }; -static void *mailbox_0_clear_regs[] = { +static volatile void *mailbox_0_clear_regs[] = { IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU), IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU), IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU), IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU), }; -static void *mailbox_0_regs[] = { +static volatile void *mailbox_0_regs[] = { IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU), IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU), IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU), -- GitLab From 04d4d7d5e36957b2d941310fc8243aa7bf036f3b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 11 Oct 2006 01:22:12 +0100 Subject: [PATCH 1090/1619] [MIPS] Cleanup definitions of speed_t and tcflag_t. Signed-off-by: Ralf Baechle --- include/asm-mips/termbits.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/include/asm-mips/termbits.h b/include/asm-mips/termbits.h index fa6d04dac56..b62ec7c521c 100644 --- a/include/asm-mips/termbits.h +++ b/include/asm-mips/termbits.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1999, 2001 Ralf Baechle + * Copyright (C) 1995, 96, 99, 2001, 06 Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) 2001 MIPS Technologies, Inc. */ @@ -13,14 +13,8 @@ #include typedef unsigned char cc_t; -#if (_MIPS_SZLONG == 32) -typedef unsigned long speed_t; -typedef unsigned long tcflag_t; -#endif -#if (_MIPS_SZLONG == 64) -typedef __u32 speed_t; -typedef __u32 tcflag_t; -#endif +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; /* * The ABI says nothing about NCC but seems to use NCCS as -- GitLab From 67672f5b1f90ff19b970727b3fe2fa2b3cee3bef Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 11 Oct 2006 01:42:30 +0100 Subject: [PATCH 1091/1619] [MIPS] BigSur: More useful defconfig. Signed-off-by: Ralf Baechle --- arch/mips/configs/bigsur_defconfig | 102 +++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 21 deletions(-) diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index c6a015940b4..ba3bf733d27 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:02:58 2006 +# Linux kernel version: 2.6.19-rc1 +# Wed Oct 11 01:41:41 2006 # CONFIG_MIPS=y @@ -25,8 +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_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 @@ -83,6 +81,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_COHERENT=y CONFIG_CPU_BIG_ENDIAN=y @@ -132,8 +131,8 @@ CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_64KB is not set # CONFIG_SIBYTE_DMA_PAGEOPS is not set CONFIG_MIPS_MT_DISABLED=y -# CONFIG_MIPS_MT_SMTC is not set # CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set # CONFIG_MIPS_VPE_LOADER is not set CONFIG_CPU_HAS_LLSC=y CONFIG_CPU_HAS_SYNC=y @@ -185,9 +184,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -195,7 +196,9 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -204,12 +207,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -228,6 +231,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_BLK_DEV_IO_TRACE is not set # @@ -249,18 +253,17 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_HW_HAS_PCI=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set CONFIG_PCI_DEBUG=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 @@ -271,7 +274,7 @@ CONFIG_BINFMT_ELF=y CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y -# CONFIG_MIPS32_N32 is not set +CONFIG_MIPS32_N32=y CONFIG_BINFMT_ELF32=y # @@ -288,6 +291,7 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_XFRM=y CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set CONFIG_NET_KEY=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -308,10 +312,12 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -341,7 +347,6 @@ CONFIG_NETWORK_SECMARK=y # 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 @@ -368,7 +373,6 @@ CONFIG_NETWORK_SECMARK=y # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set # CONFIG_SYS_HYPERVISOR is not set @@ -404,7 +408,7 @@ CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -412,6 +416,7 @@ CONFIG_BLK_DEV_NBD=m # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -429,10 +434,40 @@ CONFIG_BLK_DEV_IDEFLOPPY=y # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_IDE_SWARM is not set # CONFIG_IDE_ARM is not set -# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_BLK_DEV_HD is not set @@ -441,6 +476,12 @@ CONFIG_IDE_GENERIC=y # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set # # Multi-device support (RAID and LVM) @@ -516,6 +557,7 @@ CONFIG_NET_SB1250_MAC=y # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -650,7 +692,6 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_ALGOBIT is not set # CONFIG_I2C_ALGOPCF is not set # CONFIG_I2C_ALGOPCA is not set -CONFIG_I2C_ALGO_SIBYTE=y # # I2C Hardware Bus support @@ -712,12 +753,12 @@ CONFIG_I2C_DEBUG_CHIP=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -729,6 +770,7 @@ CONFIG_VIDEO_V4L2=y # # CONFIG_FIRMWARE_EDID is not set # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -811,6 +853,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -840,8 +883,10 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -# CONFIG_TMPFS is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set @@ -851,6 +896,7 @@ CONFIG_RAMFS=y # # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set @@ -881,7 +927,6 @@ CONFIG_SUNRPC=y # 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 @@ -898,6 +943,10 @@ CONFIG_MSDOS_PARTITION=y # # CONFIG_NLS is not set +# +# Distributed Lock Manager +# + # # Profiling support # @@ -907,7 +956,8 @@ CONFIG_MSDOS_PARTITION=y # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y @@ -920,12 +970,15 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_SPINLOCK is not set CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set CONFIG_CROSSCOMPILE=y @@ -946,6 +999,10 @@ CONFIG_KEYS_DEBUG_PROC_KEYS=y # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_MD4=y @@ -955,9 +1012,12 @@ CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y CONFIG_CRYPTO_SERPENT=y CONFIG_CRYPTO_AES=m # CONFIG_CRYPTO_CAST5 is not set -- GitLab From c11b3c1bc0250027ff05665898f8d8eec40b7e49 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 11 Oct 2006 18:35:33 +0100 Subject: [PATCH 1092/1619] [MIPS] IP27: Make declaration of setup_replication_mask a proper prototype. Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/ip27-klnuma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c index d777b7d1a9f..f9f404a8dda 100644 --- a/arch/mips/sgi-ip27/ip27-klnuma.c +++ b/arch/mips/sgi-ip27/ip27-klnuma.c @@ -26,7 +26,7 @@ static cpumask_t ktext_repmask; * kernel. For example, we should never put a copy on a headless node, * and we should respect the topology of the machine. */ -void __init setup_replication_mask() +void __init setup_replication_mask(void) { cnodeid_t cnode; -- GitLab From 9a244b95ddb62a17b62f4b061b6e13ca4d177942 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 11 Oct 2006 19:30:03 +0100 Subject: [PATCH 1093/1619] [MIPS] Pass NULL not 0 for pointer value. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 1af3612a1ce..db80957ada8 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -310,7 +310,7 @@ static void flush_tlb_all_ipi(void *info) void flush_tlb_all(void) { - on_each_cpu(flush_tlb_all_ipi, 0, 1, 1); + on_each_cpu(flush_tlb_all_ipi, NULL, 1, 1); } static void flush_tlb_mm_ipi(void *mm) -- GitLab From 70903ca004fef17b0f6483714baefdb2f6ecceb0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 11 Oct 2006 18:49:24 +0000 Subject: [PATCH 1094/1619] [CIFS] Do not need to adjust for Jan/Feb for leap day calculation in 2100 (year divisible by 100) Signed-off-by: Yehuda Sadeh Weinraub Signed-off-by: Steve French --- fs/cifs/netmisc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 32562d19955..3adbd128e08 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -956,7 +956,8 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) days = days - 1; /* do not count leap year for the year 2100 */ /* adjust for leap year where we are still before leap day */ - days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); + if(year != 120) + days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); sec += 24 * 60 * 60 * days; ts.tv_sec = sec; -- GitLab From 533f90af6d90b9e4859a158565385d1d84a79f75 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 00:02:32 +0000 Subject: [PATCH 1095/1619] [CIFS] Fix old DOS time conversion to handle timezone Signed-off-by: Steve French --- fs/cifs/netmisc.c | 2 +- fs/cifs/readdir.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 3adbd128e08..992e80edc72 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -942,7 +942,7 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) cERROR(1,("illegal date, month %d day: %d", month, days)); month -= 1; days += total_days_of_prev_months[month]; - days += 3653; /* account for difference in days between 1980 and 1970 */ + days += 3652; /* account for difference in days between 1980 and 1970 */ year = sd->Year; days += year * 365; days += (year/4); /* leap year */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 81e7b2e5fb4..80e6ebd440a 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -106,6 +106,17 @@ static int construct_dentry(struct qstr *qstring, struct file *file, return rc; } +static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) +{ + if((tcon) && (tcon->ses) && (tcon->ses->server)) { + inode->i_ctime.tv_sec += tcon->ses->server.timeAdj; + inode->i_mtime.tv_sec += tcon->ses->server.timeAdj; + inode->i_atime.tv_sec += tcon->ses->server.timeAdj; + } + return; +} + + static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, char * buf, int *pobject_type, int isNewInode) { @@ -148,7 +159,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, tmp_inode->i_ctime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastWriteDate), le16_to_cpu(pfindData->LastWriteTime)); - + AdjustForTZ(cifs_sb->tcon, tmp_inode); attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); -- GitLab From ddae957da48cc381c1472a8909905e1818e4afdd Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 01:23:29 +0000 Subject: [PATCH 1096/1619] [CIFS] fix typo in previous patch Signed-off-by: Steve French --- fs/cifs/readdir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 80e6ebd440a..acbabc09543 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -109,9 +109,9 @@ static int construct_dentry(struct qstr *qstring, struct file *file, static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) { if((tcon) && (tcon->ses) && (tcon->ses->server)) { - inode->i_ctime.tv_sec += tcon->ses->server.timeAdj; - inode->i_mtime.tv_sec += tcon->ses->server.timeAdj; - inode->i_atime.tv_sec += tcon->ses->server.timeAdj; + inode->i_ctime.tv_sec += tcon->ses->server->timeAdj; + inode->i_mtime.tv_sec += tcon->ses->server->timeAdj; + inode->i_atime.tv_sec += tcon->ses->server->timeAdj; } return; } -- GitLab From 8884c4cb8b621963b5eb4a9ae45070bd0cb7085f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 12 Oct 2006 11:56:31 +0900 Subject: [PATCH 1097/1619] sh: Default enable R7780RP IRQs. Now that we've started accounting for spurious IRQs, change the logic somewhat so that we have a better chance of catching them. Signed-off-by: Paul Mundt --- arch/sh/boards/renesas/r7780rp/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c index 5519d3da6bc..b544772cbc7 100644 --- a/arch/sh/boards/renesas/r7780rp/irq.c +++ b/arch/sh/boards/renesas/r7780rp/irq.c @@ -49,6 +49,6 @@ void __init init_r7780rp_IRQ(void) disable_irq_nosync(i); set_irq_chip_and_handler(i, &r7780rp_irq_chip, handle_level_irq); - disable_r7780rp_irq(i); + enable_r7780rp_irq(i); } } -- GitLab From baf4326e49801526e4516e4de7f37b5e51468c49 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 12 Oct 2006 12:03:04 +0900 Subject: [PATCH 1098/1619] sh: interrupt exception handling rework Kill off interrupt_table for all of the CPU subtypes, we now default in to stepping in to do_IRQ() for _all_ IRQ exceptions and counting the spurious ones, rather than simply flipping on the ones we cared about. This and enabling the IRQ by default automatically has already uncovered a couple of bugs and IRQs that weren't being caught, as well as some that are being generated far too often (SCI Tx Data Empty, for example). The general rationale is to use a marker for interrupt exceptions, test for it in the handle_exception() path, and skip out to do_IRQ() if it's found. Everything else follows the same behaviour of finding the cached EXPEVT value in r2/r2_bank, we just rip out the INTEVT read from entry.S entirely (except for in the kGDB NMI case, which is another matter). Note that while this changes the do_IRQ() semantics regarding r4 handling, they were fundamentally broken anyways (relying entirely on r2_bank for the cached code). With this, we do the INTEVT read from do_IRQ() itself (in the CONFIG_CPU_HAS_INTEVT case), or fall back on r4 for the muxed IRQ number, which should also be closer to what SH-2 and SH-2A want anyways. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh3/ex.S | 195 -------------- arch/sh/kernel/cpu/sh4/ex.S | 500 ------------------------------------ arch/sh/kernel/entry.S | 43 +++- arch/sh/kernel/irq.c | 23 +- 4 files changed, 40 insertions(+), 721 deletions(-) diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S index 44daf44833f..6be46f0686b 100644 --- a/arch/sh/kernel/cpu/sh3/ex.S +++ b/arch/sh/kernel/cpu/sh3/ex.S @@ -49,198 +49,3 @@ ENTRY(nmi_slot) #endif ENTRY(user_break_point_trap) .long break_point_trap /* 1E0 */ -ENTRY(interrupt_table) - ! external hardware - .long do_IRQ ! 0000 /* 200 */ - .long do_IRQ ! 0001 - .long do_IRQ ! 0010 - .long do_IRQ ! 0011 - .long do_IRQ ! 0100 - .long do_IRQ ! 0101 - .long do_IRQ ! 0110 - .long do_IRQ ! 0111 - .long do_IRQ ! 1000 /* 300 */ - .long do_IRQ ! 1001 - .long do_IRQ ! 1010 - .long do_IRQ ! 1011 - .long do_IRQ ! 1100 - .long do_IRQ ! 1101 - .long do_IRQ ! 1110 - .long exception_error - ! Internal hardware - .long do_IRQ ! TMU0 tuni0 /* 400 */ - .long do_IRQ ! TMU1 tuni1 - .long do_IRQ ! TMU2 tuni2 - .long do_IRQ ! ticpi2 - .long do_IRQ ! RTC ati - .long do_IRQ ! pri - .long do_IRQ ! cui - .long do_IRQ ! SCI eri - .long do_IRQ ! rxi /* 500 */ - .long do_IRQ ! txi - .long do_IRQ ! tei - .long do_IRQ ! WDT iti /* 560 */ - .long do_IRQ ! REF rcmi - .long do_IRQ ! rovi - .long do_IRQ - .long do_IRQ /* 5E0 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7300) || \ - defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7710) - .long do_IRQ ! 32 IRQ irq0 /* 600 */ - .long do_IRQ ! 33 irq1 - .long do_IRQ ! 34 irq2 - .long do_IRQ ! 35 irq3 - .long do_IRQ ! 36 irq4 - .long do_IRQ ! 37 irq5 - .long do_IRQ ! 38 - .long do_IRQ ! 39 - .long do_IRQ ! 40 PINT pint0-7 /* 700 */ - .long do_IRQ ! 41 pint8-15 - .long do_IRQ ! 42 - .long do_IRQ ! 43 - .long do_IRQ ! 44 - .long do_IRQ ! 45 - .long do_IRQ ! 46 - .long do_IRQ ! 47 - .long do_IRQ ! 48 DMAC dei0 /* 800 */ - .long do_IRQ ! 49 dei1 - .long do_IRQ ! 50 dei2 - .long do_IRQ ! 51 dei3 - .long do_IRQ ! 52 IrDA eri1 - .long do_IRQ ! 53 rxi1 - .long do_IRQ ! 54 bri1 - .long do_IRQ ! 55 txi1 - .long do_IRQ ! 56 SCIF eri2 - .long do_IRQ ! 57 rxi2 - .long do_IRQ ! 58 bri2 - .long do_IRQ ! 59 txi2 - .long do_IRQ ! 60 ADC adi /* 980 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7705) - .long exception_none ! 61 /* 9A0 */ - .long exception_none ! 62 - .long exception_none ! 63 - .long exception_none ! 64 /* A00 */ - .long do_IRQ ! 65 USB usi0 - .long do_IRQ ! 66 usi1 - .long exception_none ! 67 - .long exception_none ! 68 - .long exception_none ! 69 - .long exception_none ! 70 - .long exception_none ! 71 - .long exception_none ! 72 /* B00 */ - .long exception_none ! 73 - .long exception_none ! 74 - .long exception_none ! 75 - .long exception_none ! 76 - .long exception_none ! 77 - .long exception_none ! 78 - .long exception_none ! 79 - .long do_IRQ ! 80 TPU0 tpi0 /* C00 */ - .long do_IRQ ! 81 TPU1 tpi1 - .long exception_none ! 82 - .long exception_none ! 83 - .long do_IRQ ! 84 TPU2 tpi2 - .long do_IRQ ! 85 TPU3 tpi3 /* CA0 */ -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7300) - .long do_IRQ ! 61 LCDC lcdi /* 9A0 */ - .long do_IRQ ! 62 PCC pcc0i - .long do_IRQ ! 63 pcc1i /* 9E0 */ -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7710) - .long exception_none ! 61 /* 9A0 */ - .long exception_none ! 62 - .long exception_none ! 63 - .long exception_none ! 64 /* A00 */ - .long exception_none ! 65 - .long exception_none ! 66 - .long exception_none ! 67 - .long exception_none ! 68 - .long exception_none ! 69 - .long exception_none ! 70 - .long exception_none ! 71 - .long exception_none ! 72 /* B00 */ - .long exception_none ! 73 - .long exception_none ! 74 - .long exception_none ! 75 - .long do_IRQ ! 76 DMAC2 dei4 /* B80 */ - .long do_IRQ ! 77 DMAC2 dei5 - .long exception_none ! 78 - .long do_IRQ ! 79 IPSEC ipseci /* BE0 */ - .long do_IRQ ! 80 EDMAC eint0 /* C00 */ - .long do_IRQ ! 81 EDMAC eint1 - .long do_IRQ ! 82 EDMAC eint2 - .long exception_none ! 83 /* C60 */ - .long exception_none ! 84 - .long exception_none ! 85 - .long exception_none ! 86 - .long exception_none ! 87 - .long exception_none ! 88 /* D00 */ - .long exception_none ! 89 - .long exception_none ! 90 - .long exception_none ! 91 - .long exception_none ! 92 - .long exception_none ! 93 - .long exception_none ! 94 - .long exception_none ! 95 - .long do_IRQ ! 96 SIOF eri0 /* E00 */ - .long do_IRQ ! 97 txi0 - .long do_IRQ ! 98 rxi0 - .long do_IRQ ! 99 cci0 - .long do_IRQ ! 100 eri1 /* E80 */ - .long do_IRQ ! 101 txi1 - .long do_IRQ ! 102 rxi2 - .long do_IRQ ! 103 cci3 -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7300) - .long do_IRQ ! 64 - .long do_IRQ ! 65 - .long do_IRQ ! 66 - .long do_IRQ ! 67 - .long do_IRQ ! 68 - .long do_IRQ ! 69 - .long do_IRQ ! 70 - .long do_IRQ ! 71 - .long do_IRQ ! 72 - .long do_IRQ ! 73 - .long do_IRQ ! 74 - .long do_IRQ ! 75 - .long do_IRQ ! 76 - .long do_IRQ ! 77 - .long do_IRQ ! 78 - .long do_IRQ ! 79 - .long do_IRQ ! 80 SCIF0(SH7300) - .long do_IRQ ! 81 - .long do_IRQ ! 82 - .long do_IRQ ! 83 - .long do_IRQ ! 84 - .long do_IRQ ! 85 - .long do_IRQ ! 86 - .long do_IRQ ! 87 - .long do_IRQ ! 88 - .long do_IRQ ! 89 - .long do_IRQ ! 90 - .long do_IRQ ! 91 - .long do_IRQ ! 92 - .long do_IRQ ! 93 - .long do_IRQ ! 94 - .long do_IRQ ! 95 - .long do_IRQ ! 96 - .long do_IRQ ! 97 - .long do_IRQ ! 98 - .long do_IRQ ! 99 - .long do_IRQ ! 100 - .long do_IRQ ! 101 - .long do_IRQ ! 102 - .long do_IRQ ! 103 - .long do_IRQ ! 104 - .long do_IRQ ! 105 - .long do_IRQ ! 106 - .long do_IRQ ! 107 - .long do_IRQ ! 108 -#endif -#endif diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S index 7146893a6cc..3f4cd043e90 100644 --- a/arch/sh/kernel/cpu/sh4/ex.S +++ b/arch/sh/kernel/cpu/sh4/ex.S @@ -53,503 +53,3 @@ ENTRY(nmi_slot) #endif ENTRY(user_break_point_trap) .long break_point_trap /* 1E0 */ -ENTRY(interrupt_table) - ! external hardware - .long do_IRQ ! 0000 /* 200 */ - .long do_IRQ ! 0001 - .long do_IRQ ! 0010 - .long do_IRQ ! 0011 - .long do_IRQ ! 0100 - .long do_IRQ ! 0101 - .long do_IRQ ! 0110 - .long do_IRQ ! 0111 - .long do_IRQ ! 1000 /* 300 */ - .long do_IRQ ! 1001 - .long do_IRQ ! 1010 - .long do_IRQ ! 1011 - .long do_IRQ ! 1100 - .long do_IRQ ! 1101 - .long do_IRQ ! 1110 - .long exception_error - ! Internal hardware -#ifndef CONFIG_CPU_SUBTYPE_SH7780 - .long do_IRQ ! TMU0 tuni0 /* 400 */ - .long do_IRQ ! TMU1 tuni1 - .long do_IRQ ! TMU2 tuni2 - .long do_IRQ ! ticpi2 -#if defined(CONFIG_CPU_SUBTYPE_SH7760) - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error /* 500 */ - .long exception_error - .long exception_error -#else - .long do_IRQ ! RTC ati - .long do_IRQ ! pri - .long do_IRQ ! cui - .long do_IRQ ! SCI eri - .long do_IRQ ! rxi /* 500 */ - .long do_IRQ ! txi - .long do_IRQ ! tei -#endif - .long do_IRQ ! WDT iti /* 560 */ - .long do_IRQ ! REF rcmi - .long do_IRQ ! rovi - .long do_IRQ - .long do_IRQ /* 5E0 */ - .long do_IRQ ! 32 Hitachi UDI /* 600 */ - .long do_IRQ ! 33 GPIO - .long do_IRQ ! 34 DMAC dmte0 - .long do_IRQ ! 35 dmte1 - .long do_IRQ ! 36 dmte2 - .long do_IRQ ! 37 dmte3 - .long do_IRQ ! 38 dmae - .long exception_error ! 39 /* 6E0 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7760) - .long exception_error /* 700 */ - .long exception_error - .long exception_error - .long exception_error /* 760 */ -#else - .long do_IRQ ! 40 SCIF eri /* 700 */ - .long do_IRQ ! 41 rxi - .long do_IRQ ! 42 bri - .long do_IRQ ! 43 txi -#endif -#if CONFIG_NR_ONCHIP_DMA_CHANNELS == 8 - .long do_IRQ ! 44 DMAC dmte4 /* 780 */ - .long do_IRQ ! 45 dmte5 - .long do_IRQ ! 46 dmte6 - .long do_IRQ ! 47 dmte7 /* 7E0 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7343) - .long do_IRQ ! 44 IIC1 ali /* 780 */ - .long do_IRQ ! 45 tacki - .long do_IRQ ! 46 waiti - .long do_IRQ ! 47 dtei /* 7E0 */ - .long do_IRQ ! 48 DMAC dei0 /* 800 */ - .long do_IRQ ! 49 dei1 /* 820 */ -#else - .long exception_error ! 44 /* 780 */ - .long exception_error ! 45 - .long exception_error ! 46 - .long exception_error ! 47 -#endif -#if defined(CONFIG_SH_FPU) - .long do_fpu_state_restore ! 48 /* 800 */ - .long do_fpu_state_restore ! 49 /* 820 */ -#elif !defined(CONFIG_CPU_SUBTYPE_SH7343) && \ - !defined(CONFIG_CPU_SUBTYPE_SH73180) - .long exception_error - .long exception_error -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7751) - .long exception_error /* 840 */ - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error /* 900 */ - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! PCI serr /* A00 */ - .long do_IRQ ! dma3 - .long do_IRQ ! dma2 - .long do_IRQ ! dma1 - .long do_IRQ ! dma0 - .long do_IRQ ! pwon - .long do_IRQ ! pwdwn - .long do_IRQ ! err - .long do_IRQ ! TMU3 tuni3 /* B00 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! TMU4 tuni4 /* B80 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) - .long do_IRQ ! IRQ irq6 /* 840 */ - .long do_IRQ ! irq7 - .long do_IRQ ! SCIF eri0 - .long do_IRQ ! rxi0 - .long do_IRQ ! bri0 - .long do_IRQ ! txi0 - .long do_IRQ ! HCAN2 cani0 /* 900 */ - .long do_IRQ ! cani1 - .long do_IRQ ! SSI ssii0 - .long do_IRQ ! ssii1 - .long do_IRQ ! HAC haci0 - .long do_IRQ ! haci1 - .long do_IRQ ! IIC iici0 - .long do_IRQ ! iici1 - .long do_IRQ ! USB usbi /* A00 */ - .long do_IRQ ! LCDC vint - .long exception_error - .long exception_error - .long do_IRQ ! DMABRG dmabrgi0 - .long do_IRQ ! dmabrgi1 - .long do_IRQ ! dmabrgi2 - .long exception_error - .long do_IRQ ! SCIF eri1 /* B00 */ - .long do_IRQ ! rxi1 - .long do_IRQ ! bri1 - .long do_IRQ ! txi1 - .long do_IRQ ! eri2 - .long do_IRQ ! rxi2 - .long do_IRQ ! bri2 - .long do_IRQ ! txi2 - .long do_IRQ ! SIM simeri /* C00 */ - .long do_IRQ ! simrxi - .long do_IRQ ! simtxi - .long do_IRQ ! simtei - .long do_IRQ ! HSPI spii - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! MMCIF mmci0 /* D00 */ - .long do_IRQ ! mmci1 - .long do_IRQ ! mmci2 - .long do_IRQ ! mmci3 - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error /* E00 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! MFI mfii - .long exception_error - .long exception_error - .long exception_error - .long exception_error /* F00 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! ADC adi - .long do_IRQ ! CMT cmti /* FA0 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7343) - .long do_IRQ ! 50 0x840 - .long do_IRQ ! 51 0x860 - .long do_IRQ ! 52 0x880 - .long do_IRQ ! 53 0x8a0 - .long do_IRQ ! 54 0x8c0 - .long do_IRQ ! 55 0x8e0 - .long do_IRQ ! 56 0x900 - .long do_IRQ ! 57 0x920 - .long do_IRQ ! 58 0x940 - .long do_IRQ ! 59 0x960 - .long do_IRQ ! 60 0x980 - .long do_IRQ ! 61 0x9a0 - .long do_IRQ ! 62 0x9c0 - .long do_IRQ ! 63 0x9e0 - .long do_IRQ ! 64 0xa00 - .long do_IRQ ! 65 0xa20 - .long do_IRQ ! 66 0xa40 - .long do_IRQ ! 67 0xa60 - .long do_IRQ ! 68 0xa80 - .long do_IRQ ! 69 0xaa0 - .long do_IRQ ! 70 0xac0 - .long do_IRQ ! 71 0xae0 - .long do_IRQ ! 72 0xb00 - .long do_IRQ ! 73 0xb20 - .long do_IRQ ! 74 0xb40 - .long do_IRQ ! 75 0xb60 - .long do_IRQ ! 76 0xb80 - .long do_IRQ ! 77 0xba0 - .long do_IRQ ! 78 0xbc0 - .long do_IRQ ! 79 0xbe0 - .long do_IRQ ! 80 0xc00 - .long do_IRQ ! 81 0xc20 - .long do_IRQ ! 82 0xc40 - .long do_IRQ ! 83 0xc60 - .long do_IRQ ! 84 0xc80 - .long do_IRQ ! 85 0xca0 - .long do_IRQ ! 86 0xcc0 - .long do_IRQ ! 87 0xce0 - .long do_IRQ ! 88 0xd00 - .long do_IRQ ! 89 0xd20 - .long do_IRQ ! 90 0xd40 - .long do_IRQ ! 91 0xd60 - .long do_IRQ ! 92 0xd80 - .long do_IRQ ! 93 0xda0 - .long do_IRQ ! 94 0xdc0 - .long do_IRQ ! 95 0xde0 - .long do_IRQ ! 96 0xe00 - .long do_IRQ ! 97 0xe20 - .long do_IRQ ! 98 0xe40 - .long do_IRQ ! 99 0xe60 - .long do_IRQ ! 100 0xe80 - .long do_IRQ ! 101 0xea0 - .long do_IRQ ! 102 0xec0 - .long do_IRQ ! 103 0xee0 - .long do_IRQ ! 104 0xf00 - .long do_IRQ ! 105 0xf20 - .long do_IRQ ! 106 0xf40 - .long do_IRQ ! 107 0xf60 - .long do_IRQ ! 108 0xf80 -#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) - .long exception_error ! 50 0x840 - .long exception_error ! 51 0x860 - .long exception_error ! 52 0x880 - .long exception_error ! 53 0x8a0 - .long exception_error ! 54 0x8c0 - .long exception_error ! 55 0x8e0 - .long exception_error ! 56 0x900 - .long exception_error ! 57 0x920 - .long exception_error ! 58 0x940 - .long exception_error ! 59 0x960 - .long exception_error ! 60 0x980 - .long exception_error ! 61 0x9a0 - .long exception_error ! 62 0x9c0 - .long exception_error ! 63 0x9e0 - .long do_IRQ ! 64 0xa00 PCI serr - .long do_IRQ ! 65 0xa20 err - .long do_IRQ ! 66 0xa40 ad - .long do_IRQ ! 67 0xa60 pwr_dwn - .long exception_error ! 68 0xa80 - .long exception_error ! 69 0xaa0 - .long exception_error ! 70 0xac0 - .long exception_error ! 71 0xae0 - .long do_IRQ ! 72 0xb00 DMA INT0 - .long do_IRQ ! 73 0xb20 INT1 - .long do_IRQ ! 74 0xb40 INT2 - .long do_IRQ ! 75 0xb60 INT3 - .long do_IRQ ! 76 0xb80 INT4 - .long exception_error ! 77 0xba0 - .long do_IRQ ! 78 0xbc0 DMA ERR - .long exception_error ! 79 0xbe0 - .long do_IRQ ! 80 0xc00 PIO0 - .long do_IRQ ! 81 0xc20 PIO1 - .long do_IRQ ! 82 0xc40 PIO2 - .long exception_error ! 83 0xc60 - .long exception_error ! 84 0xc80 - .long exception_error ! 85 0xca0 - .long exception_error ! 86 0xcc0 - .long exception_error ! 87 0xce0 - .long exception_error ! 88 0xd00 - .long exception_error ! 89 0xd20 - .long exception_error ! 90 0xd40 - .long exception_error ! 91 0xd60 - .long exception_error ! 92 0xd80 - .long exception_error ! 93 0xda0 - .long exception_error ! 94 0xdc0 - .long exception_error ! 95 0xde0 - .long exception_error ! 96 0xe00 - .long exception_error ! 97 0xe20 - .long exception_error ! 98 0xe40 - .long exception_error ! 99 0xe60 - .long exception_error ! 100 0xe80 - .long exception_error ! 101 0xea0 - .long exception_error ! 102 0xec0 - .long exception_error ! 103 0xee0 - .long exception_error ! 104 0xf00 - .long exception_error ! 105 0xf20 - .long exception_error ! 106 0xf40 - .long exception_error ! 107 0xf60 - .long exception_error ! 108 0xf80 - .long exception_error ! 109 0xfa0 - .long exception_error ! 110 0xfc0 - .long exception_error ! 111 0xfe0 - .long do_IRQ ! 112 0x1000 Mailbox - .long exception_error ! 113 0x1020 - .long exception_error ! 114 0x1040 - .long exception_error ! 115 0x1060 - .long exception_error ! 116 0x1080 - .long exception_error ! 117 0x10a0 - .long exception_error ! 118 0x10c0 - .long exception_error ! 119 0x10e0 - .long exception_error ! 120 0x1100 - .long exception_error ! 121 0x1120 - .long exception_error ! 122 0x1140 - .long exception_error ! 123 0x1160 - .long exception_error ! 124 0x1180 - .long exception_error ! 125 0x11a0 - .long exception_error ! 126 0x11c0 - .long exception_error ! 127 0x11e0 - .long exception_error ! 128 0x1200 - .long exception_error ! 129 0x1220 - .long exception_error ! 130 0x1240 - .long exception_error ! 131 0x1260 - .long exception_error ! 132 0x1280 - .long exception_error ! 133 0x12a0 - .long exception_error ! 134 0x12c0 - .long exception_error ! 135 0x12e0 - .long exception_error ! 136 0x1300 - .long exception_error ! 137 0x1320 - .long exception_error ! 138 0x1340 - .long exception_error ! 139 0x1360 - .long do_IRQ ! 140 0x1380 EMPI INV_ADDR - .long exception_error ! 141 0x13a0 - .long exception_error ! 142 0x13c0 - .long exception_error ! 143 0x13e0 -#elif defined(CONFIG_CPU_SUBTYPE_SH7770) - .long do_IRQ ! 50 0x840 - .long do_IRQ ! 51 0x860 - .long do_IRQ ! 52 0x880 - .long do_IRQ ! 53 0x8a0 - .long do_IRQ ! 54 0x8c0 - .long do_IRQ ! 55 0x8e0 - .long do_IRQ ! 56 0x900 - .long do_IRQ ! 57 0x920 - .long do_IRQ ! 58 0x940 - .long do_IRQ ! 59 0x960 - .long do_IRQ ! 60 0x980 - .long do_IRQ ! 61 0x9a0 - .long do_IRQ ! 62 0x9c0 - .long do_IRQ ! 63 0x9e0 - .long do_IRQ ! 64 0xa00 - .long do_IRQ ! 65 0xa20 - .long do_IRQ ! 66 0xa4d - .long do_IRQ ! 67 0xa60 - .long do_IRQ ! 68 0xa80 - .long do_IRQ ! 69 0xaa0 - .long do_IRQ ! 70 0xac0 - .long do_IRQ ! 71 0xae0 - .long do_IRQ ! 72 0xb00 - .long do_IRQ ! 73 0xb20 - .long do_IRQ ! 74 0xb40 - .long do_IRQ ! 75 0xb60 - .long do_IRQ ! 76 0xb80 - .long do_IRQ ! 77 0xba0 - .long do_IRQ ! 78 0xbc0 - .long do_IRQ ! 79 0xbe0 - .long do_IRQ ! 80 0xc00 - .long do_IRQ ! 81 0xc20 - .long do_IRQ ! 82 0xc40 - .long do_IRQ ! 83 0xc60 - .long do_IRQ ! 84 0xc80 - .long do_IRQ ! 85 0xca0 - .long do_IRQ ! 86 0xcc0 - .long do_IRQ ! 87 0xce0 - .long do_IRQ ! 88 0xd00 - .long do_IRQ ! 89 0xd20 - .long do_IRQ ! 90 0xd40 - .long do_IRQ ! 91 0xd60 - .long do_IRQ ! 92 0xd80 - .long do_IRQ ! 93 0xda0 - .long do_IRQ ! 94 0xdc0 - .long do_IRQ ! 95 0xde0 - .long do_IRQ ! 96 0xe00 - .long do_IRQ ! 97 0xe20 - .long do_IRQ ! 98 0xe40 - .long do_IRQ ! 99 0xe60 - .long do_IRQ ! 100 0xe80 - .long do_IRQ ! 101 0xea0 - .long do_IRQ ! 102 0xec0 - .long do_IRQ ! 103 0xee0 - .long do_IRQ ! 104 0xf00 - .long do_IRQ ! 105 0xf20 - .long do_IRQ ! 106 0xf40 - .long do_IRQ ! 107 0xf60 - .long do_IRQ ! 108 0xf80 -#endif -#else - .long exception_error /* 400 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! RTC ati - .long do_IRQ ! pri - .long do_IRQ ! cui - .long exception_error - .long exception_error /* 500 */ - .long exception_error - .long exception_error - .long do_IRQ ! WDT iti /* 560 */ - .long do_IRQ ! TMU-ch0 - .long do_IRQ ! TMU-ch1 - .long do_IRQ ! TMU-ch2 - .long do_IRQ ! ticpi2 /* 5E0 */ - .long do_IRQ ! 32 Hitachi UDI /* 600 */ - .long exception_error - .long do_IRQ ! 34 DMAC dmte0 - .long do_IRQ ! 35 dmte1 - .long do_IRQ ! 36 dmte2 - .long do_IRQ ! 37 dmte3 - .long do_IRQ ! 38 dmae - .long exception_error ! 39 /* 6E0 */ - .long do_IRQ ! 40 SCIF-ch0 eri /* 700 */ - .long do_IRQ ! 41 rxi - .long do_IRQ ! 42 bri - .long do_IRQ ! 43 txi - .long do_IRQ ! 44 DMAC dmte4 /* 780 */ - .long do_IRQ ! 45 dmte5 - .long do_IRQ ! 46 dmte6 - .long do_IRQ ! 47 dmte7 /* 7E0 */ -#if defined(CONFIG_SH_FPU) - .long do_fpu_state_restore ! 48 /* 800 */ - .long do_fpu_state_restore ! 49 /* 820 */ -#else - .long exception_error - .long exception_error -#endif - .long exception_error /* 840 */ - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! 56 CMT /* 900 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! 60 HAC - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! PCI serr /* A00 */ - .long do_IRQ ! INTA - .long do_IRQ ! INTB - .long do_IRQ ! INTC - .long do_IRQ ! INTD - .long do_IRQ ! err - .long do_IRQ ! pwd3 - .long do_IRQ ! pwd2 - .long do_IRQ ! pwd1 /* B00 */ - .long do_IRQ ! pwd0 - .long exception_error - .long exception_error - .long do_IRQ ! SCIF-ch1 eri /* B80 */ - .long do_IRQ ! rxi - .long do_IRQ ! bri - .long do_IRQ ! txi - .long do_IRQ ! SIOF /* C00 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! HSPI /* C80 */ - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! MMCIF fatat /* D00 */ - .long do_IRQ ! tran - .long do_IRQ ! err - .long do_IRQ ! frdy - .long do_IRQ ! DMAC dmint8 /* D80 */ - .long do_IRQ ! dmint9 - .long do_IRQ ! dmint10 - .long do_IRQ ! dmint11 - .long do_IRQ ! TMU-ch3 /* E00 */ - .long do_IRQ ! TMU-ch4 - .long do_IRQ ! TMU-ch5 - .long exception_error - .long do_IRQ ! SSI - .long exception_error - .long exception_error - .long exception_error - .long do_IRQ ! FLCTL flste /* F00 */ - .long do_IRQ ! fltend - .long do_IRQ ! fltrq0 - .long do_IRQ ! fltrq1 - .long do_IRQ ! GPIO gpioi0 /* F80 */ - .long do_IRQ ! gpioi1 - .long do_IRQ ! gpioi2 - .long do_IRQ ! gpioi3 -#endif - diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index 97c571fbcdf..39aaefb2d83 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -1,9 +1,8 @@ -/* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $ - * +/* * linux/arch/sh/entry.S * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003 - 2006 Paul Mundt * * 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 @@ -78,7 +77,6 @@ OFF_TRA = (16*4+6*4) #define k3 r3 #define k4 r4 -#define k_ex_code r2_bank /* r2_bank1 */ #define g_imask r6 /* r6_bank1 */ #define k_g_imask r6_bank /* r6_bank1 */ #define current r7 /* r7_bank1 */ @@ -691,7 +689,7 @@ interrupt: 0: #endif /* defined(CONFIG_KGDB_NMI) */ bra handle_exception - mov.l @k2, k2 + mov #-1, k2 ! interrupt exception marker .align 2 1: .long EXPEVT @@ -717,8 +715,7 @@ ENTRY(handle_exception) add current, k1 mov k1, r15 ! change to kernel stack ! -1: mov #-1, k4 - mov.l 2f, k1 +1: mov.l 2f, k1 ! #ifdef CONFIG_SH_DSP mov.l r2, @-r15 ! Save r2, we need another reg @@ -763,6 +760,8 @@ skip_save: #endif ! Save the user registers on the stack. mov.l k2, @-r15 ! EXPEVT + + mov #-1, k4 mov.l k4, @-r15 ! set TRA (default: -1) ! sts.l macl, @-r15 @@ -797,8 +796,21 @@ skip_save: mov.l r2, @-r15 mov.l r1, @-r15 mov.l r0, @-r15 - ! Then, dispatch to the handler, according to the exception code. - stc k_ex_code, r8 + + /* + * This gets a bit tricky.. in the INTEVT case we don't want to use + * the VBR offset as a destination in the jump call table, since all + * of the destinations are the same. In this case, (interrupt) sets + * a marker in r2 (now r2_bank since SR.RB changed), which we check + * to determine the exception type. For all other exceptions, we + * forcibly read EXPEVT from memory and fix up the jump address, in + * the interrupt exception case we jump to do_IRQ() and defer the + * INTEVT read until there. As a bonus, we can also clean up the SR.RB + * checks that do_IRQ() was doing.. + */ + stc r2_bank, r8 + cmp/pz r8 + bf interrupt_exception shlr2 r8 shlr r8 mov.l 4f, r9 @@ -806,6 +818,8 @@ skip_save: mov.l @r9, r9 jmp @r9 nop + rts + nop .align 2 1: .long 0x00001000 ! DSP=1 @@ -813,8 +827,17 @@ skip_save: 3: .long 0xcfffffff ! RB=0, BL=0 4: .long exception_handling_table +interrupt_exception: + mov.l 1f, r9 + jmp @r9 + nop + rts + nop + + .align 2 +1: .long do_IRQ + .align 2 ENTRY(exception_none) rts nop - diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 3b93682bf18..acf2602569c 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ atomic_t irq_err_count; */ void ack_bad_irq(unsigned int irq) { + atomic_inc(&irq_err_count); printk("unexpected IRQ trap at vector %02x\n", irq); } @@ -85,7 +87,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, struct pt_regs regs) { struct pt_regs *old_regs = set_irq_regs(®s); - int irq = r4; + int irq; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; #endif @@ -109,20 +111,9 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, #endif #ifdef CONFIG_CPU_HAS_INTEVT - __asm__ __volatile__ ( -#ifdef CONFIG_CPU_HAS_SR_RB - "stc r2_bank, %0\n\t" + irq = (ctrl_inl(INTEVT) >> 5) - 16; #else - "mov.l @%1, %0\n\t" -#endif - "shlr2 %0\n\t" - "shlr2 %0\n\t" - "shlr %0\n\t" - "add #-16, %0\n\t" - : "=z" (irq), "=r" (r4) - : "1" (INTEVT) - : "memory" - ); + irq = r4; #endif irq = irq_demux(irq); @@ -147,9 +138,9 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, __asm__ __volatile__ ( "mov %0, r4 \n" "mov r15, r9 \n" - "jsr @%2 \n" + "jsr @%1 \n" /* swith to the irq stack */ - " mov %3, r15 \n" + " mov %2, r15 \n" /* restore the stack (ring zero) */ "mov r9, r15 \n" : /* no outputs */ -- GitLab From 8ae91b9ad88a130cd50fc0b78b16e7b9510b8067 Mon Sep 17 00:00:00 2001 From: Ryusuke Sakato Date: Thu, 12 Oct 2006 12:16:13 +0900 Subject: [PATCH 1099/1619] sh: SH-4A UBC support A simple patch to enable the UBC on SH-4A. Signed-off-by: Ryusuke Sakato Signed-off-by: Paul Mundt --- arch/sh/kernel/process.c | 30 +++++++++++++++++++++++++++++ include/asm-sh/cpu-sh4/ubc.h | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 0b1d5dd7a93..91516dca4a8 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -5,6 +5,7 @@ * Copyright (C) 1995 Linus Torvalds * * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC */ /* @@ -290,6 +291,24 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, static void ubc_set_tracing(int asid, unsigned long pc) { +#if defined(CONFIG_CPU_SH4A) + unsigned long val; + + val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE); + val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid)); + + ctrl_outl(val, UBC_CBR0); + ctrl_outl(pc, UBC_CAR0); + ctrl_outl(0x0, UBC_CAMR0); + ctrl_outl(0x0, UBC_CBCR); + + val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); + ctrl_outl(val, UBC_CRR0); + + /* Read UBC register that we writed last. For chekking UBC Register changed */ + val = ctrl_inl(UBC_CRR0); + +#else /* CONFIG_CPU_SH4A */ ctrl_outl(pc, UBC_BARA); #ifdef CONFIG_MMU @@ -307,6 +326,7 @@ ubc_set_tracing(int asid, unsigned long pc) ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA); ctrl_outw(BRCR_PCBA, UBC_BRCR); } +#endif /* CONFIG_CPU_SH4A */ } /* @@ -359,8 +379,13 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne #endif ubc_set_tracing(asid, next->thread.ubc_pc); } else { +#if defined(CONFIG_CPU_SH4A) + ctrl_outl(UBC_CBR_INIT, UBC_CBR0); + ctrl_outl(UBC_CRR_INIT, UBC_CRR0); +#else ctrl_outw(0, UBC_BBRA); ctrl_outw(0, UBC_BBRB); +#endif } return prev; @@ -460,8 +485,13 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, struct pt_regs regs) { /* Clear tracing. */ +#if defined(CONFIG_CPU_SH4A) + ctrl_outl(UBC_CBR_INIT, UBC_CBR0); + ctrl_outl(UBC_CRR_INIT, UBC_CRR0); +#else ctrl_outw(0, UBC_BBRA); ctrl_outw(0, UBC_BBRB); +#endif current->thread.ubc_pc = 0; ubc_usercnt -= 1; diff --git a/include/asm-sh/cpu-sh4/ubc.h b/include/asm-sh/cpu-sh4/ubc.h index 3d094316765..c86e1705093 100644 --- a/include/asm-sh/cpu-sh4/ubc.h +++ b/include/asm-sh/cpu-sh4/ubc.h @@ -3,6 +3,7 @@ * * Copyright (C) 1999 Niibe Yutaka * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC * * 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 @@ -11,6 +12,41 @@ #ifndef __ASM_CPU_SH4_UBC_H #define __ASM_CPU_SH4_UBC_H +#if defined(CONFIG_CPU_SH4A) +#define UBC_CBR0 0xff200000 +#define UBC_CRR0 0xff200004 +#define UBC_CAR0 0xff200008 +#define UBC_CAMR0 0xff20000c +#define UBC_CBR1 0xff200020 +#define UBC_CRR1 0xff200024 +#define UBC_CAR1 0xff200028 +#define UBC_CAMR1 0xff20002c +#define UBC_CDR1 0xff200030 +#define UBC_CDMR1 0xff200034 +#define UBC_CETR1 0xff200038 +#define UBC_CCMFR 0xff200600 +#define UBC_CBCR 0xff200620 + +/* CBR */ +#define UBC_CBR_AIE (0x01<<30) +#define UBC_CBR_ID_INST (0x01<<4) +#define UBC_CBR_RW_READ (0x01<<1) +#define UBC_CBR_CE (0x01) + +#define UBC_CBR_AIV_MASK (0x00FF0000) +#define UBC_CBR_AIV_SHIFT (16) +#define UBC_CBR_AIV_SET(asid) (((asid)< Date: Thu, 12 Oct 2006 03:28:28 +0000 Subject: [PATCH 1100/1619] [CIFS] Level 1 QPathInfo needed for proper OS2 support Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 1 + fs/cifs/cifssmb.c | 21 ++++++++++++++++++--- fs/cifs/inode.c | 5 ++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7dd2f48a407..4a4fd2dbca6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -119,6 +119,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * findData, + int legacy /* whether to use old info level */, const struct nls_table *nls_codepage, int remap); extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 79a01d35a78..6f50f2bc887 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2969,6 +2969,7 @@ int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * pFindData, + int legacy /* old style infolevel */, const struct nls_table *nls_codepage, int remap) { /* level 263 SMB_QUERY_FILE_ALL_INFO */ @@ -3017,7 +3018,10 @@ QPathInfoRetry: byte_count = params + 1 /* pad */ ; pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); + if(legacy) + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); + else + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; pSMB->hdr.smb_buf_length += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); @@ -3029,13 +3033,24 @@ QPathInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 40)) + if (rc) /* BB add auto retry on EOPNOTSUPP? */ + rc = -EIO; + else if (!legacy && (pSMBr->ByteCount < 40)) rc = -EIO; /* bad smb */ + else if(legacy && (pSMBr->ByteCount < 24)) + rc = -EIO; /* 24 or 26 expected but we do not read last field */ else if (pFindData){ + int size; __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + if(legacy) /* we do not read the last field, EAsize, fortunately + since it varies by subdialect and on Set vs. Get, is + two bytes or 4 bytes depending but we don't care here */ + size = sizeof(FILE_INFO_STANDARD); + else + size = sizeof(FILE_ALL_INFO); memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + - data_offset, sizeof (FILE_ALL_INFO)); + data_offset, size); } else rc = -ENOMEM; } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 06dbce3a181..fe6d21f9996 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -338,6 +338,7 @@ int cifs_get_inode_info(struct inode **pinode, pfindData = (FILE_ALL_INFO *)buf; /* could do find first instead but this returns more info */ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, + 0 /* not legacy */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB optimize code so we do not make the above call @@ -385,8 +386,10 @@ int cifs_get_inode_info(struct inode **pinode, /* get new inode */ if (*pinode == NULL) { *pinode = new_inode(sb); - if (*pinode == NULL) + if (*pinode == NULL) { + kfree(buf); return -ENOMEM; + } /* Is an i_ino of zero legal? Can we use that to check if the server supports returning inode numbers? Are there other sanity checks we can use to ensure that -- GitLab From 07646e217f473a3e6213f8228336a9046833d6aa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 23:45:23 -0400 Subject: [PATCH 1101/1619] 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(+) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 14fec2a23b2..819f08f1310 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) -- GitLab From 0a66045bcfd3a7ba5d1253f9f305b78bf636ac57 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Oct 2006 01:06:23 -0400 Subject: [PATCH 1102/1619] Input: serio core - handle errors returned by device_bind_driver() Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 480fdc5d20b..211943f85cb 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -118,6 +118,8 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) { + int error; + down_write(&serio_bus.subsys.rwsem); if (serio_match_port(drv->id_table, serio)) { @@ -126,9 +128,19 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) serio->dev.driver = NULL; goto out; } - device_bind_driver(&serio->dev); + error = device_bind_driver(&serio->dev); + if (error) { + printk(KERN_WARNING + "serio: device_bind_driver() failed " + "for %s (%s) and %s, error: %d\n", + serio->phys, serio->name, + drv->description, error); + serio_disconnect_driver(serio); + serio->dev.driver = NULL; + goto out; + } } -out: + out: up_write(&serio_bus.subsys.rwsem); } -- GitLab From 23de1510e2468ea349354889097e018d4e8770c5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Oct 2006 01:06:34 -0400 Subject: [PATCH 1103/1619] Input: gameport core - handle errors returned by device_bind_driver() Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 3f47ae55c6f..a0af97efe6a 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -191,6 +191,8 @@ static void gameport_run_poll_handler(unsigned long d) static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv) { + int error; + down_write(&gameport_bus.subsys.rwsem); gameport->dev.driver = &drv->driver; @@ -198,8 +200,20 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv gameport->dev.driver = NULL; goto out; } - device_bind_driver(&gameport->dev); -out: + + error = device_bind_driver(&gameport->dev); + if (error) { + printk(KERN_WARNING + "gameport: device_bind_driver() failed " + "for %s (%s) and %s, error: %d\n", + gameport->phys, gameport->name, + drv->description, error); + drv->disconnect(gameport); + gameport->dev.driver = NULL; + goto out; + } + + out: up_write(&gameport_bus.subsys.rwsem); } -- GitLab From b435fdcda126db42343b8055d04a0a27c229717b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 12 Oct 2006 01:06:53 -0400 Subject: [PATCH 1104/1619] Input: fm801-gp - handle errors from pci_enable_device() Signed-off-by: Jeff Garzik Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/fm801-gp.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 90de5afe03c..1dec00e20db 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -82,17 +82,19 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device { struct fm801_gp *gp; struct gameport *port; + int error; gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL); port = gameport_allocate_port(); if (!gp || !port) { printk(KERN_ERR "fm801-gp: Memory allocation failed\n"); - kfree(gp); - gameport_free_port(port); - return -ENOMEM; + error = -ENOMEM; + goto err_out_free; } - pci_enable_device(pci); + error = pci_enable_device(pci); + if (error) + goto err_out_free; port->open = fm801_gp_open; #ifdef HAVE_COOKED @@ -108,9 +110,8 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device if (!gp->res_port) { printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n", port->io, port->io + 0x0f); - gameport_free_port(port); - kfree(gp); - return -EBUSY; + error = -EBUSY; + goto err_out_disable_dev; } pci_set_drvdata(pci, gp); @@ -119,6 +120,13 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device gameport_register_port(port); return 0; + + err_out_disable_dev: + pci_disable_device(pci); + err_out_free: + gameport_free_port(port); + kfree(gp); + return error; } static void __devexit fm801_gp_remove(struct pci_dev *pci) -- GitLab From c2baeb0526277676d4cee022f663af880c22fe84 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 10 Oct 2006 14:17:05 -0700 Subject: [PATCH 1105/1619] [SPARC32]: pcic.c needs asm/irq_regs.h Signed-off-by: David S. Miller --- arch/sparc/kernel/pcic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index b4e50ae323b..207f1b6eef5 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -34,6 +34,7 @@ #include #include #include +#include unsigned int pcic_pin_to_irq(unsigned int pin, char *name); -- GitLab From e3096de34c35683bc233f76d4e86562f1d782d0d Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Tue, 10 Oct 2006 14:36:47 -0700 Subject: [PATCH 1106/1619] [SPARC32]: Mark srmmu_nocache_init as __init. Fix these 2.6.19-rc1 build warnings from modpost: WARNING: vmlinux - Section mismatch: reference to .init.text:__alloc_bootmem from .text between 'srmmu_nocache_init' (at offset 0x1a0f8) and 'srmmu_mmu_info' WARNING: vmlinux - Section mismatch: reference to .init.text:__alloc_bootmem from .text between 'srmmu_nocache_init' (at offset 0x1a118) and 'srmmu_mmu_info' WARNING: vmlinux - Section mismatch: reference to .init.text:srmmu_early_allocate_ptable_skeleton from .text between 'srmmu_nocache_init' (at offset 0x1a188) and 'srmmu_mmu_info' Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/mm/srmmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index b27a506309e..0df7121cef0 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -402,7 +402,7 @@ void srmmu_nocache_calcsize(void) srmmu_nocache_end = SRMMU_NOCACHE_VADDR + srmmu_nocache_size; } -void srmmu_nocache_init(void) +void __init srmmu_nocache_init(void) { unsigned int bitmap_bits; pgd_t *pgd; -- GitLab From eba8cefc789f6e51a79363604a7db1dba6a678cb Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Tue, 10 Oct 2006 14:44:01 -0700 Subject: [PATCH 1107/1619] [SPARC32]: Fix sparc32 modpost warnings with sunzilog Fix this 2.6.19-rc1 build warnings from modpost: WARNING: vmlinux - Section mismatch: reference to .init.text:sunzilog_console_setup from .data between 'sunzilog_console' (at offset 0x8394) and 'devices_subsys' Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/kernel/setup.c | 10 ---------- arch/sparc64/kernel/setup.c | 10 ---------- drivers/serial/sunzilog.c | 6 +++--- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 0251cab4708..f5ee1ac834b 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -121,16 +121,6 @@ static struct console prom_debug_console = { .index = -1, }; -int obp_system_intr(void) -{ - if (boot_flags & BOOTME_DEBUG) { - printk("OBP: system interrupted\n"); - prom_halt(); - return 1; - } - return 0; -} - /* * Process kernel command line switches that are specific to the * SPARC or that require special low-level processing. diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 958287448cf..cc8ad480a20 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -91,16 +91,6 @@ void kernel_enter_debugger(void) { } -int obp_system_intr(void) -{ - if (boot_flags & BOOTME_DEBUG) { - printk("OBP: system interrupted\n"); - prom_halt(); - return 1; - } - return 0; -} - /* * Process kernel command line switches that are specific to the * SPARC or that require special low-level processing. diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 73dd2eedaaa..b2cc703b2b9 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1182,7 +1182,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) return 0; } -static struct console sunzilog_console = { +static struct console sunzilog_console_ops = { .name = "ttyS", .write = sunzilog_console_write, .device = uart_console_device, @@ -1208,10 +1208,10 @@ static inline struct console *SUNZILOG_CONSOLE(void) if (i == NUM_CHANNELS) return NULL; - sunzilog_console.index = i; + sunzilog_console_ops.index = i; sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; - return &sunzilog_console; + return &sunzilog_console_ops; } #else -- GitLab From ab5da288ce6a526a0a730362b8c4e03c3a0b58d5 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Wed, 11 Oct 2006 14:58:30 -0700 Subject: [PATCH 1108/1619] [SPARC32]: Fix sparc32 modpost warnings. Fix these 2.6.19-rc1 build warnings from modpost: WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'core_kernel_text' (at offset 0x3e060) and '__kernel_text_address' WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'core_kernel_text' (at offset 0x3e064) and '__kernel_text_address' WARNING: vmlinux - Section mismatch: reference to .init.text:_einittext from .text between 'core_kernel_text' (at offset 0x3e07c) and '__kernel_text_address' WARNING: vmlinux - Section mismatch: reference to .init.text:_einittext from .text between 'core_kernel_text' (at offset 0x3e080) and '__kernel_text_address' WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'is_ksym_addr' (at offset 0x4b3a4) and 'kallsyms_expand_symbol' WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'is_ksym_addr' (at offset 0x4b3a8) and 'kallsyms_expand_symbol' WARNING: vmlinux - Section mismatch: reference to .init.text:_einittext from .text between 'is_ksym_addr' (at offset 0x4b3b4) and 'kallsyms_expand_symbol' WARNING: vmlinux - Section mismatch: reference to .init.text:_einittext from .text between 'is_ksym_addr' (at offset 0x4b3e4) and 'kallsyms_expand_symbol' WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'get_symbol_pos' (at offset 0x4b640) and 'kallsyms_lookup_size_offset' WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'get_symbol_pos' (at offset 0x4b644) and 'kallsyms_lookup_size_offset' WARNING: vmlinux - Section mismatch: reference to .init.text:_einittext from .text between 'get_symbol_pos' (at offset 0x4b654) and 'kallsyms_lookup_size_offset' WARNING: vmlinux - Section mismatch: reference to .init.text:_einittext from .text between 'get_symbol_pos' (at offset 0x4b658) and 'kallsyms_lookup_size_offset' WARNING: vmlinux - Section mismatch: reference to .init.text:_sinittext from .text between 'get_symbol_pos' (at offset 0x4b68c) and 'kallsyms_lookup_size_offset' The crux of the matter is that modpost only checks the relocatable sections. i386 vmlinux has none, so modpost does no checking on it (it does on the modules). However, sparc vmlinux has plenty of relocatable sections because it is being built with 'ld -r' (to allow for btfixup processing). So for sparc, modpost does do a lot of checking. Sure enough, running modpost on arch/sparc/boot/image yields no output (i.e. all is well). modpost.c check_sec_ref() has: /* We want to process only relocation sections and not .init */ if (sechdrs[i].sh_type == SHT_RELA) { // check here } else if (sechdrs[i].sh_type == SHT_REL) { // check here } Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/kernel/vmlinux.lds.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 346c19a949f..1dd78c84888 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -36,11 +36,11 @@ SECTIONS . = ALIGN(4096); __init_begin = .; + _sinittext = .; .init.text : { - _sinittext = .; *(.init.text) - _einittext = .; } + _einittext = .; __init_text_end = .; .init.data : { *(.init.data) } . = ALIGN(16); -- GitLab From ffb733c65000ee701294f7b80c4eca2a5f335637 Mon Sep 17 00:00:00 2001 From: "paul.moore@hp.com" Date: Wed, 4 Oct 2006 11:46:31 -0400 Subject: [PATCH 1109/1619] NetLabel: fix a cache race condition Testing revealed a problem with the NetLabel cache where a cached entry could be freed while in use by the LSM layer causing an oops and other problems. This patch fixes that problem by introducing a reference counter to the cache entry so that it is only freed when it is no longer in use. Signed-off-by: Paul Moore Signed-off-by: James Morris --- include/net/netlabel.h | 62 ++++++++++++++++++++++++++-------- net/ipv4/cipso_ipv4.c | 18 +++++----- net/netlabel/netlabel_kapi.c | 2 +- security/selinux/ss/services.c | 37 +++++++++++--------- 4 files changed, 79 insertions(+), 40 deletions(-) diff --git a/include/net/netlabel.h b/include/net/netlabel.h index c63a58058e2..113337c2795 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -34,6 +34,7 @@ #include #include #include +#include /* * NetLabel - A management interface for maintaining network packet label @@ -106,6 +107,7 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); /* LSM security attributes */ struct netlbl_lsm_cache { + atomic_t refcount; void (*free) (const void *data); void *data; }; @@ -117,7 +119,7 @@ struct netlbl_lsm_secattr { unsigned char *mls_cat; size_t mls_cat_len; - struct netlbl_lsm_cache cache; + struct netlbl_lsm_cache *cache; }; /* @@ -125,6 +127,43 @@ struct netlbl_lsm_secattr { */ +/** + * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache + * @flags: the memory allocation flags + * + * Description: + * Allocate and initialize a netlbl_lsm_cache structure. Returns a pointer + * on success, NULL on failure. + * + */ +static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(int flags) +{ + struct netlbl_lsm_cache *cache; + + cache = kzalloc(sizeof(*cache), flags); + if (cache) + atomic_set(&cache->refcount, 1); + return cache; +} + +/** + * netlbl_secattr_cache_free - Frees a netlbl_lsm_cache struct + * @cache: the struct to free + * + * Description: + * Frees @secattr including all of the internal buffers. + * + */ +static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) +{ + if (!atomic_dec_and_test(&cache->refcount)) + return; + + if (cache->free) + cache->free(cache->data); + kfree(cache); +} + /** * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct * @secattr: the struct to initialize @@ -143,20 +182,16 @@ static inline int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) /** * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct * @secattr: the struct to clear - * @clear_cache: cache clear flag * * Description: * Destroys the @secattr struct, including freeing all of the internal buffers. - * If @clear_cache is true then free the cache fields, otherwise leave them - * intact. The struct must be reset with a call to netlbl_secattr_init() - * before reuse. + * The struct must be reset with a call to netlbl_secattr_init() before reuse. * */ -static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr, - u32 clear_cache) +static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) { - if (clear_cache && secattr->cache.data != NULL && secattr->cache.free) - secattr->cache.free(secattr->cache.data); + if (secattr->cache) + netlbl_secattr_cache_free(secattr->cache); kfree(secattr->domain); kfree(secattr->mls_cat); } @@ -178,17 +213,14 @@ static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(int flags) /** * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct * @secattr: the struct to free - * @clear_cache: cache clear flag * * Description: - * Frees @secattr including all of the internal buffers. If @clear_cache is - * true then free the cache fields, otherwise leave them intact. + * Frees @secattr including all of the internal buffers. * */ -static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr, - u32 clear_cache) +static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr) { - netlbl_secattr_destroy(secattr, clear_cache); + netlbl_secattr_destroy(secattr); kfree(secattr); } diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a8e2e879a64..bde8ccaa153 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -43,6 +43,7 @@ #include #include #include +#include #include struct cipso_v4_domhsh_entry { @@ -79,7 +80,7 @@ struct cipso_v4_map_cache_entry { unsigned char *key; size_t key_len; - struct netlbl_lsm_cache lsm_data; + struct netlbl_lsm_cache *lsm_data; u32 activity; struct list_head list; @@ -188,13 +189,14 @@ static void cipso_v4_doi_domhsh_free(struct rcu_head *entry) * @entry: the entry to free * * Description: - * This function frees the memory associated with a cache entry. + * This function frees the memory associated with a cache entry including the + * LSM cache data if there are no longer any users, i.e. reference count == 0. * */ static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry) { - if (entry->lsm_data.free) - entry->lsm_data.free(entry->lsm_data.data); + if (entry->lsm_data) + netlbl_secattr_cache_free(entry->lsm_data); kfree(entry->key); kfree(entry); } @@ -315,8 +317,8 @@ static int cipso_v4_cache_check(const unsigned char *key, entry->key_len == key_len && memcmp(entry->key, key, key_len) == 0) { entry->activity += 1; - secattr->cache.free = entry->lsm_data.free; - secattr->cache.data = entry->lsm_data.data; + atomic_inc(&entry->lsm_data->refcount); + secattr->cache = entry->lsm_data; if (prev_entry == NULL) { spin_unlock_bh(&cipso_v4_cache[bkt].lock); return 0; @@ -383,8 +385,8 @@ int cipso_v4_cache_add(const struct sk_buff *skb, memcpy(entry->key, cipso_ptr, cipso_ptr_len); entry->key_len = cipso_ptr_len; entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); - entry->lsm_data.free = secattr->cache.free; - entry->lsm_data.data = secattr->cache.data; + atomic_inc(&secattr->cache->refcount); + entry->lsm_data = secattr->cache; bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); spin_lock_bh(&cipso_v4_cache[bkt].lock); diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 54fb7de3c2b..ff971103fd0 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -200,7 +200,7 @@ void netlbl_cache_invalidate(void) int netlbl_cache_add(const struct sk_buff *skb, const struct netlbl_lsm_secattr *secattr) { - if (secattr->cache.data == NULL) + if (secattr->cache == NULL) return -ENOMSG; if (CIPSO_V4_OPTEXIST(skb)) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 0c219a1b324..bb2d2bc869b 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2172,7 +2172,12 @@ struct netlbl_cache { */ static void selinux_netlbl_cache_free(const void *data) { - struct netlbl_cache *cache = NETLBL_CACHE(data); + struct netlbl_cache *cache; + + if (data == NULL) + return; + + cache = NETLBL_CACHE(data); switch (cache->type) { case NETLBL_CACHE_T_MLS: ebitmap_destroy(&cache->data.mls_label.level[0].cat); @@ -2197,17 +2202,20 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx) struct netlbl_lsm_secattr secattr; netlbl_secattr_init(&secattr); + secattr.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); + if (secattr.cache == NULL) + goto netlbl_cache_add_return; cache = kzalloc(sizeof(*cache), GFP_ATOMIC); if (cache == NULL) - goto netlbl_cache_add_failure; - secattr.cache.free = selinux_netlbl_cache_free; - secattr.cache.data = (void *)cache; + goto netlbl_cache_add_return; + secattr.cache->free = selinux_netlbl_cache_free; + secattr.cache->data = (void *)cache; cache->type = NETLBL_CACHE_T_MLS; if (ebitmap_cpy(&cache->data.mls_label.level[0].cat, &ctx->range.level[0].cat) != 0) - goto netlbl_cache_add_failure; + goto netlbl_cache_add_return; cache->data.mls_label.level[1].cat.highbit = cache->data.mls_label.level[0].cat.highbit; cache->data.mls_label.level[1].cat.node = @@ -2215,13 +2223,10 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx) cache->data.mls_label.level[0].sens = ctx->range.level[0].sens; cache->data.mls_label.level[1].sens = ctx->range.level[0].sens; - if (netlbl_cache_add(skb, &secattr) != 0) - goto netlbl_cache_add_failure; - - return; + netlbl_cache_add(skb, &secattr); -netlbl_cache_add_failure: - netlbl_secattr_destroy(&secattr, 1); +netlbl_cache_add_return: + netlbl_secattr_destroy(&secattr); } /** @@ -2263,8 +2268,8 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb, POLICY_RDLOCK; - if (secattr->cache.data) { - cache = NETLBL_CACHE(secattr->cache.data); + if (secattr->cache) { + cache = NETLBL_CACHE(secattr->cache->data); switch (cache->type) { case NETLBL_CACHE_T_SID: *sid = cache->data.sid; @@ -2369,7 +2374,7 @@ static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, &secattr, base_sid, sid); - netlbl_secattr_destroy(&secattr, 0); + netlbl_secattr_destroy(&secattr); return rc; } @@ -2415,7 +2420,7 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) if (rc == 0) sksec->nlbl_state = NLBL_LABELED; - netlbl_secattr_destroy(&secattr, 0); + netlbl_secattr_destroy(&secattr); netlbl_socket_setsid_return: POLICY_RDUNLOCK; @@ -2517,7 +2522,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) sksec->sid, &nlbl_peer_sid) == 0) sksec->peer_sid = nlbl_peer_sid; - netlbl_secattr_destroy(&secattr, 0); + netlbl_secattr_destroy(&secattr); sksec->nlbl_state = NLBL_REQUIRE; -- GitLab From 388b24057f90ba109d4bf855006a8809c383eb76 Mon Sep 17 00:00:00 2001 From: "paul.moore@hp.com" Date: Thu, 5 Oct 2006 18:28:24 -0400 Subject: [PATCH 1110/1619] NetLabel: use SECINITSID_UNLABELED for a base SID This patch changes NetLabel to use SECINITSID_UNLABLELED as it's source of SELinux type information when generating a NetLabel context. Signed-off-by: Paul Moore Signed-off-by: James Morris --- security/selinux/ss/services.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index bb2d2bc869b..18274b00509 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2336,7 +2336,7 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb, selinux_netlbl_cache_add(skb, &ctx_new); ebitmap_destroy(&ctx_new.range.level[0].cat); } else { - *sid = SECINITSID_UNLABELED; + *sid = SECSID_NULL; rc = 0; } @@ -2519,7 +2519,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) if (netlbl_sock_getattr(sk, &secattr) == 0 && selinux_netlbl_secattr_to_sid(NULL, &secattr, - sksec->sid, + SECINITSID_UNLABELED, &nlbl_peer_sid) == 0) sksec->peer_sid = nlbl_peer_sid; netlbl_secattr_destroy(&secattr); @@ -2552,9 +2552,6 @@ u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid) if (rc != 0) return SECSID_NULL; - if (peer_sid == SECINITSID_UNLABELED) - return SECSID_NULL; - return peer_sid; } @@ -2616,11 +2613,13 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, u32 netlbl_sid; u32 recv_perm; - rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &netlbl_sid); + rc = selinux_netlbl_skbuff_getsid(skb, + SECINITSID_UNLABELED, + &netlbl_sid); if (rc != 0) return rc; - if (netlbl_sid == SECINITSID_UNLABELED) + if (netlbl_sid == SECSID_NULL) return 0; switch (sksec->sclass) { @@ -2658,10 +2657,6 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock) { struct sk_security_struct *sksec = sock->sk->sk_security; - - if (sksec->peer_sid == SECINITSID_UNLABELED) - return SECSID_NULL; - return sksec->peer_sid; } @@ -2677,16 +2672,10 @@ u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock) u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb) { int peer_sid; - struct sock *sk = skb->sk; - struct inode_security_struct *isec; - if (sk == NULL || sk->sk_socket == NULL) - return SECSID_NULL; - - isec = SOCK_INODE(sk->sk_socket)->i_security; - if (selinux_netlbl_skbuff_getsid(skb, isec->sid, &peer_sid) != 0) - return SECSID_NULL; - if (peer_sid == SECINITSID_UNLABELED) + if (selinux_netlbl_skbuff_getsid(skb, + SECINITSID_UNLABELED, + &peer_sid) != 0) return SECSID_NULL; return peer_sid; -- GitLab From 134b0fc544ba062498451611cb6f3e4454221b3d Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 5 Oct 2006 15:42:27 -0500 Subject: [PATCH 1111/1619] IPsec: propagate security module errors up from flow_cache_lookup When a security module is loaded (in this case, SELinux), the security_xfrm_policy_lookup() hook can return an access denied permission (or other error). 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 way I 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. The first SYNACK would be blocked, because of an uncached lookup via flow_cache_lookup(), which would fail to resolve an xfrm policy because the SELinux policy is checked at that point via the resolver. However, retransmitted SYNACKs would then find a cached flow entry when calling into flow_cache_lookup() with a null xfrm policy, which is interpreted by xfrm_lookup() as the packet not having any associated policy and similarly to the first case, allowing it to pass without transformation. The solution presented here 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). Signed-off-by: James Morris --- include/net/flow.h | 2 +- net/core/flow.c | 42 +++++++++++++++++--------- net/xfrm/xfrm_policy.c | 68 ++++++++++++++++++++++++++++++++---------- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index ddf5f3ca172..3b44d72b27d 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -97,7 +97,7 @@ struct flowi { #define FLOW_DIR_FWD 2 struct sock; -typedef void (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir, +typedef int (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir, void **objp, atomic_t **obj_refp); extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, diff --git a/net/core/flow.c b/net/core/flow.c index f23e7e38654..b16d31ae5e5 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -85,6 +85,14 @@ static void flow_cache_new_hashrnd(unsigned long arg) add_timer(&flow_hash_rnd_timer); } +static void flow_entry_kill(int cpu, struct flow_cache_entry *fle) +{ + if (fle->object) + atomic_dec(fle->object_ref); + kmem_cache_free(flow_cachep, fle); + flow_count(cpu)--; +} + static void __flow_cache_shrink(int cpu, int shrink_to) { struct flow_cache_entry *fle, **flp; @@ -100,10 +108,7 @@ static void __flow_cache_shrink(int cpu, int shrink_to) } while ((fle = *flp) != NULL) { *flp = fle->next; - if (fle->object) - atomic_dec(fle->object_ref); - kmem_cache_free(flow_cachep, fle); - flow_count(cpu)--; + flow_entry_kill(cpu, fle); } } } @@ -220,24 +225,33 @@ void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, nocache: { + int err; void *obj; atomic_t *obj_ref; - resolver(key, family, dir, &obj, &obj_ref); + err = resolver(key, family, dir, &obj, &obj_ref); if (fle) { - fle->genid = atomic_read(&flow_cache_genid); - - if (fle->object) - atomic_dec(fle->object_ref); - - fle->object = obj; - fle->object_ref = obj_ref; - if (obj) - atomic_inc(fle->object_ref); + if (err) { + /* Force security policy check on next lookup */ + *head = fle->next; + flow_entry_kill(cpu, fle); + } else { + fle->genid = atomic_read(&flow_cache_genid); + + if (fle->object) + atomic_dec(fle->object_ref); + + fle->object = obj; + fle->object_ref = obj_ref; + if (obj) + atomic_inc(fle->object_ref); + } } local_bh_enable(); + if (err) + obj = ERR_PTR(err); return obj; } } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 2a7861661f1..fffdd34f3ba 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -883,30 +883,32 @@ out: } EXPORT_SYMBOL(xfrm_policy_walk); -/* Find policy to apply to this flow. */ - +/* + * Find policy to apply to this flow. + * + * Returns 0 if policy found, else an -errno. + */ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, u8 type, u16 family, int dir) { struct xfrm_selector *sel = &pol->selector; - int match; + int match, ret = -ESRCH; if (pol->family != family || pol->type != type) - return 0; + return ret; match = xfrm_selector_match(sel, fl, family); - if (match) { - if (!security_xfrm_policy_lookup(pol, fl->secid, dir)) - return 1; - } + if (match) + ret = security_xfrm_policy_lookup(pol, fl->secid, dir); - return 0; + return ret; } static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, u16 family, u8 dir) { + int err; struct xfrm_policy *pol, *ret; xfrm_address_t *daddr, *saddr; struct hlist_node *entry; @@ -922,7 +924,15 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, chain = policy_hash_direct(daddr, saddr, family, dir); ret = NULL; hlist_for_each_entry(pol, entry, chain, bydst) { - if (xfrm_policy_match(pol, fl, type, family, dir)) { + err = xfrm_policy_match(pol, fl, type, family, dir); + if (err) { + if (err == -ESRCH) + continue; + else { + ret = ERR_PTR(err); + goto fail; + } + } else { ret = pol; priority = ret->priority; break; @@ -930,36 +940,53 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, } chain = &xfrm_policy_inexact[dir]; hlist_for_each_entry(pol, entry, chain, bydst) { - if (xfrm_policy_match(pol, fl, type, family, dir) && - pol->priority < priority) { + err = xfrm_policy_match(pol, fl, type, family, dir); + if (err) { + if (err == -ESRCH) + continue; + else { + ret = ERR_PTR(err); + goto fail; + } + } else if (pol->priority < priority) { ret = pol; break; } } if (ret) xfrm_pol_hold(ret); +fail: read_unlock_bh(&xfrm_policy_lock); return ret; } -static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, +static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, void **objp, atomic_t **obj_refp) { struct xfrm_policy *pol; + int err = 0; #ifdef CONFIG_XFRM_SUB_POLICY pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); - if (pol) + if (IS_ERR(pol)) { + err = PTR_ERR(pol); + pol = NULL; + } + if (pol || err) goto end; #endif pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); - + if (IS_ERR(pol)) { + err = PTR_ERR(pol); + pol = NULL; + } #ifdef CONFIG_XFRM_SUB_POLICY end: #endif if ((*objp = (void *) pol) != NULL) *obj_refp = &pol->refcnt; + return err; } static inline int policy_to_flow_dir(int dir) @@ -1297,6 +1324,8 @@ restart: policy = flow_cache_lookup(fl, dst_orig->ops->family, dir, xfrm_policy_lookup); + if (IS_ERR(policy)) + return PTR_ERR(policy); } if (!policy) @@ -1343,6 +1372,10 @@ restart: fl, family, XFRM_POLICY_OUT); if (pols[1]) { + if (IS_ERR(pols[1])) { + err = PTR_ERR(pols[1]); + goto error; + } if (pols[1]->action == XFRM_POLICY_BLOCK) { err = -EPERM; goto error; @@ -1581,6 +1614,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, pol = flow_cache_lookup(&fl, family, fl_dir, xfrm_policy_lookup); + if (IS_ERR(pol)) + return 0; + if (!pol) { if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { xfrm_secpath_reject(xerr_idx, skb, &fl); @@ -1599,6 +1635,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, &fl, family, XFRM_POLICY_IN); if (pols[1]) { + if (IS_ERR(pols[1])) + return 0; pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; npols ++; } -- GitLab From 5b368e61c2bcb2666bb66e2acf1d6d85ba6f474d Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Thu, 5 Oct 2006 15:42:18 -0500 Subject: [PATCH 1112/1619] 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(-) diff --git a/include/linux/security.h b/include/linux/security.h index 9b5fea81f55..b200b9856f3 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 1e2a4ddec96..737fdb2ee8a 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 7a7a00147e5..1bed0cdf53e 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 6a252e2134d..73cee2ec07e 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 ff98e70b093..20ff7cca1d0 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 fffdd34f3ba..695761ff132 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 d54b3a70d5d..2b2e59d8ffb 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 aeee7056550..43874c1e6e2 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 81eb5989016..526b28019ac 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 3e742b850af..675b995a67c 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)) -- GitLab From 3bccfbc7a7ba4085817deae6e7c67daf0cbd045a Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Thu, 5 Oct 2006 15:42:35 -0500 Subject: [PATCH 1113/1619] IPsec: fix handling of errors for socket policies This treats the security errors encountered in the case of socket policy matching, the same as how these are treated in the case of main/sub policies, which is to return a full lookup failure. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- net/xfrm/xfrm_policy.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 695761ff132..7736b23c3f0 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1016,12 +1016,16 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc sk->sk_family); int err = 0; - if (match) - err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir)); - - if (match && !err) - xfrm_pol_hold(pol); - else + if (match) { + err = security_xfrm_policy_lookup(pol, fl->secid, + policy_to_flow_dir(dir)); + if (!err) + xfrm_pol_hold(pol); + else if (err == -ESRCH) + pol = NULL; + else + pol = ERR_PTR(err); + } else pol = NULL; } read_unlock_bh(&xfrm_policy_lock); @@ -1313,8 +1317,11 @@ restart: pol_dead = 0; xfrm_nr = 0; - if (sk && sk->sk_policy[1]) + if (sk && sk->sk_policy[1]) { policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); + if (IS_ERR(policy)) + return PTR_ERR(policy); + } if (!policy) { /* To accelerate a bit... */ @@ -1607,8 +1614,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, } pol = NULL; - if (sk && sk->sk_policy[dir]) + if (sk && sk->sk_policy[dir]) { pol = xfrm_sk_policy_lookup(sk, dir, &fl); + if (IS_ERR(pol)) + return 0; + } if (!pol) pol = flow_cache_lookup(&fl, family, fl_dir, -- GitLab From 6e8c751e07b34d73069e9333f67fbe5ffe31ec3a Mon Sep 17 00:00:00 2001 From: Chad Sellers Date: Fri, 6 Oct 2006 16:09:52 -0400 Subject: [PATCH 1114/1619] SELinux: Bug fix in polidydb_destroy This patch fixes two bugs in policydb_destroy. Two list pointers (policydb.ocontexts[i] and policydb.genfs) were not being reset to NULL when the lists they pointed to were being freed. This caused a problem when the initial policy load failed, as the policydb being destroyed was not a temporary new policydb that was thrown away, but rather was the global (active) policydb. Consequently, later functions, particularly sys_bind->selinux_socket_bind->security_node_sid and do_rw_proc->selinux_sysctl->selinux_proc_get_sid->security_genfs_sid tried to dereference memory that had previously been freed. Signed-off-by: Chad Sellers Signed-off-by: James Morris --- security/selinux/ss/policydb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index b1889530255..ba48961f9d0 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -618,6 +618,7 @@ void policydb_destroy(struct policydb *p) c = c->next; ocontext_destroy(ctmp,i); } + p->ocontexts[i] = NULL; } g = p->genfs; @@ -633,6 +634,7 @@ void policydb_destroy(struct policydb *p) g = g->next; kfree(gtmp); } + p->genfs = NULL; cond_policydb_destroy(p); -- GitLab From 331c4ee7faa4ee1e1404c872a139784753100498 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 9 Oct 2006 21:34:04 -0700 Subject: [PATCH 1115/1619] [SCTP]: Fix receive buffer accounting. When doing receiver buffer accounting, we always used skb->truesize. This is problematic when processing bundled DATA chunks because for every DATA chunk that could be small part of one large skb, we would charge the size of the entire skb. The new approach is to store the size of the DATA chunk we are accounting for in the sctp_ulpevent structure and use that stored value for accounting. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 14 ++++++++++++++ include/net/sctp/ulpevent.h | 1 + net/sctp/socket.c | 22 ++++++++++++++++++---- net/sctp/ulpevent.c | 25 +++++++++++++++---------- net/sctp/ulpqueue.c | 2 +- 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index ee68a312407..764e3af5be9 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -139,6 +139,7 @@ int sctp_inet_listen(struct socket *sock, int backlog); void sctp_write_space(struct sock *sk); unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); +void sctp_sock_rfree(struct sk_buff *skb); /* * sctp/primitive.c @@ -444,6 +445,19 @@ static inline struct list_head *sctp_list_dequeue(struct list_head *list) return result; } +/* SCTP version of skb_set_owner_r. We need this one because + * of the way we have to do receive buffer accounting on bundled + * chunks. + */ +static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + struct sctp_ulpevent *event = sctp_skb2event(skb); + + skb->sk = sk; + skb->destructor = sctp_sock_rfree; + atomic_add(event->rmem_len, &sk->sk_rmem_alloc); +} + /* Tests if the list has one and only one entry. */ static inline int sctp_list_single_entry(struct list_head *head) { diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 6c40cfc4832..1a4ddc1ec7d 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -63,6 +63,7 @@ struct sctp_ulpevent { __u32 cumtsn; int msg_flags; int iif; + unsigned int rmem_len; }; /* Retrieve the skb this event sits inside of. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3fe906d6506..9deec439118 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5362,6 +5362,20 @@ static void sctp_wfree(struct sk_buff *skb) sctp_association_put(asoc); } +/* Do accounting for the receive space on the socket. + * Accounting for the association is done in ulpevent.c + * We set this as a destructor for the cloned data skbs so that + * accounting is done at the correct time. + */ +void sctp_sock_rfree(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + struct sctp_ulpevent *event = sctp_skb2event(skb); + + atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); +} + + /* Helper function to wait for space in the sndbuf. */ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, size_t msg_len) @@ -5634,10 +5648,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { event = sctp_skb2event(skb); if (event->asoc == assoc) { - sock_rfree(skb); + sctp_sock_rfree(skb); __skb_unlink(skb, &oldsk->sk_receive_queue); __skb_queue_tail(&newsk->sk_receive_queue, skb); - skb_set_owner_r(skb, newsk); + sctp_skb_set_owner_r(skb, newsk); } } @@ -5665,10 +5679,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { event = sctp_skb2event(skb); if (event->asoc == assoc) { - sock_rfree(skb); + sctp_sock_rfree(skb); __skb_unlink(skb, &oldsp->pd_lobby); __skb_queue_tail(queue, skb); - skb_set_owner_r(skb, newsk); + sctp_skb_set_owner_r(skb, newsk); } } diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index ee236784a6b..a015283a908 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -55,10 +55,13 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event); /* Initialize an ULP event from an given skb. */ -SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) +SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, + int msg_flags, + unsigned int len) { memset(event, 0, sizeof(struct sctp_ulpevent)); event->msg_flags = msg_flags; + event->rmem_len = len; } /* Create a new sctp_ulpevent. */ @@ -73,7 +76,7 @@ SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, goto fail; event = sctp_skb2event(skb); - sctp_ulpevent_init(event, msg_flags); + sctp_ulpevent_init(event, msg_flags, skb->truesize); return event; @@ -101,17 +104,16 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, sctp_association_hold((struct sctp_association *)asoc); skb = sctp_event2skb(event); event->asoc = (struct sctp_association *)asoc; - atomic_add(skb->truesize, &event->asoc->rmem_alloc); - skb_set_owner_r(skb, asoc->base.sk); + atomic_add(event->rmem_len, &event->asoc->rmem_alloc); + sctp_skb_set_owner_r(skb, asoc->base.sk); } /* A simple destructor to give up the reference to the association. */ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) { struct sctp_association *asoc = event->asoc; - struct sk_buff *skb = sctp_event2skb(event); - atomic_sub(skb->truesize, &asoc->rmem_alloc); + atomic_sub(event->rmem_len, &asoc->rmem_alloc); sctp_association_put(asoc); } @@ -372,7 +374,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - sctp_ulpevent_init(event, MSG_NOTIFICATION); + sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); sre = (struct sctp_remote_error *) skb_push(skb, sizeof(struct sctp_remote_error)); @@ -464,7 +466,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - sctp_ulpevent_init(event, MSG_NOTIFICATION); + sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); ssf = (struct sctp_send_failed *) skb_push(skb, sizeof(struct sctp_send_failed)); @@ -682,8 +684,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - /* Initialize event with flags 0. */ - sctp_ulpevent_init(event, 0); + /* Initialize event with flags 0 and correct length + * Since this is a clone of the original skb, only account for + * the data of this chunk as other chunks will be accounted separately. + */ + sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff)); sctp_ulpevent_receive_data(event, asoc); diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 575e556aeb3..e1d144275f9 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -309,7 +309,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu if (!new) return NULL; /* try again later */ - new->sk = f_frag->sk; + sctp_skb_set_owner_r(new, f_frag->sk); skb_shinfo(new)->frag_list = pos; } else -- GitLab From 6aa2551cf135f1d246d31482adc8c679eeea3a83 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 9 Oct 2006 21:34:26 -0700 Subject: [PATCH 1116/1619] [SCTP]: Fix the RX queue size shown in /proc/net/sctp/assocs output. Show the true receive buffer usage. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/proc.c b/net/sctp/proc.c index a356d8d310a..7f49e769080 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -344,7 +344,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) assoc, sk, sctp_sk(sk)->type, sk->sk_state, assoc->state, hash, assoc->assoc_id, assoc->sndbuf_used, - (sk->sk_rcvbuf - assoc->rwnd), + atomic_read(&assoc->rmem_alloc), sock_i_uid(sk), sock_i_ino(sk), epb->bind_addr.port, assoc->peer.port); -- GitLab From effee6a00034a8d83a6dea6d221820d87364ac21 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 9 Oct 2006 21:42:14 -0700 Subject: [PATCH 1117/1619] [NET]: File descriptor loss while receiving SCM_RIGHTS If more than one file descriptor was sent with an SCM_RIGHTS message, and on the receiving end, after installing a nonzero (but not all) file descritpors the process runs out of fds, then the already installed fds will be lost (userspace will have no way of knowing about them). The following patch makes sure, that at least the already installed fds are sent to userspace. It doesn't solve the issue of losing file descriptors in case of an EFAULT on the userspace buffer. Signed-off-by: Miklos Szeredi Signed-off-by: David S. Miller --- net/compat.c | 3 +-- net/core/scm.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/net/compat.c b/net/compat.c index d5d69fa15d0..52d32f1bc72 100644 --- a/net/compat.c +++ b/net/compat.c @@ -285,8 +285,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) if (i > 0) { int cmlen = CMSG_COMPAT_LEN(i * sizeof(int)); - if (!err) - err = put_user(SOL_SOCKET, &cm->cmsg_level); + err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) diff --git a/net/core/scm.c b/net/core/scm.c index 649d01ef35b..271cf060ef8 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -245,8 +245,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) if (i > 0) { int cmlen = CMSG_LEN(i*sizeof(int)); - if (!err) - err = put_user(SOL_SOCKET, &cm->cmsg_level); + err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) -- GitLab From 989e5b96e1af399296e2d1a34ca4a5aea1cf6d63 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 10 Oct 2006 14:47:44 -0700 Subject: [PATCH 1118/1619] [IPV6]: Seperate sit driver to extra module This patch removes the driver of the IPv6-in-IPv4 tunnel driver (sit) from the IPv6 module. It adds an option to Kconfig which makes it possible to compile it as a seperate module. Signed-off-by: Joerg Roedel Signed-off-by: David S. Miller --- net/ipv6/Kconfig | 13 +++++++++++++ net/ipv6/Makefile | 3 ++- net/ipv6/af_inet6.c | 2 -- net/ipv6/sit.c | 3 +++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index a460e8132b4..ef5eaad4485 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -153,6 +153,19 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION ---help--- Support for MIPv6 route optimization mode. +config IPV6_SIT + tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" + depends on IPV6 + default y + ---help--- + Tunneling means encapsulating data of one protocol type within + another protocol and sending it over a channel that understands the + encapsulating protocol. This driver implements encapsulation of IPv6 + into IPv4 packets. This is useful if you want to connect two IPv6 + networks over an IPv4-only path. + + Saying M here will produce a module called sit.ko. If unsure, say Y. + config IPV6_TUNNEL tristate "IPv6: IPv6-in-IPv6 tunnel" select INET6_TUNNEL diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 87274e47fe3..addcc011bc0 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IPV6) += ipv6.o -ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.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 \ exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ @@ -29,6 +29,7 @@ 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_SIT) += sit.o obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o obj-y += exthdrs_core.o diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e94eccb9970..858cae29581 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -850,7 +850,6 @@ static int __init inet6_init(void) err = addrconf_init(); if (err) goto addrconf_fail; - sit_init(); /* Init v6 extension headers. */ ipv6_rthdr_init(); @@ -927,7 +926,6 @@ static void __exit inet6_exit(void) mip6_fini(); #endif /* Cleanup code parts. */ - sit_cleanup(); ip6_flowlabel_cleanup(); addrconf_cleanup(); ip6_route_cleanup(); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 836eecd7e62..dc5765b62b8 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -850,3 +850,6 @@ int __init sit_init(void) inet_del_protocol(&sit_protocol, IPPROTO_IPV6); goto out; } + +module_init(sit_init); +module_exit(sit_cleanup); -- GitLab From 0be669bb37693103c15e64610454f8f431a38feb Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 10 Oct 2006 14:49:53 -0700 Subject: [PATCH 1119/1619] [IPV6]: Seperate sit driver to extra module (addrconf.c changes) This patch contains the changes to net/ipv6/addrconf.c to remove sit specific code if the sit driver is not selected. Signed-off-by: Joerg Roedel Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e03c33b2465..b312a5f7a75 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -396,8 +396,10 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) ndev->regen_timer.data = (unsigned long) ndev; if ((dev->flags&IFF_LOOPBACK) || dev->type == ARPHRD_TUNNEL || - dev->type == ARPHRD_NONE || - dev->type == ARPHRD_SIT) { +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) + dev->type == ARPHRD_SIT || +#endif + dev->type == ARPHRD_NONE) { printk(KERN_INFO "%s: Disabled Privacy Extensions\n", dev->name); @@ -1546,8 +1548,10 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, This thing is done here expecting that the whole class of non-broadcast devices need not cloning. */ +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) cfg.fc_flags |= RTF_NONEXTHOP; +#endif ip6_route_add(&cfg); } @@ -1569,6 +1573,7 @@ static void addrconf_add_mroute(struct net_device *dev) ip6_route_add(&cfg); } +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) static void sit_route_add(struct net_device *dev) { struct fib6_config cfg = { @@ -1582,6 +1587,7 @@ static void sit_route_add(struct net_device *dev) /* prefix length - 96 bits "::d.d.d.d" */ ip6_route_add(&cfg); } +#endif static void addrconf_add_lroute(struct net_device *dev) { @@ -1852,6 +1858,7 @@ int addrconf_set_dstaddr(void __user *arg) if (dev == NULL) goto err_exit; +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) if (dev->type == ARPHRD_SIT) { struct ifreq ifr; mm_segment_t oldfs; @@ -1881,6 +1888,7 @@ int addrconf_set_dstaddr(void __user *arg) err = dev_open(dev); } } +#endif err_exit: rtnl_unlock(); @@ -2010,6 +2018,7 @@ int addrconf_del_ifaddr(void __user *arg) return err; } +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) static void sit_add_v4_addrs(struct inet6_dev *idev) { struct inet6_ifaddr * ifp; @@ -2078,6 +2087,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) } } } +#endif static void init_loopback(struct net_device *dev) { @@ -2141,6 +2151,7 @@ static void addrconf_dev_config(struct net_device *dev) addrconf_add_linklocal(idev, &addr); } +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) static void addrconf_sit_config(struct net_device *dev) { struct inet6_dev *idev; @@ -2166,6 +2177,7 @@ static void addrconf_sit_config(struct net_device *dev) } else sit_route_add(dev); } +#endif static inline int ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) @@ -2260,9 +2272,11 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, } switch(dev->type) { +#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) case ARPHRD_SIT: addrconf_sit_config(dev); break; +#endif case ARPHRD_TUNNEL6: addrconf_ip6_tnl_config(dev); break; -- GitLab From 4244f8a9f86a6d6e820b4cb53835c15c56d41aff Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 10 Oct 2006 19:40:50 -0700 Subject: [PATCH 1120/1619] [TCP]: Use TCPOLEN_TSTAMP_ALIGNED macro instead of magic number. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c83938b8fcb..f745095196f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -578,7 +578,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 tsopt[3]; + u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2]; } rep; struct ip_reply_arg arg; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3b6575478fc..34e004bdeab 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -653,7 +653,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 int tot_len = sizeof(struct tcphdr); if (ts) - tot_len += 3*4; + tot_len += TCPOLEN_TSTAMP_ALIGNED; buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); -- GitLab From 496c98dff8e353880299168d36fa082d6fba5237 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 10 Oct 2006 19:41:21 -0700 Subject: [PATCH 1121/1619] [NET]: Use hton{l,s}() for non-initializers. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/tcp_output.c | 31 ++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f5fba051df3..d5b5dec075b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -611,8 +611,8 @@ static int ipgre_rcv(struct sk_buff *skb) * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header */ if (flags == 0 && - skb->protocol == __constant_htons(ETH_P_WCCP)) { - skb->protocol = __constant_htons(ETH_P_IP); + skb->protocol == htons(ETH_P_WCCP)) { + skb->protocol = htons(ETH_P_IP); if ((*(h + offset) & 0xF0) != 0x40) offset += 4; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 9a253faefc8..f22536e32cb 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -273,10 +273,10 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, __u32 tstamp) { if (tp->rx_opt.tstamp_ok) { - *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); *ptr++ = htonl(tstamp); *ptr++ = htonl(tp->rx_opt.ts_recent); } @@ -325,18 +325,27 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss); if (ts) { if(sack) - *ptr++ = __constant_htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) | - (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); + *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | + (TCPOLEN_SACK_PERM << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); else - *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); *ptr++ = htonl(tstamp); /* TSVAL */ *ptr++ = htonl(ts_recent); /* TSECR */ } else if(sack) - *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM); + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_SACK_PERM << 8) | + TCPOLEN_SACK_PERM); if (offer_wscale) - *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale)); + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_WINDOW << 16) | + (TCPOLEN_WINDOW << 8) | + (wscale)); } /* This routine actually transmits TCP packets queued in by -- GitLab From 9469c7b4aa210ce94c6e7208cfadbd0aca0ebe08 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 10 Oct 2006 19:41:46 -0700 Subject: [PATCH 1122/1619] [NET]: Use typesafe inet_twsk() inline function instead of cast. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 6 +++--- net/dccp/ipv6.c | 6 +++--- net/ipv4/tcp_ipv4.c | 16 +++++++--------- net/ipv6/tcp_ipv6.c | 11 +++++------ 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index bf692c1c116..7e746c4c168 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -311,7 +311,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) } if (sk->sk_state == DCCP_TIME_WAIT) { - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); return; } @@ -614,7 +614,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) bh_lock_sock(nsk); return nsk; } - inet_twsk_put((struct inet_timewait_sock *)nsk); + inet_twsk_put(inet_twsk(nsk)); return NULL; } @@ -980,7 +980,7 @@ discard_and_relse: goto discard_it; do_time_wait: - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); goto no_dccp_socket; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 7a47399cf31..7171a78671a 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -285,7 +285,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, } if (sk->sk_state == DCCP_TIME_WAIT) { - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); return; } @@ -663,7 +663,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) bh_lock_sock(nsk); return nsk; } - inet_twsk_put((struct inet_timewait_sock *)nsk); + inet_twsk_put(inet_twsk(nsk)); return NULL; } @@ -1109,7 +1109,7 @@ discard_and_relse: goto discard_it; do_time_wait: - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); goto no_dccp_socket; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f745095196f..6bbd9857517 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -355,7 +355,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) return; } if (sk->sk_state == TCP_TIME_WAIT) { - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); return; } @@ -960,7 +960,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) bh_lock_sock(nsk); return nsk; } - inet_twsk_put((struct inet_timewait_sock *)nsk); + inet_twsk_put(inet_twsk(nsk)); return NULL; } @@ -1154,26 +1154,24 @@ discard_and_relse: do_time_wait: if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - inet_twsk_put((struct inet_timewait_sock *) sk); + inet_twsk_put(inet_twsk(sk)); goto discard_it; } if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TCP_MIB_INERRS); - inet_twsk_put((struct inet_timewait_sock *) sk); + inet_twsk_put(inet_twsk(sk)); goto discard_it; } - switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk, - skb, th)) { + switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { case TCP_TW_SYN: { struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo, skb->nh.iph->daddr, th->dest, inet_iif(skb)); if (sk2) { - inet_twsk_deschedule((struct inet_timewait_sock *)sk, - &tcp_death_row); - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row); + inet_twsk_put(inet_twsk(sk)); sk = sk2; goto process; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 34e004bdeab..4c2a7c0cafe 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -329,7 +329,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, } if (sk->sk_state == TCP_TIME_WAIT) { - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); return; } @@ -749,7 +749,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) bh_lock_sock(nsk); return nsk; } - inet_twsk_put((struct inet_timewait_sock *)nsk); + inet_twsk_put(inet_twsk(nsk)); return NULL; } @@ -1283,18 +1283,17 @@ discard_and_relse: do_time_wait: if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); goto discard_it; } if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TCP_MIB_INERRS); - inet_twsk_put((struct inet_timewait_sock *)sk); + inet_twsk_put(inet_twsk(sk)); goto discard_it; } - switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk, - skb, th)) { + switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { case TCP_TW_SYN: { struct sock *sk2; -- GitLab From 42b6785eeb40fe3e9dab9981b6e3231a77c7c2f6 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 10 Oct 2006 19:42:09 -0700 Subject: [PATCH 1123/1619] [NET]: Introduce protocol-specific destructor for time-wait sockets. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/inet_timewait_sock.h | 1 + include/net/timewait_sock.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 6d14c22a00c..5f48748fe01 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -196,6 +196,7 @@ static inline void inet_twsk_put(struct inet_timewait_sock *tw) { if (atomic_dec_and_test(&tw->tw_refcnt)) { struct module *owner = tw->tw_prot->owner; + twsk_destructor((struct sock *)tw); #ifdef SOCK_REFCNT_DEBUG printk(KERN_DEBUG "%s timewait_sock %p released\n", tw->tw_prot->name, tw); diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h index 2544281e1d5..be293d795e3 100644 --- a/include/net/timewait_sock.h +++ b/include/net/timewait_sock.h @@ -19,6 +19,7 @@ struct timewait_sock_ops { unsigned int twsk_obj_size; int (*twsk_unique)(struct sock *sk, struct sock *sktw, void *twp); + void (*twsk_destructor)(struct sock *sk); }; static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) @@ -28,4 +29,10 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) return 0; } +static inline void twsk_destructor(struct sock *sk) +{ + if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) + sk->sk_prot->twsk_prot->twsk_destructor(sk); +} + #endif /* _TIMEWAIT_SOCK_H */ -- GitLab From 8238b218ec883adb44d710960a031c76105274cd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 Oct 2006 00:49:15 -0700 Subject: [PATCH 1124/1619] [NET]: Do not memcmp() over pad bytes of struct flowi. They are not necessarily initialized to zero by the compiler, for example when using run-time initializers of automatic on-stack variables. Noticed by Eric Dumazet and Patrick McHardy. Signed-off-by: David S. Miller --- net/decnet/dn_route.c | 11 ++++++++--- net/ipv4/route.c | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index dd0761e3d28..a2a43d8d93f 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -267,9 +267,14 @@ static void dn_dst_link_failure(struct sk_buff *skb) static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { - return memcmp(&fl1->nl_u.dn_u, &fl2->nl_u.dn_u, sizeof(fl1->nl_u.dn_u)) == 0 && - fl1->oif == fl2->oif && - fl1->iif == fl2->iif; + return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) | + (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) | +#ifdef CONFIG_IP_ROUTE_FWMARK + (fl1->nl_u.dn_u.fwmark ^ fl2->nl_u.dn_u.fwmark) | +#endif + (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) | + (fl1->oif ^ fl2->oif) | + (fl1->iif ^ fl2->iif)) == 0; } static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c41ddba02e9..925ee4dfc32 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -566,9 +566,15 @@ static inline u32 rt_score(struct rtable *rt) static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { - return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 && - fl1->oif == fl2->oif && - fl1->iif == fl2->iif; + 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) | +#ifdef CONFIG_IP_ROUTE_FWMARK + (fl1->nl_u.ip4_u.fwmark ^ fl2->nl_u.ip4_u.fwmark) | +#endif + (*(u16 *)&fl1->nl_u.ip4_u.tos ^ + *(u16 *)&fl2->nl_u.ip4_u.tos) | + (fl1->oif ^ fl2->oif) | + (fl1->iif ^ fl2->iif)) == 0; } #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED -- GitLab From 52c41a3224666d252d34597b580f1b6d4dc440e7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 01:48:20 -0700 Subject: [PATCH 1125/1619] [DECNET]: Fix sfuzz hanging on 2.6.18 Dave Jones wrote: > sfuzz D 724EF62A 2828 28717 28691 (NOTLB) > cd69fe98 00000082 0000012d 724ef62a 0001971a 00000010 00000007 df6d22b0 > dfd81080 725bbc5e 0001971a 000cc634 00000001 df6d23bc c140e260 00000202 > de1d5ba0 cd69fea0 de1d5ba0 00000000 00000000 de1d5b60 de1d5b8c de1d5ba0 > Call Trace: > [] lock_sock+0x75/0xa6 > [] dn_getname+0x18/0x5f [decnet] > [] sys_getsockname+0x5c/0xb0 > [] sys_socketcall+0xef/0x261 > [] syscall_call+0x7/0xb > DWARF2 unwinder stuck at syscall_call+0x7/0xb > > I wonder if the plethora of lockdep related changes inadvertantly broke something? Looks like unbalanced locking. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/decnet/af_decnet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 70e02737568..3456cd33183 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1178,8 +1178,10 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len if (peer) { if ((sock->state != SS_CONNECTED && sock->state != SS_CONNECTING) && - scp->accept_mode == ACC_IMMED) + scp->accept_mode == ACC_IMMED) { + release_sock(sk); return -ENOTCONN; + } memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn)); } else { -- GitLab From b974179abef7cd680b80bd7c7042802bdd6f0eb6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 01:50:30 -0700 Subject: [PATCH 1126/1619] [RTNETLINK]: Fix use of wrong skb in do_getlink() skb is the netlink query, nskb is the reply message. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 221e4038216..02f3c794789 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -602,7 +602,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) goto errout; } - err = rtnl_unicast(skb, NETLINK_CB(skb).pid); + err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); errout: kfree(iw_buf); dev_put(dev); -- GitLab From 30bdbe397bf58131a91fd836f60972442bed0544 Mon Sep 17 00:00:00 2001 From: Akinbou Mita Date: Thu, 12 Oct 2006 01:52:05 -0700 Subject: [PATCH 1127/1619] [PKT_SCHED] sch_htb: use rb_first() cleanup Use rb_first() to get first entry in rb tree. Signed-off-by: Akinbou Mita Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index bb3ddd4784b..9b9c555c713 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -786,11 +786,10 @@ static long htb_do_events(struct htb_sched *q, int level) for (i = 0; i < 500; i++) { struct htb_class *cl; long diff; - struct rb_node *p = q->wait_pq[level].rb_node; + struct rb_node *p = rb_first(&q->wait_pq[level]); + if (!p) return 0; - while (p->rb_left) - p = p->rb_left; cl = rb_entry(p, struct htb_class, pq_node); if (time_after(cl->pq_key, q->jiffies)) { -- GitLab From 2b1191af683d16a899c2b81b87b605841ceffdec Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Oct 2006 13:04:35 +0200 Subject: [PATCH 1128/1619] [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(-) diff --git a/include/linux/elevator.h b/include/linux/elevator.h index b3370ef5164..2fa9f114422 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; -- GitLab From a22b169df1b9f259391cf3b8ad8bfeea3d7be3f1 Mon Sep 17 00:00:00 2001 From: Vasily Tarasov Date: Wed, 11 Oct 2006 09:24:27 +0200 Subject: [PATCH 1129/1619] [PATCH] block layer: elevator_find function cleanup We can easily produce search through the elevator list without introducing additional elevator_type variable. Signed-off-by: Vasily Tarasov Signed-off-by: Jens Axboe --- block/elevator.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index 487dd3da885..d8030a84773 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -93,21 +93,18 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio) static struct elevator_type *elevator_find(const char *name) { - struct elevator_type *e = NULL; + struct elevator_type *e; struct list_head *entry; list_for_each(entry, &elv_list) { - struct elevator_type *__e; - __e = list_entry(entry, struct elevator_type, list); + e = list_entry(entry, struct elevator_type, list); - if (!strcmp(__e->elevator_name, name)) { - e = __e; - break; - } + if (!strcmp(e->elevator_name, name)) + return e; } - return e; + return NULL; } static void elevator_put(struct elevator_type *e) -- GitLab From e6e80f294c2688302f41959c57acfee7e131e489 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 11 Oct 2006 10:03:09 +0200 Subject: [PATCH 1130/1619] [PATCH] splice: fix pipe_to_file() ->prepare_write() error path Don't jump to the unlock+release path, we already did that. Signed-off-by: Jens Axboe --- fs/splice.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 13e92dd19fb..a567010b62a 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -607,7 +607,7 @@ find_page: ret = -ENOMEM; page = page_cache_alloc_cold(mapping); if (unlikely(!page)) - goto out_nomem; + goto out_ret; /* * This will also lock the page @@ -666,7 +666,7 @@ find_page: if (sd->pos + this_len > isize) vmtruncate(mapping->host, isize); - goto out; + goto out_ret; } if (buf->page != page) { @@ -698,7 +698,7 @@ find_page: out: page_cache_release(page); unlock_page(page); -out_nomem: +out_ret: return ret; } -- GitLab From c5841642242e9ae817275e09b36b298456dc17d2 Mon Sep 17 00:00:00 2001 From: Vasily Tarasov Date: Wed, 11 Oct 2006 13:26:30 +0200 Subject: [PATCH 1131/1619] [PATCH] block layer: elv_iosched_show should get elv_list_lock elv_iosched_show function iterates other elv_list, hence elv_list_lock should be got. Signed-off-by: Vasily Tarasov Signed-off-by: Vasily Tarasov --- block/elevator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index d8030a84773..8ccd163254b 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -1085,7 +1085,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) struct list_head *entry; int len = 0; - spin_lock_irq(q->queue_lock); + spin_lock_irq(&elv_list_lock); list_for_each(entry, &elv_list) { struct elevator_type *__e; @@ -1095,7 +1095,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) else len += sprintf(name+len, "%s ", __e->elevator_name); } - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(&elv_list_lock); len += sprintf(len+name, "\n"); return len; -- GitLab From cea2885a2e989d1dc19af1fc991717b33b7d1456 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 12 Oct 2006 15:08:45 +0200 Subject: [PATCH 1132/1619] [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(-) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 69bbb6206a0..e7513e55ace 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 26f7856ff81..d370d2cfe13 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, }; /* -- GitLab From d58cdfb89ce0c6bd5f81ae931a984ef298dbda20 Mon Sep 17 00:00:00 2001 From: Vasily Tarasov Date: Thu, 12 Oct 2006 15:09:51 +0200 Subject: [PATCH 1133/1619] [PATCH] block layer: ioprio_best function fix Currently ioprio_best function first checks wethere aioprio or bioprio equals IOPRIO_CLASS_NONE (ioprio_valid() macros does that) and if it is so it returns bioprio/aioprio appropriately. Thus the next four lines, that set aclass/bclass to IOPRIO_CLASS_BE, if aclass/bclass == IOPRIO_CLASS_NONE, are never executed. The second problem: if aioprio from class IOPRIO_CLASS_NONE and bioprio from class IOPRIO_CLASS_IDLE are passed to ioprio_best function, it will return IOPRIO_CLASS_IDLE. It means that during __make_request we can merge two requests and set the priority of merged request to IDLE, while one of the initial requests originates from a process with NONE (default) priority. So we can get a situation when a process with default ioprio will experience IO starvation, while there is no process from real-time class in the system. Just removing ioprio_valid check should correct situation. Signed-off-by: Vasily Tarasov Signed-off-by: Jens Axboe --- fs/ioprio.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/ioprio.c b/fs/ioprio.c index 6dc6721d9e8..89e8da112a7 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -150,11 +150,6 @@ int ioprio_best(unsigned short aprio, unsigned short bprio) unsigned short aclass = IOPRIO_PRIO_CLASS(aprio); unsigned short bclass = IOPRIO_PRIO_CLASS(bprio); - if (!ioprio_valid(aprio)) - return bprio; - if (!ioprio_valid(bprio)) - return aprio; - if (aclass == IOPRIO_CLASS_NONE) aclass = IOPRIO_CLASS_BE; if (bclass == IOPRIO_CLASS_NONE) -- GitLab From 994bd4f9f5a065ead4a92435fdd928ac7fd33809 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 11 Oct 2006 22:44:46 -0600 Subject: [PATCH 1134/1619] [PATCH] x86_64 irq: Properly update vector_irq This patch fixes my one line thinko where I was clearing the vector_irq entries on the wrong cpus. Signed-off-by: Eric W. Biederman Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/io_apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index c3cdcab2968..44b55f83387 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -660,7 +660,7 @@ next: } if (old_vector >= 0) { int old_cpu; - for_each_cpu_mask(old_cpu, domain) + for_each_cpu_mask(old_cpu, irq_domain[irq]) per_cpu(vector_irq, old_cpu)[old_vector] = -1; } for_each_cpu_mask(new_cpu, domain) -- GitLab From 230a03950ecd63bc613c6adeffbe9049189d9f05 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 12 Oct 2006 15:07:55 +0000 Subject: [PATCH 1135/1619] [CIFS] cifs Kconfig: don't select CONNECTOR `select' is a bit obnoxious: the option keeps on coming back and it's hard to work out what to do to make it go away again. The use of `depends on' is preferred (although it has usability problems too..) Signed-off-by: Andrew Morton Signed-off-by: Steve French --- fs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/Kconfig b/fs/Kconfig index 53058162831..6865a33544d 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1827,7 +1827,7 @@ config CIFS_EXPERIMENTAL config CIFS_UPCALL bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" depends on CIFS_EXPERIMENTAL - select CONNECTOR + depends on CONNECTOR help Enables an upcall mechanism for CIFS which will be used to contact userspace helper utilities to provide SPNEGO packaged Kerberos -- GitLab From 8770c018da7bbaa3b41371abc401b2aa7e76a71a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 12 Oct 2006 17:24:52 +0200 Subject: [PATCH 1136/1619] [PATCH] ide-cd: one more missing REQ_TYPE_CMD_ATA check Signed-off-by: Jens Axboe --- drivers/ide/ide-cd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index e7513e55ace..bddfebdf91d 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -716,7 +716,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) ide_error(drive, "request sense failure", stat); return 1; - } else if (blk_pc_request(rq)) { + } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { /* All other functions, except for READ. */ unsigned long flags; -- GitLab From d103e164bee2f21d0efe7d713cbbb0a443ba480d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 17:49:24 +0000 Subject: [PATCH 1137/1619] [CIFS] Workaround incomplete byte length returned by some servers on small SMB responses Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 2 +- fs/cifs/misc.c | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4a4fd2dbca6..f1f8225102f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -55,7 +55,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , int * /* bytes returned */); -extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); +extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_size_safe_to_change(struct cifsInodeInfo *); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index ca6e9b1413f..bbc9cd34b6e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) } int -checkSMB(struct smb_hdr *smb, __u16 mid, int length) +checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) { __u32 len = smb->smb_buf_length; __u32 clc_len; /* calculated length */ cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); - if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || - (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { - if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { - if (((unsigned int)length >= - sizeof (struct smb_hdr) - 1) + + if (length < 2 + sizeof (struct smb_hdr)) { + if ((length >= sizeof (struct smb_hdr) - 1) && (smb->Status.CifsError != 0)) { - smb->WordCount = 0; - /* some error cases do not return wct and bcc */ + smb->WordCount = 0; + /* some error cases do not return wct and bcc */ + return 0; + } else if ((length == sizeof(struct smb_hdr) + 1) && + (smb->WordCount == 0)) { + char * tmp = (char *)smb; + /* Need to work around a bug in two servers here */ + /* First, check if the part of bcc they sent was zero */ + if (tmp[sizeof(struct smb_hdr)] == 0) { + /* some servers return only half of bcc + * on simple responses (wct, bcc both zero) + * in particular have seen this on + * ulogoffX and FindClose. This leaves + * one byte of bcc potentially unitialized + */ + /* zero rest of bcc */ + tmp[sizeof(struct smb_hdr)+1] = 0; return 0; - } else { - cERROR(1, ("Length less than smb header size")); } + cERROR(1,("rcvd invalid byte count (bcc)")); + } else { + cERROR(1, ("Length less than smb header size")); } - if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) - cERROR(1, ("smb length greater than MaxBufSize, mid=%d", + return 1; + } + if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + cERROR(1, ("smb length greater than MaxBufSize, mid=%d", smb->Mid)); return 1; } @@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) return 1; clc_len = smbCalcSize_LE(smb); - if(4 + len != (unsigned int)length) { + if(4 + len != length) { cERROR(1, ("Length read does not match RFC1001 length %d",len)); return 1; } -- GitLab From 78b93f2db11df75ada5d04962ba631940b0a1398 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 12 Oct 2006 19:00:35 +0100 Subject: [PATCH 1138/1619] [PATCH] fixing includes in alpha_ksyms.c kernel_execve() fallout Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/alpha_ksyms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 692809e4aec..e9762a33b04 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -12,7 +12,7 @@ #include #include -#include +#include /* these are C runtime functions with special calling conventions: */ extern void __divl (void); -- GitLab From 734c4c67393893f61b39bcdfe1e94f72111c56d6 Mon Sep 17 00:00:00 2001 From: Ravikiran Thirumalai Date: Thu, 12 Oct 2006 12:17:52 -0700 Subject: [PATCH 1139/1619] [PATCH] Fix build breakage with CONFIG_X86_VSMP Kernel build breaks with CONFIG_X86_VSMP. Probably due to some header file cleanups in 2.6.19-rc1. Signed-off-by: Ravikiran Thirumalai Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/vsmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/kernel/vsmp.c b/arch/x86_64/kernel/vsmp.c index 044e852bd25..414caf0c5f9 100644 --- a/arch/x86_64/kernel/vsmp.c +++ b/arch/x86_64/kernel/vsmp.c @@ -14,6 +14,7 @@ #include #include #include +#include static int __init vsmp_init(void) { -- GitLab From 1baaf0b424fe611a99cf3e2e59e84df0561d679a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 12 Oct 2006 19:07:59 +0100 Subject: [PATCH 1140/1619] [PATCH] more kernel_execve() fallout (sbus) drivers/sbus/char stuff using kernel_execve() needs linux/syscalls.h now; includes trimmed, while we are at it. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/sbus/char/bbc_envctrl.c | 4 +--- drivers/sbus/char/envctrl.c | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index d27e4f6d704..0d3660c28f7 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -4,10 +4,8 @@ * Copyright (C) 2001 David S. Miller (davem@redhat.com) */ -#include #include -#include -#include +#include #include #include #include diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 728a133d0fc..6b6a855f379 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -20,16 +20,12 @@ */ #include -#include +#include #include -#include #include #include -#include #include -#include -#include -#include +#include #include #include -- GitLab From 52ae7b7935a079aaba25da98fe90772d04109f26 Mon Sep 17 00:00:00 2001 From: Russell Cattelan Date: Mon, 9 Oct 2006 12:11:54 -0500 Subject: [PATCH 1141/1619] [GFS2] Fix a size calculation error Fix a size calculation error. The size was incorrect being computed as a negative length and then being passed to an unsigned parameter. This in turn would cause the allocator to think it needed enough meta data to store a gigabyte file for every file created. Signed-off-by: Russell Cattelan Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 4fb743f4e4a..bdf56cf6622 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -370,15 +370,17 @@ static int gfs2_prepare_write(struct file *file, struct page *page, 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; + unsigned int write_len = to - from; + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|GL_AOP, &ip->i_gh); error = gfs2_glock_nq_m_atime(1, &ip->i_gh); if (error) goto out_uninit; - gfs2_write_calc_reserv(ip, to - from, &data_blocks, &ind_blocks); + gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks); - error = gfs2_write_alloc_required(ip, pos, from - to, &alloc_required); + error = gfs2_write_alloc_required(ip, pos, write_len, &alloc_required); if (error) goto out_unlock; -- GitLab From f5c54804d9e3bb23d8924af09d9ca1c8de9560b6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 10 Oct 2006 13:45:15 -0400 Subject: [PATCH 1142/1619] [GFS2] Fix uninitialised variable This fixes a bug where, in certain cases an uninitialised variable could cause a dereference of a NULL pointer in gfs2_commit_write(). Also a typo in a comment is fixed at the same time. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 1 + fs/gfs2/rgrp.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index bdf56cf6622..99c933762eb 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -385,6 +385,7 @@ static int gfs2_prepare_write(struct file *file, struct page *page, goto out_unlock; + ip->i_alloc.al_requested = 0; if (alloc_required) { al = gfs2_alloc_get(ip); diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 9eedfd12bff..b01e0cfc99b 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -32,7 +32,7 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd); struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); static inline void gfs2_alloc_put(struct gfs2_inode *ip) { - return; /* Se we can see where ip->i_alloc is used */ + return; /* So we can see where ip->i_alloc is used */ } int gfs2_inplace_reserve_i(struct gfs2_inode *ip, -- GitLab From 1ee48af22ed6dcddea8cdf93c7f2a268cbcf0d56 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Oct 2006 04:30:48 +0200 Subject: [PATCH 1143/1619] [DLM] Kconfig: don't show an empty DLM menu Don't show an empty "Distributed Lock Manager" menu if IP_SCTP=n. Reported by Dmytro Bagrii in kernel Bugzilla #7268. Signed-off-by: Adrian Bunk Signed-off-by: David Teigland Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig index 490f85b3fa5..81b2c6465ee 100644 --- a/fs/dlm/Kconfig +++ b/fs/dlm/Kconfig @@ -1,10 +1,9 @@ menu "Distributed Lock Manager" - depends on INET && EXPERIMENTAL + depends on INET && IP_SCTP && EXPERIMENTAL config DLM tristate "Distributed Lock Manager (DLM)" depends on IPV6 || IPV6=n - depends on IP_SCTP select CONFIGFS_FS help A general purpose distributed lock manager for kernel or userspace -- GitLab From fe1a698ffef5af546dd4a8cd6a1f2f202491c4ef Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 11 Oct 2006 13:34:59 -0400 Subject: [PATCH 1144/1619] [GFS2] Fix bug where lock not held The log lock needs to be held when manipulating the counter for the number of free journal blocks. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 554fe5bd1b7..72eec6542d6 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -569,16 +569,15 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) 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; + gfs2_log_lock(sdp); + sdp->sd_log_head = sdp->sd_log_flush_head; sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs; - sdp->sd_log_blks_reserved = 0; sdp->sd_log_commited_buf = 0; sdp->sd_log_num_hdrs = 0; 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; -- GitLab From c312c4fdc88514dd9522b7858eb879e610aeb9b1 Mon Sep 17 00:00:00 2001 From: Russell Cattelan Date: Thu, 12 Oct 2006 09:23:41 -0400 Subject: [PATCH 1145/1619] [GFS2] Pass the correct value to kunmap_atomic Pass kaddr rather than (incorrect) struct page to kunmap_atomic. Signed-off-by: Russell Cattelan Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 4 ++-- fs/gfs2/ops_address.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 881e337b6a7..ab6d1115f95 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -492,7 +492,7 @@ static int gfs2_check_magic(struct buffer_head *bh) ptr = kaddr + bh_offset(bh); if (*ptr == cpu_to_be32(GFS2_MAGIC)) rv = 1; - kunmap_atomic(page, KM_USER0); + kunmap_atomic(kaddr, KM_USER0); return rv; } @@ -626,7 +626,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) memcpy(bh->b_data, kaddr + bh_offset(bd2->bd_bh), sdp->sd_sb.sb_bsize); - kunmap_atomic(page, KM_USER0); + kunmap_atomic(kaddr, KM_USER0); *(__be32 *)bh->b_data = 0; } else { bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 99c933762eb..e0599fed99c 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -162,7 +162,7 @@ static int zero_readpage(struct page *page) kaddr = kmap_atomic(page, KM_USER0); memset(kaddr, 0, PAGE_CACHE_SIZE); - kunmap_atomic(page, KM_USER0); + kunmap_atomic(kaddr, KM_USER0); SetPageUptodate(page); @@ -195,7 +195,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *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_atomic(page, KM_USER0); + kunmap_atomic(kaddr, KM_USER0); brelse(dibh); @@ -485,7 +485,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, kaddr = kmap_atomic(page, KM_USER0); memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, kaddr + from, to - from); - kunmap_atomic(page, KM_USER0); + kunmap_atomic(kaddr, KM_USER0); SetPageUptodate(page); -- GitLab From 4c5e1b1a8c3f591b21f09001d6748296ddff33b8 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Thu, 12 Oct 2006 10:41:22 +0100 Subject: [PATCH 1146/1619] [DLM] fix iovec length in recvmsg The DLM always passes the iovec length as 1, this is wrong when the circular buffer wraps round. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 7bcea7c5add..867f93d0417 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -548,7 +548,7 @@ static int receive_from_sock(void) } len = iov[0].iov_len + iov[1].iov_len; - r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, 1, len, + r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, msg.msg_iovlen, len, MSG_NOSIGNAL | MSG_DONTWAIT); if (ret <= 0) goto out_close; -- GitLab From 370298e2e6f513bc4a9e9445eeed060d8c31f1ca Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 12 Oct 2006 15:40:05 -0400 Subject: [PATCH 1147/1619] [GFS2] Update git tree name/location The plan is to have two trees. One for bug fixes to be sent on a regular basis (-fixes) and another called -nmw which will contain items queued for the next merge window (hence the name). The -nmw tree will come & go according to need. Signed-off-by: Steven Whitehouse --- MAINTAINERS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 931e6e40c08..1b5430a49fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -905,7 +905,8 @@ P: David Teigland M: teigland@redhat.com L: cluster-devel@redhat.com W: http://sources.redhat.com/cluster/ -T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git +T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git +T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git S: Supported DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER @@ -1188,7 +1189,8 @@ P: Steven Whitehouse M: swhiteho@redhat.com L: cluster-devel@redhat.com W: http://sources.redhat.com/cluster/ -T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git +T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git +T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git S: Supported GIGASET ISDN DRIVERS -- GitLab From 1a4e15a04ec69cb3552f4120079f5472377df5f7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 21:33:51 +0000 Subject: [PATCH 1148/1619] [CIFS] Missing flags2 for DFS Partly suggested by Igor Mammedov Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 8 ++++++++ fs/cifs/connect.c | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6f50f2bc887..5dc5a966bd5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3675,6 +3675,14 @@ getDFSRetry: strncpy(pSMB->RequestFileName, searchName, name_len); } + if(ses->server) { + if(ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + } + + pSMB->hdr.Uid = ses->Suid; + params = 2 /* level */ + name_len /*includes null */ ; pSMB->TotalDataCount = 0; pSMB->DataCount = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c96f3edf1b9..1d17691086c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3219,7 +3219,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, } /* else do not bother copying these informational fields */ } - if(smb_buffer_response->WordCount == 3) + if((smb_buffer_response->WordCount == 3) || + (smb_buffer_response->WordCount == 7)) + /* field is in same location */ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); else tcon->Flags = 0; -- GitLab From c771746ef6ad64357897a90da42908d5c800a2c5 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 12 Oct 2006 22:21:16 -0500 Subject: [PATCH 1149/1619] [VOYAGER] fix genirq mess The implementation of genirq in x86 completely broke voyager (and presumably visws). Since it's plugged into so much of the x86 infrastructure, you can't expect it to work unconverted. This patch introduces a voyager IRQ handler type and switches voyager to the genirq infrastructure. Signed-off-by: James Bottomley --- arch/i386/mach-voyager/voyager_smp.c | 42 +++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index d42422fc4af..2e73f353f16 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -85,8 +85,8 @@ static int ack_QIC_CPI(__u8 cpi); static void ack_special_QIC_CPI(__u8 cpi); static void ack_VIC_CPI(__u8 cpi); static void send_CPI_allbutself(__u8 cpi); -static void enable_vic_irq(unsigned int irq); -static void disable_vic_irq(unsigned int irq); +static void mask_vic_irq(unsigned int irq); +static void unmask_vic_irq(unsigned int irq); static unsigned int startup_vic_irq(unsigned int irq); static void enable_local_vic_irq(unsigned int irq); static void disable_local_vic_irq(unsigned int irq); @@ -205,15 +205,12 @@ ack_CPI(__u8 cpi) /* The VIC IRQ descriptors -- these look almost identical to the * 8259 IRQs except that masks and things must be kept per processor */ -static struct hw_interrupt_type vic_irq_type = { - .typename = "VIC-level", - .startup = startup_vic_irq, - .shutdown = disable_vic_irq, - .enable = enable_vic_irq, - .disable = disable_vic_irq, - .ack = before_handle_vic_irq, - .end = after_handle_vic_irq, - .set_affinity = set_vic_irq_affinity, +static struct irq_chip vic_chip = { + .name = "VIC", + .startup = startup_vic_irq, + .mask = mask_vic_irq, + .unmask = unmask_vic_irq, + .set_affinity = set_vic_irq_affinity, }; /* used to count up as CPUs are brought on line (starts at 0) */ @@ -1397,6 +1394,17 @@ setup_profiling_timer(unsigned int multiplier) return 0; } +/* This is a bit of a mess, but forced on us by the genirq changes + * there's no genirq handler that really does what voyager wants + * so hack it up with the simple IRQ handler */ +static void fastcall +handle_vic_irq(unsigned int irq, struct irq_desc *desc) +{ + before_handle_vic_irq(irq); + handle_simple_irq(irq, desc); + after_handle_vic_irq(irq); +} + /* The CPIs are handled in the per cpu 8259s, so they must be * enabled to be received: FIX: enabling the CPIs in the early @@ -1433,7 +1441,7 @@ smp_intr_init(void) * This is for later: first 16 correspond to PC IRQs; next 16 * are Primary MC IRQs and final 16 are Secondary MC IRQs */ for(i = 0; i < 48; i++) - irq_desc[i].chip = &vic_irq_type; + set_irq_chip_and_handler(i, &vic_chip, handle_vic_irq); } /* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per @@ -1531,7 +1539,7 @@ ack_VIC_CPI(__u8 cpi) static unsigned int startup_vic_irq(unsigned int irq) { - enable_vic_irq(irq); + unmask_vic_irq(irq); return 0; } @@ -1558,7 +1566,7 @@ startup_vic_irq(unsigned int irq) * adjust their masks accordingly. */ static void -enable_vic_irq(unsigned int irq) +unmask_vic_irq(unsigned int irq) { /* linux doesn't to processor-irq affinity, so enable on * all CPUs we know about */ @@ -1567,7 +1575,7 @@ enable_vic_irq(unsigned int irq) __u32 processorList = 0; unsigned long flags; - VDEBUG(("VOYAGER: enable_vic_irq(%d) CPU%d affinity 0x%lx\n", + VDEBUG(("VOYAGER: unmask_vic_irq(%d) CPU%d affinity 0x%lx\n", irq, cpu, cpu_irq_affinity[cpu])); spin_lock_irqsave(&vic_irq_lock, flags); for_each_online_cpu(real_cpu) { @@ -1591,7 +1599,7 @@ enable_vic_irq(unsigned int irq) } static void -disable_vic_irq(unsigned int irq) +mask_vic_irq(unsigned int irq) { /* lazy disable, do nothing */ } @@ -1819,7 +1827,7 @@ set_vic_irq_affinity(unsigned int irq, cpumask_t mask) * disabled again as it comes in (voyager lazy disable). If * the affinity map is tightened to disable the interrupt on a * cpu, it will be pushed off when it comes in */ - enable_vic_irq(irq); + unmask_vic_irq(irq); } static void -- GitLab From 58f07943b0ef1e59cbf9a45cdc727048d224637f Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 12 Oct 2006 22:23:18 -0500 Subject: [PATCH 1150/1619] [VOYAGER] fix up attribute packed specifiers in voyager.h The old style (attribute on each structure entry) never really worked. Move it to an attribute per structure Signed-off-by: James Bottomley --- include/asm-i386/voyager.h | 160 ++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h index e74c54aa757..5b27838905b 100644 --- a/include/asm-i386/voyager.h +++ b/include/asm-i386/voyager.h @@ -118,33 +118,33 @@ typedef struct voyager_module { } voyager_module_t; typedef struct voyager_eeprom_hdr { - __u8 module_id[4] __attribute__((packed)); - __u8 version_id __attribute__((packed)); - __u8 config_id __attribute__((packed)); - __u16 boundry_id __attribute__((packed)); /* boundary scan id */ - __u16 ee_size __attribute__((packed)); /* size of EEPROM */ - __u8 assembly[11] __attribute__((packed)); /* assembly # */ - __u8 assembly_rev __attribute__((packed)); /* assembly rev */ - __u8 tracer[4] __attribute__((packed)); /* tracer number */ - __u16 assembly_cksum __attribute__((packed)); /* asm checksum */ - __u16 power_consump __attribute__((packed)); /* pwr requirements */ - __u16 num_asics __attribute__((packed)); /* number of asics */ - __u16 bist_time __attribute__((packed)); /* min. bist time */ - __u16 err_log_offset __attribute__((packed)); /* error log offset */ - __u16 scan_path_offset __attribute__((packed));/* scan path offset */ - __u16 cct_offset __attribute__((packed)); - __u16 log_length __attribute__((packed)); /* length of err log */ - __u16 xsum_end __attribute__((packed)); /* offset to end of + __u8 module_id[4]; + __u8 version_id; + __u8 config_id; + __u16 boundry_id; /* boundary scan id */ + __u16 ee_size; /* size of EEPROM */ + __u8 assembly[11]; /* assembly # */ + __u8 assembly_rev; /* assembly rev */ + __u8 tracer[4]; /* tracer number */ + __u16 assembly_cksum; /* asm checksum */ + __u16 power_consump; /* pwr requirements */ + __u16 num_asics; /* number of asics */ + __u16 bist_time; /* min. bist time */ + __u16 err_log_offset; /* error log offset */ + __u16 scan_path_offset;/* scan path offset */ + __u16 cct_offset; + __u16 log_length; /* length of err log */ + __u16 xsum_end; /* offset to end of checksum */ - __u8 reserved[4] __attribute__((packed)); - __u8 sflag __attribute__((packed)); /* starting sentinal */ - __u8 part_number[13] __attribute__((packed)); /* prom part number */ - __u8 version[10] __attribute__((packed)); /* version number */ - __u8 signature[8] __attribute__((packed)); - __u16 eeprom_chksum __attribute__((packed)); - __u32 data_stamp_offset __attribute__((packed)); - __u8 eflag __attribute__((packed)); /* ending sentinal */ -} voyager_eprom_hdr_t; + __u8 reserved[4]; + __u8 sflag; /* starting sentinal */ + __u8 part_number[13]; /* prom part number */ + __u8 version[10]; /* version number */ + __u8 signature[8]; + __u16 eeprom_chksum; + __u32 data_stamp_offset; + __u8 eflag ; /* ending sentinal */ +} __attribute__((packed)) voyager_eprom_hdr_t; @@ -155,30 +155,30 @@ typedef struct voyager_eeprom_hdr { * in the module EPROMs. We really only care about the IDs and * offsets */ typedef struct voyager_sp_table { - __u8 asic_id __attribute__((packed)); - __u8 bypass_flag __attribute__((packed)); - __u16 asic_data_offset __attribute__((packed)); - __u16 config_data_offset __attribute__((packed)); -} voyager_sp_table_t; + __u8 asic_id; + __u8 bypass_flag; + __u16 asic_data_offset; + __u16 config_data_offset; +} __attribute__((packed)) voyager_sp_table_t; typedef struct voyager_jtag_table { - __u8 icode[4] __attribute__((packed)); - __u8 runbist[4] __attribute__((packed)); - __u8 intest[4] __attribute__((packed)); - __u8 samp_preld[4] __attribute__((packed)); - __u8 ireg_len __attribute__((packed)); -} voyager_jtt_t; + __u8 icode[4]; + __u8 runbist[4]; + __u8 intest[4]; + __u8 samp_preld[4]; + __u8 ireg_len; +} __attribute__((packed)) voyager_jtt_t; typedef struct voyager_asic_data_table { - __u8 jtag_id[4] __attribute__((packed)); - __u16 length_bsr __attribute__((packed)); - __u16 length_bist_reg __attribute__((packed)); - __u32 bist_clk __attribute__((packed)); - __u16 subaddr_bits __attribute__((packed)); - __u16 seed_bits __attribute__((packed)); - __u16 sig_bits __attribute__((packed)); - __u16 jtag_offset __attribute__((packed)); -} voyager_at_t; + __u8 jtag_id[4]; + __u16 length_bsr; + __u16 length_bist_reg; + __u32 bist_clk; + __u16 subaddr_bits; + __u16 seed_bits; + __u16 sig_bits; + __u16 jtag_offset; +} __attribute__((packed)) voyager_at_t; /* Voyager Interrupt Controller (VIC) registers */ @@ -328,52 +328,52 @@ struct voyager_bios_info { #define NUMBER_OF_POS_REGS 8 typedef struct { - __u8 MC_Slot __attribute__((packed)); - __u8 POS_Values[NUMBER_OF_POS_REGS] __attribute__((packed)); -} MC_SlotInformation_t; + __u8 MC_Slot; + __u8 POS_Values[NUMBER_OF_POS_REGS]; +} __attribute__((packed)) MC_SlotInformation_t; struct QuadDescription { - __u8 Type __attribute__((packed)); /* for type 0 (DYADIC or MONADIC) all fields + __u8 Type; /* for type 0 (DYADIC or MONADIC) all fields * will be zero except for slot */ - __u8 StructureVersion __attribute__((packed)); - __u32 CPI_BaseAddress __attribute__((packed)); - __u32 LARC_BankSize __attribute__((packed)); - __u32 LocalMemoryStateBits __attribute__((packed)); - __u8 Slot __attribute__((packed)); /* Processor slots 1 - 4 */ -}; + __u8 StructureVersion; + __u32 CPI_BaseAddress; + __u32 LARC_BankSize; + __u32 LocalMemoryStateBits; + __u8 Slot; /* Processor slots 1 - 4 */ +} __attribute__((packed)); struct ProcBoardInfo { - __u8 Type __attribute__((packed)); - __u8 StructureVersion __attribute__((packed)); - __u8 NumberOfBoards __attribute__((packed)); - struct QuadDescription QuadData[MAX_PROCESSOR_BOARDS] __attribute__((packed)); -}; + __u8 Type; + __u8 StructureVersion; + __u8 NumberOfBoards; + struct QuadDescription QuadData[MAX_PROCESSOR_BOARDS]; +} __attribute__((packed)); struct CacheDescription { - __u8 Level __attribute__((packed)); - __u32 TotalSize __attribute__((packed)); - __u16 LineSize __attribute__((packed)); - __u8 Associativity __attribute__((packed)); - __u8 CacheType __attribute__((packed)); - __u8 WriteType __attribute__((packed)); - __u8 Number_CPUs_SharedBy __attribute__((packed)); - __u8 Shared_CPUs_Hardware_IDs[MAX_SHARED_CPUS] __attribute__((packed)); + __u8 Level; + __u32 TotalSize; + __u16 LineSize; + __u8 Associativity; + __u8 CacheType; + __u8 WriteType; + __u8 Number_CPUs_SharedBy; + __u8 Shared_CPUs_Hardware_IDs[MAX_SHARED_CPUS]; -}; +} __attribute__((packed)); struct CPU_Description { - __u8 CPU_HardwareId __attribute__((packed)); - char *FRU_String __attribute__((packed)); - __u8 NumberOfCacheLevels __attribute__((packed)); - struct CacheDescription CacheLevelData[MAX_CACHE_LEVELS] __attribute__((packed)); -}; + __u8 CPU_HardwareId; + char *FRU_String; + __u8 NumberOfCacheLevels; + struct CacheDescription CacheLevelData[MAX_CACHE_LEVELS]; +} __attribute__((packed)); struct CPU_Info { - __u8 Type __attribute__((packed)); - __u8 StructureVersion __attribute__((packed)); - __u8 NumberOf_CPUs __attribute__((packed)); - struct CPU_Description CPU_Data[MAX_CPUS] __attribute__((packed)); -}; + __u8 Type; + __u8 StructureVersion; + __u8 NumberOf_CPUs; + struct CPU_Description CPU_Data[MAX_CPUS]; +} __attribute__((packed)); /* -- GitLab From 81c06b10bcd4c7e8c88b4b425c55402b1d65fd0e Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 12 Oct 2006 22:25:03 -0500 Subject: [PATCH 1151/1619] [VOYAGER] fix up ptregs removal mess Apparently whoever converted voyager never actually checked that the patch would compile ... Remove as much of the pt_regs references as possible and move the remaining ones into line with what's in x86 generic. Signed-off-by: James Bottomley --- arch/i386/mach-voyager/voyager_basic.c | 6 +++--- arch/i386/mach-voyager/voyager_smp.c | 10 ++++------ include/asm-i386/vic.h | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c index c639d30d8bd..8fe7e4593d5 100644 --- a/arch/i386/mach-voyager/voyager_basic.c +++ b/arch/i386/mach-voyager/voyager_basic.c @@ -44,7 +44,7 @@ struct voyager_SUS *voyager_SUS = NULL; #ifdef CONFIG_SMP static void -voyager_dump(int dummy1, struct pt_regs *dummy2, struct tty_struct *dummy3) +voyager_dump(int dummy1, struct tty_struct *dummy3) { /* get here via a sysrq */ voyager_smp_dump(); @@ -166,7 +166,7 @@ voyager_memory_detect(int region, __u32 *start, __u32 *length) * off the timer tick to the SMP code, since the VIC doesn't have an * internal timer (The QIC does, but that's another story). */ void -voyager_timer_interrupt(struct pt_regs *regs) +voyager_timer_interrupt(void) { if((jiffies & 0x3ff) == 0) { @@ -202,7 +202,7 @@ voyager_timer_interrupt(struct pt_regs *regs) } } #ifdef CONFIG_SMP - smp_vic_timer_interrupt(regs); + smp_vic_timer_interrupt(); #endif } diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index 2e73f353f16..f3fea2ad50f 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -1141,9 +1141,9 @@ smp_apic_timer_interrupt(struct pt_regs *regs) fastcall void smp_qic_timer_interrupt(struct pt_regs *regs) { - ack_QIC_CPI(QIC_TIMER_CPI); struct pt_regs *old_regs = set_irq_regs(regs); - wrapper_smp_local_timer_interrupt(void); + ack_QIC_CPI(QIC_TIMER_CPI); + wrapper_smp_local_timer_interrupt(); set_irq_regs(old_regs); } @@ -1267,12 +1267,10 @@ smp_send_stop(void) /* this function is triggered in time.c when a clock tick fires * we need to re-broadcast the tick to all CPUs */ void -smp_vic_timer_interrupt(struct pt_regs *regs) +smp_vic_timer_interrupt(void) { - struct pt_regs *old_regs = set_irq_regs(regs); send_CPI_allbutself(VIC_TIMER_CPI); smp_local_timer_interrupt(); - set_irq_regs(old_regs); } /* local (per CPU) timer interrupt. It does both profiling and @@ -1307,7 +1305,7 @@ smp_local_timer_interrupt(void) per_cpu(prof_counter, cpu); } - update_process_times(user_mode_vm(irq_regs)); + update_process_times(user_mode_vm(get_irq_regs())); } if( ((1< Date: Fri, 13 Oct 2006 04:13:16 +0200 Subject: [PATCH 1152/1619] [PATCH] Get core dump code to work... The file based core dump code was broken by pipe changes - a relative llseek returns the absolute file position on success, not the relative one, so dump_seek() always failed when invoked with non-zero current position. Only success/failure can be tested with relative lseek, we have to trust kernel that on success we've got right file offset. With this fix in place I have finally real core files instead of 1KB fragments... Signed-off-by: Petr Vandrovec [ Cleaned it up a bit while here - use SEEK_CUR instead of hardcoding 1 ] Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 06435f3665f..56100612790 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1152,7 +1152,7 @@ static int dump_write(struct file *file, const void *addr, int nr) static int dump_seek(struct file *file, loff_t off) { if (file->f_op->llseek && file->f_op->llseek != no_llseek) { - if (file->f_op->llseek(file, off, 1) != off) + if (file->f_op->llseek(file, off, SEEK_CUR) < 0) return 0; } else { char *buf = (char *)get_zeroed_page(GFP_KERNEL); -- GitLab From 99a10a60ba9bedcf5d70ef81414d3e03816afa3f Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 12 Oct 2006 21:06:33 +0200 Subject: [PATCH 1153/1619] [PATCH] Fix up mmap_kmem vma->vm_pgoff is an pfn _offset_ relatif to the begining of the memory start. The previous code was doing at first: vma->vm_pgoff << PAGE_SHIFT which results into a wrong physical address since some platforms have a physical mem start that can be different from 0. After that the previous call __pa() on this wrong physical address, however __pa() is used to convert a _virtual_ address into a physical one. This patch rewrites this convertion. It calculates the pfn of PAGE_OFFSET which is the pfn of the mem start then it adds the vma->vm_pgoff to it. It also uses virt_to_phys() instead of __pa() since the latter shouldn't be used by drivers. Signed-off-by: Franck Bui-Huu Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 6511012cbdc..a89cb52228c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -292,8 +292,8 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; - /* Turn a kernel-virtual address into a physical page frame */ - pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; + /* Turn a pfn offset into an absolute pfn */ + pfn = PFN_DOWN(virt_to_phys((void *)PAGE_OFFSET)) + vma->vm_pgoff; /* * RED-PEN: on some architectures there is more mapped memory -- GitLab From 1b95817dd76084c10cb8dc899f429bcc85454741 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 12 Oct 2006 19:10:04 +0100 Subject: [PATCH 1154/1619] [PATCH] uml shouldn't do HEADERS_CHECK The lack of asm-um/Kbuild is deliberate. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- lib/Kconfig.debug | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8fd2dbf7eb5..77491e31179 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -373,6 +373,7 @@ config FORCED_INLINING config HEADERS_CHECK bool "Run 'make headers_check' when building vmlinux" + depends on !UML help This option will extract the user-visible kernel headers whenever building the kernel, and will run basic sanity checks on them to -- GitLab From 6569345abbcdbd1e13915a3bc5033c98817d0ec6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 12 Oct 2006 11:01:30 -0700 Subject: [PATCH 1155/1619] [PATCH] thermal throttle: sysfs error checking Get rid of warning in the thermal throttling code about not checking sysfs return values. Signed-off-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/mcheck/therm_throt.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c index 4f43047de40..2d8703b7ce6 100644 --- a/arch/i386/kernel/cpu/mcheck/therm_throt.c +++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c @@ -110,17 +110,15 @@ int therm_throt_process(int curr) #ifdef CONFIG_SYSFS /* Add/Remove thermal_throttle interface for CPU device */ -static __cpuinit int thermal_throttle_add_dev(struct sys_device * sys_dev) +static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) { - sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group); - return 0; + return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group); } #ifdef CONFIG_HOTPLUG_CPU -static __cpuinit int thermal_throttle_remove_dev(struct sys_device * sys_dev) +static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) { - sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group); - return 0; + return sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group); } /* Mutex protecting device creation against CPU hotplug */ @@ -133,12 +131,14 @@ static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb, { unsigned int cpu = (unsigned long)hcpu; struct sys_device *sys_dev; + int err; sys_dev = get_cpu_sysdev(cpu); mutex_lock(&therm_cpu_lock); switch (action) { case CPU_ONLINE: - thermal_throttle_add_dev(sys_dev); + err = thermal_throttle_add_dev(sys_dev); + WARN_ON(err); break; case CPU_DEAD: thermal_throttle_remove_dev(sys_dev); @@ -157,6 +157,7 @@ static struct notifier_block thermal_throttle_cpu_notifier = static __init int thermal_throttle_init_device(void) { unsigned int cpu = 0; + int err; if (!atomic_read(&therm_throt_en)) return 0; @@ -167,8 +168,10 @@ static __init int thermal_throttle_init_device(void) mutex_lock(&therm_cpu_lock); #endif /* connect live CPUs to sysfs */ - for_each_online_cpu(cpu) - thermal_throttle_add_dev(get_cpu_sysdev(cpu)); + for_each_online_cpu(cpu) { + err = thermal_throttle_add_dev(get_cpu_sysdev(cpu)); + WARN_ON(err); + } #ifdef CONFIG_HOTPLUG_CPU mutex_unlock(&therm_cpu_lock); #endif -- GitLab From e0fafda36a2fc5ecf8d11771f6c01c523b2a1fd8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 Oct 2006 23:18:53 +0200 Subject: [PATCH 1156/1619] [PATCH] m68knommu: sync syscalls with m68k m68knommu: sync syscalls with m68k Signed-Off-By: Geert Uytterhoeven Signed-Off-By: Greg Ungerer Signed-off-by: Linus Torvalds --- arch/m68knommu/kernel/syscalltable.S | 37 +++++++++++++++++++++++++--- include/asm-m68knommu/unistd.h | 35 +++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S index 617e43ec95a..4603f4f3c93 100644 --- a/arch/m68knommu/kernel/syscalltable.S +++ b/arch/m68knommu/kernel/syscalltable.S @@ -296,10 +296,39 @@ ENTRY(sys_call_table) .long sys_mq_notify /* 275 */ .long sys_mq_getsetattr .long sys_waitid - .long sys_ni_syscall /* sys_setaltroot */ - .long sys_ni_syscall /* sys_add_key */ - .long sys_ni_syscall /* 280 */ /* sys_request_key */ - .long sys_ni_syscall /* sys_keyctl */ + .long sys_ni_syscall /* for sys_vserver */ + .long sys_add_key + .long sys_request_key /* 280 */ + .long sys_keyctl + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init + .long sys_inotify_add_watch /* 285 */ + .long sys_inotify_rm_watch + .long sys_migrate_pages + .long sys_openat + .long sys_mkdirat + .long sys_mknodat /* 290 */ + .long sys_fchownat + .long sys_futimesat + .long sys_fstatat64 + .long sys_unlinkat + .long sys_renameat /* 295 */ + .long sys_linkat + .long sys_symlinkat + .long sys_readlinkat + .long sys_fchmodat + .long sys_faccessat /* 300 */ + .long sys_ni_syscall /* Reserved for pselect6 */ + .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_unshare + .long sys_set_robust_list + .long sys_get_robust_list /* 305 */ + .long sys_splice + .long sys_sync_file_range + .long sys_tee + .long sys_vmsplice + .long sys_move_pages /* 310 */ .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h index daafb5d43ef..ebaf0319711 100644 --- a/include/asm-m68knommu/unistd.h +++ b/include/asm-m68knommu/unistd.h @@ -281,14 +281,43 @@ #define __NR_mq_notify 275 #define __NR_mq_getsetattr 276 #define __NR_waitid 277 -#define __NR_sys_setaltroot 278 +#define __NR_vserver 278 #define __NR_add_key 279 #define __NR_request_key 280 #define __NR_keyctl 281 - +#define __NR_ioprio_set 282 +#define __NR_ioprio_get 283 +#define __NR_inotify_init 284 +#define __NR_inotify_add_watch 285 +#define __NR_inotify_rm_watch 286 +#define __NR_migrate_pages 287 +#define __NR_openat 288 +#define __NR_mkdirat 289 +#define __NR_mknodat 290 +#define __NR_fchownat 291 +#define __NR_futimesat 292 +#define __NR_fstatat64 293 +#define __NR_unlinkat 294 +#define __NR_renameat 295 +#define __NR_linkat 296 +#define __NR_symlinkat 297 +#define __NR_readlinkat 298 +#define __NR_fchmodat 299 +#define __NR_faccessat 300 +#define __NR_pselect6 301 +#define __NR_ppoll 302 +#define __NR_unshare 303 +#define __NR_set_robust_list 304 +#define __NR_get_robust_list 305 +#define __NR_splice 306 +#define __NR_sync_file_range 307 +#define __NR_tee 308 +#define __NR_vmsplice 309 +#define __NR_move_pages 310 + #ifdef __KERNEL__ -#define NR_syscalls 282 +#define NR_syscalls 311 #include /* user-visible error numbers are in the range -1 - -MAX_ERRNO: see -- GitLab From 0e7af8d04ecb4f6ba8cd1f731f036a004ad0e174 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 13 Oct 2006 16:04:23 +0100 Subject: [PATCH 1157/1619] [PATCH] Fix headers_check for O= builds; disable automatic check on UML. * make header_check work with O= Signed-off-by: David Woodhouse Signed-off-by: Linus Torvalds --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f242829c4f0..eebf310e8ce 100644 --- a/Makefile +++ b/Makefile @@ -742,7 +742,7 @@ endif # ifdef CONFIG_KALLSYMS # vmlinux image - including updated kernel symbols vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE ifdef CONFIG_HEADERS_CHECK - $(Q)$(MAKE) headers_check + $(Q)$(MAKE) -f $(srctree)/Makefile headers_check endif $(call if_changed_rule,vmlinux__) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@ @@ -935,7 +935,7 @@ headers_install_all: include/linux/version.h scripts_basic FORCE PHONY += headers_install headers_install: include/linux/version.h scripts_basic FORCE - @if [ ! -r include/asm-$(ARCH)/Kbuild ]; then \ + @if [ ! -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \ echo '*** Error: Headers not exportable for this architecture ($(ARCH))'; \ exit 1 ; fi $(Q)$(MAKE) $(build)=scripts scripts/unifdef -- GitLab From b8a3ad5b53918787f4708ad9dfe90d2557cc78dd Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 13 Oct 2006 08:42:10 -0700 Subject: [PATCH 1158/1619] Include proper header file for PFN_DOWN() The recent commit (99a10a60ba9bedcf5d70ef81414d3e03816afa3f) to fix up mmap_kmem() broke compiles because it used PFN_DOWN() without including . Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index a89cb52228c..55473371b7c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include -- GitLab From b4bd8c66435a8cdf8c90334fb3b517a23ff2ab95 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 13 Oct 2006 09:25:04 -0700 Subject: [PATCH 1159/1619] Linux 2.6.19-rc2 That was slightly more painful than really necessary.. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eebf310e8ce..703d40a65e7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 19 -EXTRAVERSION =-rc1 +EXTRAVERSION =-rc2 NAME=Avast! A bilge rat! # *DOCUMENTATION* -- GitLab From 76dc82ab57236105285fd8520895c1404b8b952f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 30 Sep 2006 00:43:58 -0300 Subject: [PATCH 1160/1619] V4L/DVB (4692): Add WinTV-HVR3000 DVB-T support The WinTV-HVR3000 is currently defined for analog support only. This patch adds full DVB-T support. (DVB-S support will be added soon) Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 2 +- drivers/media/video/cx88/cx88-cards.c | 21 +++++++++++++++++++++ drivers/media/video/cx88/cx88-dvb.c | 17 +++++++++++++++++ drivers/media/video/cx88/cx88-input.c | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 126e59d935c..8755b3e7b09 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -51,7 +51,7 @@ 50 -> NPG Tech Real TV FM Top 10 [14f1:0842] 51 -> WinFast DTV2000 H [107d:665e] 52 -> Geniatech DVB-S [14f1:0084] - 53 -> Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T [0070:1404] + 53 -> Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T [0070:1404,0070:1400,0070:1401,0070:1402] 54 -> Norwood Micro TV Tuner 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980] 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index af71d4225c7..f764a57c56b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1230,6 +1230,7 @@ struct cx88_board cx88_boards[] = { .vmux = 2, .gpio0 = 0x84bf, }}, + .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_NORWOOD_MICRO] = { .name = "Norwood Micro TV Tuner", @@ -1590,6 +1591,18 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x9000, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, + },{ + .subvendor = 0x0070, + .subdevice = 0x1400, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x0070, + .subdevice = 0x1401, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x0070, + .subdevice = 0x1402, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1633,7 +1646,15 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) /* Make sure we support the board model */ switch (tv.model) { + case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */ + case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */ + case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */ + case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */ + case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */ + case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */ case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */ + case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */ + case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */ case 28552: /* WinTV-PVR 'Roslyn' (No IR) */ case 34519: /* WinTV-PCI-FM */ case 90002: /* Nova-T-PCI (9002) */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index bd0c8797f26..0ef13e7efa2 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -315,15 +315,22 @@ static struct cx22702_config hauppauge_novat_config = { .demod_address = 0x43, .output_mode = CX22702_SERIAL_OUTPUT, }; + static struct cx22702_config hauppauge_hvr1100_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; + static struct cx22702_config hauppauge_hvr1300_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; +static struct cx22702_config hauppauge_hvr3000_config = { + .demod_address = 0x63, + .output_mode = CX22702_SERIAL_OUTPUT, +}; + static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { @@ -558,6 +565,16 @@ static int dvb_register(struct cx8802_dev *dev) &dvb_pll_fmd1216me); } break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr3000_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_fmd1216me); + } + break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 83ebf7a3c05..ee48995a4ab 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -196,6 +196,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; @@ -419,6 +420,7 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) -- GitLab From 7844d7561307d6f8b0dd18b91f4dc6cff53848b4 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 6 Oct 2006 17:12:00 -0300 Subject: [PATCH 1161/1619] V4L/DVB (4725): Fix vivi compile on parisc parisc (and several other architectures) don't have a dma_address in their sg list. Use the macro instead. Signed-off-by: Matthew Wilcox Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index e7c01d560b6..3c8dc72dc8e 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -272,7 +272,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, /* Get first addr pointed to pixel position */ oldpg=get_addr_pos(pos,pages,to_addr); - pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT); + pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; /* We will just duplicate the second pixel at the packet */ @@ -287,7 +287,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, for (color=0;color<4;color++) { pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { - pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT); + pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); kunmap_atomic(basep, KM_BOUNCE_READ); basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset; oldpg=pgpos; @@ -339,8 +339,8 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, for (color=0;color<4;color++) { pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { - pg=pfn_to_page(to_addr[pgpos]. - sg->dma_address + pg=pfn_to_page(sg_dma_address( + to_addr[pgpos].sg) >> PAGE_SHIFT); kunmap_atomic(basep, KM_BOUNCE_READ); @@ -386,7 +386,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) struct timeval ts; /* Test if DMA mapping is ready */ - if (!vb->dma.sglist[0].dma_address) + if (!sg_dma_address(&vb->dma.sglist[0])) return; prep_to_addr(to_addr,vb); @@ -783,7 +783,7 @@ static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, for (i = 0; i < nents; i++ ) { BUG_ON(!sg[i].page); - sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset; + sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset; } return nents; -- GitLab From 2e7cf3ea5acc7ed57b8883cc6d35ffc06a5c95fa Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Fri, 6 Oct 2006 19:45:23 -0300 Subject: [PATCH 1162/1619] V4L/DVB (4727): Support status readout for saa713x based FM radio This patch adds readout for stereo and signal level for saa713x cards which use the saa713x as FM demodulator. These are many cards based on saa7133, tda8290 and tda8275a. FM channel search should work now. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 203302f2182..830617ea81c 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2248,7 +2248,11 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, t->type = V4L2_TUNER_RADIO; saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - + if (dev->input->amux == TV) { + t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); + t->rxsubchans = (saa_readb(0x529) & 0x08) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } return 0; } case VIDIOC_S_TUNER: -- GitLab From e0abc8cd54f5ac65465918f32f286218aa33e8c0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Oct 2006 16:22:10 -0300 Subject: [PATCH 1163/1619] V4L/DVB (4729): Fix VIDIOC_G_FMT for NTSC in cx25840. VIDIOC_G_FMT returned the sliced VBI types in the wrong lines for NTSC (three lines too low). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-vbi.c | 25 +++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index 48014a254e1..f85f2084324 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -235,6 +235,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ 0, 0, 0, 0 }; + int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60); int i; fmt = arg; @@ -246,13 +247,25 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) if ((cx25840_read(client, 0x404) & 0x10) == 0) break; - for (i = 7; i <= 23; i++) { - u8 v = cx25840_read(client, 0x424 + i - 7); + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx25840_read(client, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= + svbi->service_lines[0][i] | svbi->service_lines[1][i]; + } + } + else { + for (i = 10; i <= 21; i++) { + u8 v = cx25840_read(client, 0x424 + i - 10); - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= - svbi->service_lines[0][i] | svbi->service_lines[1][i]; + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= + svbi->service_lines[0][i] | svbi->service_lines[1][i]; + } } break; } -- GitLab From 180958febfb8d32da1d4fee13868e03be0cb931a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 7 Oct 2006 16:10:53 -0300 Subject: [PATCH 1164/1619] V4L/DVB (4731a): Kconfig: restore pvrusb2 menu items Looks like the pvrusb2 menu items were accidentally removed in git commit 1450e6bedc58c731617d99b4670070ed3ccc91b4 This patch restores the menu items so that the pvrusb2 driver can be built. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index afb734df6e0..fbe5b6168cc 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -677,6 +677,8 @@ config VIDEO_M32R_AR_M64278 menu "V4L USB devices" depends on USB && VIDEO_DEV +source "drivers/media/video/pvrusb2/Kconfig" + source "drivers/media/video/em28xx/Kconfig" source "drivers/media/video/usbvideo/Kconfig" -- GitLab From 934765b8e2f211aec119dbdd9feea6d3f2ffaf7e Mon Sep 17 00:00:00 2001 From: Uwe Bugla Date: Fri, 6 Oct 2006 13:12:48 -0300 Subject: [PATCH 1165/1619] V4L/DVB (4732): Fix spelling error in Kconfig help text for DVB_CORE_ATTACH Signed-off-by: Uwe Bugla Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig index e46eae3b9be..1990eda10c4 100644 --- a/drivers/media/dvb/dvb-core/Kconfig +++ b/drivers/media/dvb/dvb-core/Kconfig @@ -19,6 +19,6 @@ config DVB_CORE_ATTACH allow the card drivers to only load the frontend modules they require. This saves several KBytes of memory. - Note: You will need moudule-init-tools v3.2 or later for this feature. + Note: You will need module-init-tools v3.2 or later for this feature. If unsure say Y. -- GitLab From fc13d929cc7af3c0da09ea2b6d23465b933e279d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Oct 2006 05:17:09 -0300 Subject: [PATCH 1166/1619] V4L/DVB (4733): Tda10086: fix frontend selection for dvb_attach Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda10086.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h index e8061db1112..18457adee30 100644 --- a/drivers/media/dvb/frontends/tda10086.h +++ b/drivers/media/dvb/frontends/tda10086.h @@ -35,7 +35,16 @@ struct tda10086_config u8 invert; }; +#if defined(CONFIG_DVB_TDA10086) || defined(CONFIG_DVB_TDA10086_MODULE) extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TDA10086 #endif // TDA10086_H -- GitLab From c071fab453f7b181c49d92d06d936bb243ef1932 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Oct 2006 05:17:45 -0300 Subject: [PATCH 1167/1619] V4L/DVB (4734): Tda826x: fix frontend selection for dvb_attach Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda826x.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h index 3307607632b..83998c00119 100644 --- a/drivers/media/dvb/frontends/tda826x.h +++ b/drivers/media/dvb/frontends/tda826x.h @@ -35,6 +35,19 @@ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector. * @return FE pointer on success, NULL on failure. */ -extern struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough); - -#endif +#if defined(CONFIG_DVB_TDA826X) || defined(CONFIG_DVB_TDA826X_MODULE) +extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + int has_loopthrough); +#else +static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c, + int has_loopthrough) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TDA826X + +#endif // __DVB_TDA826X_H__ -- GitLab From 626ae83bb24927ca015503448f0199842ae2e8da Mon Sep 17 00:00:00 2001 From: Amit Choudhary Date: Mon, 9 Oct 2006 15:50:10 -0300 Subject: [PATCH 1168/1619] V4L/DVB (4738): Bt8xx/dvb-bt8xx.c: check kmalloc() return value. Check the return value of kmalloc() in function frontend_init(), in file drivers/media/dvb/bt8xx/dvb-bt8xx.c. Signed-off-by: Amit Choudhary Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index fb6c4cc8477..14e69a736ed 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -665,6 +665,10 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) case BTTV_BOARD_TWINHAN_DST: /* DST is not a frontend driver !!! */ state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL); + if (!state) { + printk("dvb_bt8xx: No memory\n"); + break; + } /* Setup the Card */ state->config = &dst_config; state->i2c = card->i2c_adapter; -- GitLab From fc2fa31f4eaa53995593ced14c73f2cf63dcfa17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=E1draig=20Brady?= Date: Mon, 9 Oct 2006 08:02:17 -0300 Subject: [PATCH 1169/1619] V4L/DVB (4739): SECAM support for saa7113 into saa7115 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without the attached trivial patch, the saa7113 is set up for PAL when SECAM is selected and hence will see only show black and white for SECAM signals. Tested the patch against the saa7115 module in linux-2.6.17 with a Pinnacle 50e USB tuner (em28xx). Signed-off-by: Pádraig Brady Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 974179d4d38..c5719f7bd1a 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -960,6 +960,8 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) reg |= 0x10; } else if (std == V4L2_STD_NTSC_M_JP) { reg |= 0x40; + } else if (std == V4L2_STD_SECAM) { + reg |= 0x50; } saa711x_write(client, R_0E_CHROMA_CNTL_1, reg); } else { -- GitLab From 474ce78130ba37cb50e620c538ab3ffe6c582ba6 Mon Sep 17 00:00:00 2001 From: Enrico Scholz Date: Mon, 9 Oct 2006 16:27:05 -0300 Subject: [PATCH 1170/1619] V4L/DVB (4740): Fixed an if-block to avoid floating with debug-messages The dbgarg() macro in videodev.c contains some printk() statements where only the first one is influenced by an if-statement. This causes floating with debug-messages which is fixed by this patch by adding a '{ ... }' pair. Signed-off-by: Enrico Scholz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 479a0675cf6..98de872042a 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -17,10 +17,11 @@ */ #define dbgarg(cmd, fmt, arg...) \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ printk (KERN_DEBUG "%s: ", vfd->name); \ v4l_printk_ioctl(cmd); \ - printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); + printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \ + } #define dbgarg2(fmt, arg...) \ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ -- GitLab From 2444a2fca488fa8e362895a4ca9fdc51f497282a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 10 Oct 2006 15:09:43 -0300 Subject: [PATCH 1171/1619] V4L/DVB (4741): {ov511,stv680}: handle sysfs errors Signed-off-by: Jeff Garzik Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov511.c | 58 +++++++++++++++++++++++++++++------- drivers/media/video/stv680.c | 53 +++++++++++++++++++++++++------- 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index ce4886f1528..b4db2cbb5a8 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5648,17 +5648,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf) } static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); -static void ov_create_sysfs(struct video_device *vdev) +static int ov_create_sysfs(struct video_device *vdev) { - video_device_create_file(vdev, &class_device_attr_custom_id); - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_bridge); - video_device_create_file(vdev, &class_device_attr_sensor); - video_device_create_file(vdev, &class_device_attr_brightness); - video_device_create_file(vdev, &class_device_attr_saturation); - video_device_create_file(vdev, &class_device_attr_contrast); - video_device_create_file(vdev, &class_device_attr_hue); - video_device_create_file(vdev, &class_device_attr_exposure); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_custom_id); + if (rc) goto err; + rc = video_device_create_file(vdev, &class_device_attr_model); + if (rc) goto err_id; + rc = video_device_create_file(vdev, &class_device_attr_bridge); + if (rc) goto err_model; + rc = video_device_create_file(vdev, &class_device_attr_sensor); + if (rc) goto err_bridge; + rc = video_device_create_file(vdev, &class_device_attr_brightness); + if (rc) goto err_sensor; + rc = video_device_create_file(vdev, &class_device_attr_saturation); + if (rc) goto err_bright; + rc = video_device_create_file(vdev, &class_device_attr_contrast); + if (rc) goto err_sat; + rc = video_device_create_file(vdev, &class_device_attr_hue); + if (rc) goto err_contrast; + rc = video_device_create_file(vdev, &class_device_attr_exposure); + if (rc) goto err_hue; + + return 0; + +err_hue: + video_device_remove_file(vdev, &class_device_attr_hue); +err_contrast: + video_device_remove_file(vdev, &class_device_attr_contrast); +err_sat: + video_device_remove_file(vdev, &class_device_attr_saturation); +err_bright: + video_device_remove_file(vdev, &class_device_attr_brightness); +err_sensor: + video_device_remove_file(vdev, &class_device_attr_sensor); +err_bridge: + video_device_remove_file(vdev, &class_device_attr_bridge); +err_model: + video_device_remove_file(vdev, &class_device_attr_model); +err_id: + video_device_remove_file(vdev, &class_device_attr_custom_id); +err: + return rc; } /**************************************************************************** @@ -5817,7 +5849,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) ov->vdev->minor); usb_set_intfdata(intf, ov); - ov_create_sysfs(ov->vdev); + if (ov_create_sysfs(ov->vdev)) { + err("ov_create_sysfs failed"); + goto error; + } + return 0; error: diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 87e11300181..6d1ef1e2e8e 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -516,16 +516,45 @@ stv680_file(frames_read, framecount, "%d\n"); stv680_file(packets_dropped, dropped, "%d\n"); stv680_file(decoding_errors, error, "%d\n"); -static void stv680_create_sysfs_files(struct video_device *vdev) +static int stv680_create_sysfs_files(struct video_device *vdev) { - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_in_use); - video_device_create_file(vdev, &class_device_attr_streaming); - video_device_create_file(vdev, &class_device_attr_palette); - video_device_create_file(vdev, &class_device_attr_frames_total); - video_device_create_file(vdev, &class_device_attr_frames_read); - video_device_create_file(vdev, &class_device_attr_packets_dropped); - video_device_create_file(vdev, &class_device_attr_decoding_errors); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_model); + if (rc) goto err; + rc = video_device_create_file(vdev, &class_device_attr_in_use); + if (rc) goto err_model; + rc = video_device_create_file(vdev, &class_device_attr_streaming); + if (rc) goto err_inuse; + rc = video_device_create_file(vdev, &class_device_attr_palette); + if (rc) goto err_stream; + rc = video_device_create_file(vdev, &class_device_attr_frames_total); + if (rc) goto err_pal; + rc = video_device_create_file(vdev, &class_device_attr_frames_read); + if (rc) goto err_framtot; + rc = video_device_create_file(vdev, &class_device_attr_packets_dropped); + if (rc) goto err_framread; + rc = video_device_create_file(vdev, &class_device_attr_decoding_errors); + if (rc) goto err_dropped; + + return 0; + +err_dropped: + video_device_remove_file(vdev, &class_device_attr_packets_dropped); +err_framread: + video_device_remove_file(vdev, &class_device_attr_frames_read); +err_framtot: + video_device_remove_file(vdev, &class_device_attr_frames_total); +err_pal: + video_device_remove_file(vdev, &class_device_attr_palette); +err_stream: + video_device_remove_file(vdev, &class_device_attr_streaming); +err_inuse: + video_device_remove_file(vdev, &class_device_attr_in_use); +err_model: + video_device_remove_file(vdev, &class_device_attr_model); +err: + return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) @@ -1418,9 +1447,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); usb_set_intfdata (intf, stv680); - stv680_create_sysfs_files(stv680->vdev); + retval = stv680_create_sysfs_files(stv680->vdev); + if (retval) + goto error_unreg; return 0; +error_unreg: + video_unregister_device(stv680->vdev); error_vdev: video_device_release(stv680->vdev); error: -- GitLab From c12e3be0860652ed1e15c9442adcba44317211d1 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 13 Oct 2006 07:17:32 -0300 Subject: [PATCH 1172/1619] V4L/DVB (4742): Drivers/media/video: handle sysfs errors Signed-off-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/et61x251/et61x251_core.c | 37 ++++++++-- drivers/media/video/pwc/pwc-if.c | 41 ++++++++--- drivers/media/video/sn9c102/sn9c102_core.c | 71 +++++++++++++++----- 3 files changed, 117 insertions(+), 32 deletions(-) diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index bc544cc7ccb..f786ab11d2c 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -973,16 +973,32 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, et61x251_show_i2c_val, et61x251_store_i2c_val); -static void et61x251_create_sysfs(struct et61x251_device* cam) +static int et61x251_create_sysfs(struct et61x251_device* cam) { struct video_device *v4ldev = cam->v4ldev; + int rc; - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); + rc = video_device_create_file(v4ldev, &class_device_attr_reg); + if (rc) goto err; + rc = video_device_create_file(v4ldev, &class_device_attr_val); + if (rc) goto err_reg; if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + if (rc) goto err_val; + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); + if (rc) goto err_i2c_reg; } + + return 0; + +err_i2c_reg: + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); +err_val: + video_device_remove_file(v4ldev, &class_device_attr_val); +err_reg: + video_device_remove_file(v4ldev, &class_device_attr_reg); +err: + return rc; } #endif /* CONFIG_VIDEO_ADV_DEBUG */ @@ -2534,7 +2550,9 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; #ifdef CONFIG_VIDEO_ADV_DEBUG - et61x251_create_sysfs(cam); + err = et61x251_create_sysfs(cam); + if (err) + goto fail2; DBG(2, "Optional device control through 'sysfs' interface ready"); #endif @@ -2544,6 +2562,13 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return 0; +#ifdef CONFIG_VIDEO_ADV_DEBUG +fail2: + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); + video_unregister_device(cam->v4ldev); +#endif fail: if (cam) { kfree(cam->control_buffer); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index c77b85cf3d8..46c11483088 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1024,12 +1024,25 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, NULL); -static void pwc_create_sysfs_files(struct video_device *vdev) +static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_create_file(vdev, &class_device_attr_pan_tilt); - video_device_create_file(vdev, &class_device_attr_button); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_button); + if (rc) + goto err; + if (pdev->features & FEATURE_MOTOR_PANTILT) { + rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + if (rc) goto err_button; + } + + return 0; + +err_button: + video_device_remove_file(vdev, &class_device_attr_button); +err: + return rc; } static void pwc_remove_sysfs_files(struct video_device *vdev) @@ -1408,7 +1421,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id struct usb_device *udev = interface_to_usbdev(intf); struct pwc_device *pdev = NULL; int vendor_id, product_id, type_id; - int i, hint; + int i, hint, rc; int features = 0; int video_nr = -1; /* default: use next available device */ char serial_number[30], *name; @@ -1709,9 +1722,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { PWC_ERROR("Failed to register as video device (%d).\n", i); - video_device_release(pdev->vdev); /* Drip... drip... drip... */ - kfree(pdev); /* Oops, no memory leaks please */ - return -EIO; + rc = i; + goto err; } else { PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); @@ -1723,13 +1735,24 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); usb_set_intfdata (intf, pdev); - pwc_create_sysfs_files(pdev->vdev); + rc = pwc_create_sysfs_files(pdev->vdev); + if (rc) + goto err_unreg; /* Set the leds off */ pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); return 0; + +err_unreg: + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = NULL; + video_unregister_device(pdev->vdev); +err: + video_device_release(pdev->vdev); /* Drip... drip... drip... */ + kfree(pdev); /* Oops, no memory leaks please */ + return rc; } /* The user janked out the cable... */ diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 3e0ff8a7846..a4702d3c2ac 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1240,23 +1240,53 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); -static void sn9c102_create_sysfs(struct sn9c102_device* cam) +static int sn9c102_create_sysfs(struct sn9c102_device* cam) { struct video_device *v4ldev = cam->v4ldev; + int rc; + + rc = video_device_create_file(v4ldev, &class_device_attr_reg); + if (rc) goto err; + rc = video_device_create_file(v4ldev, &class_device_attr_val); + if (rc) goto err_reg; + rc = video_device_create_file(v4ldev, &class_device_attr_frame_header); + if (rc) goto err_val; - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_frame_header); - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - video_device_create_file(v4ldev, &class_device_attr_green); - else if (cam->bridge == BRIDGE_SN9C103) { - video_device_create_file(v4ldev, &class_device_attr_blue); - video_device_create_file(v4ldev, &class_device_attr_red); - } if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + if (rc) goto err_frhead; + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); + if (rc) goto err_i2c_reg; + } + + if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { + rc = video_device_create_file(v4ldev, &class_device_attr_green); + if (rc) goto err_i2c_val; + } else if (cam->bridge == BRIDGE_SN9C103) { + rc = video_device_create_file(v4ldev, &class_device_attr_blue); + if (rc) goto err_i2c_val; + rc = video_device_create_file(v4ldev, &class_device_attr_red); + if (rc) goto err_blue; } + + return 0; + +err_blue: + video_device_remove_file(v4ldev, &class_device_attr_blue); +err_i2c_val: + if (cam->sensor.sysfs_ops) + video_device_remove_file(v4ldev, &class_device_attr_i2c_val); +err_i2c_reg: + if (cam->sensor.sysfs_ops) + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); +err_frhead: + video_device_remove_file(v4ldev, &class_device_attr_frame_header); +err_val: + video_device_remove_file(v4ldev, &class_device_attr_val); +err_reg: + video_device_remove_file(v4ldev, &class_device_attr_reg); +err: + return rc; } #endif /* CONFIG_VIDEO_ADV_DEBUG */ @@ -2809,10 +2839,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "V4L2 device registration failed"); if (err == -ENFILE && video_nr[dev_nr] == -1) DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); - goto fail; + goto fail2; } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); @@ -2823,7 +2850,9 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; #ifdef CONFIG_VIDEO_ADV_DEBUG - sn9c102_create_sysfs(cam); + err = sn9c102_create_sysfs(cam); + if (err) + goto fail3; DBG(2, "Optional device control through 'sysfs' interface ready"); #endif @@ -2833,6 +2862,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return 0; +#ifdef CONFIG_VIDEO_ADV_DEBUG +fail3: + video_unregister_device(cam->v4ldev); +#endif +fail2: + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); fail: if (cam) { kfree(cam->control_buffer); -- GitLab From 83427ac5d643308ccb36e05d525949952bdedc27 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 13 Oct 2006 07:51:16 -0300 Subject: [PATCH 1173/1619] V4L/DVB (4743): Fix oops in VIDIOC_G_PARM The call to v4l2_std_construct() in the VIDIOC_G_PARM handler treats vfd->current_norm as if it were an index - but it's not. The result is an oops if the driver has no vidioc_g_parm() method defined. Here's the fix. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 98de872042a..d424a4129d6 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1288,6 +1288,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; + int i; if (!vfd->tvnormsize) { printk (KERN_WARNING "%s: no TV norms defined!\n", @@ -1298,8 +1299,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - v4l2_video_std_construct(&s, vfd->tvnorms[vfd->current_norm].id, - vfd->tvnorms[vfd->current_norm].name); + for (i = 0; i < vfd->tvnormsize; i++) + if (vfd->tvnorms[i].id == vfd->current_norm) + break; + if (i >= vfd->tvnormsize) + return -EINVAL; + + v4l2_video_std_construct(&s, vfd->current_norm, + vfd->tvnorms[i].name); memset(p,0,sizeof(*p)); -- GitLab From 1d3e6bdaa8b4b068d378ab58679c334e433496cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Oct 2006 15:45:33 -0300 Subject: [PATCH 1174/1619] V4L/DVB (4744): The Samsung TCPN2121P30A does not have a tda9887 Contrary to all expections the Samsung TCPN2121P30A tuner does NOT have a tda9887. Remove the tda9887 flag from the tuner definition. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-types.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 8fff642fad5..781682373b6 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1046,7 +1046,6 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), - .has_tda9887 = 1, }, }; -- GitLab From 5011915cbb139a331c083e65a61c82e9174f9813 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Oct 2006 05:12:42 -0300 Subject: [PATCH 1175/1619] 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(-) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index c5fdf625954..df5c4654360 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.. */ -- GitLab From 6a74216c4590e4d322a45e1085f3553b1fb07f06 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 13 Oct 2006 11:33:26 -0300 Subject: [PATCH 1176/1619] V4L/DVB (4748): Fixed oops for Nova-T USB2 When using the remote control with the Nova-T USB there was an Oops because of the recent DVB-USB-Adapter change. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dibusb.h | 2 ++ drivers/media/dvb/dvb-usb/nova-t-usb2.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h index 5153fb943da..b6078103274 100644 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ b/drivers/media/dvb/dvb-usb/dibusb.h @@ -99,7 +99,9 @@ struct dibusb_state { struct dib_fe_xfer_ops ops; int mt2060_present; +}; +struct dibusb_device_state { /* for RC5 remote control */ int old_toggle; int last_repeat_count; diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index a9219bf69b8..a58874c790b 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -75,7 +75,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; u16 raw; int i; - struct dibusb_state *st = d->priv; + struct dibusb_device_state *st = d->priv; dvb_usb_generic_rw(d,cmd,2,key,5,0); @@ -184,6 +184,7 @@ static struct dvb_usb_device_properties nova_t_properties = { .size_of_priv = sizeof(struct dibusb_state), } }, + .size_of_priv = sizeof(struct dibusb_device_state), .power_ctrl = dibusb2_0_power_ctrl, .read_mac_address = nova_t_read_mac_address, -- GitLab From 5570dd02ca7fb2e28d32516fae05031d48711aa5 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 13 Oct 2006 11:35:12 -0300 Subject: [PATCH 1177/1619] V4L/DVB (4750): AGC command1/2 is board specific Added config-struct-parameter to take board-specific AGC command 1 and 2 into account. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dibusb-common.c | 11 +++++++++-- drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib3000mc.h | 3 +++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index fd3a9902f98..5143e426d28 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -169,7 +169,7 @@ EXPORT_SYMBOL(dibusb_read_eeprom_byte); // Config Adjacent channels Perf -cal22 static struct dibx000_agc_config dib3000p_mt2060_agc_config = { .band_caps = BAND_VHF | BAND_UHF, - .setup = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0), + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), .agc1_max = 48497, .agc1_min = 23593, @@ -196,10 +196,14 @@ static struct dib3000mc_config stk3000p_dib3000p_config = { .ln_adc_level = 0x1cc7, .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, }; static struct dibx000_agc_config dib3000p_panasonic_agc_config = { - .setup = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0), + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), .agc1_max = 56361, .agc1_min = 22282, @@ -226,6 +230,9 @@ static struct dib3000mc_config mod3000p_dib3000p_config = { .ln_adc_level = 0x1cc7, .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, }; int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index ccc813b525d..3561a777568 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -345,7 +345,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) /* agc */ dib3000mc_write_word(state, 36, state->cfg->max_time); - dib3000mc_write_word(state, 37, agc->setup); + dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0)); dib3000mc_write_word(state, 38, state->cfg->pwm3_value); dib3000mc_write_word(state, 39, state->cfg->ln_adc_level); diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h index b198cd5b184..0d6fdef7753 100644 --- a/drivers/media/dvb/frontends/dib3000mc.h +++ b/drivers/media/dvb/frontends/dib3000mc.h @@ -28,6 +28,9 @@ struct dib3000mc_config { u16 max_time; u16 ln_adc_level; + u8 agc_command1 :1; + u8 agc_command2 :1; + u8 mobile_mode; u8 output_mpeg2_in_188_bytes; -- GitLab From 288f3ad406460f03642a41bb945826891a7b866f Mon Sep 17 00:00:00 2001 From: Marek W Date: Mon, 14 Aug 2006 22:37:20 -0700 Subject: [PATCH 1178/1619] ACPI: asus_acpi: W3000 support Add support for W3000 (W3V) and indirectly fixes an issue with kmilo under KDE (it was triggering excessive LCD read error messages by querying asus_acpi module) allowing people (I am probably the only one who tested this) with W3000 to run kmilo. Cc: Karol Kozimor Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index e9ee4c52a5f..ebc033f87e7 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -138,6 +138,7 @@ struct asus_hotk { S2x, //S200 (J1 reported), Victor MP-XP7210 W1N, //W1000N W5A, //W5A + W3V, //W3030V xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N //(Centrino) END_MODEL @@ -376,6 +377,17 @@ static struct model_data model_conf[END_MODEL] = { .display_get = "\\ADVG"}, { + .name = "W3V", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\BKLT", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\INFB"}, + + { .name = "xxN", .mt_mled = "MLED", /* WLED present, but not controlled by ACPI */ @@ -1097,6 +1109,8 @@ static int asus_model_match(char *model) return A4G; else if (strncmp(model, "W1N", 3) == 0) return W1N; + else if (strncmp(model, "W3V", 3) == 0) + return W3V; else if (strncmp(model, "W5A", 3) == 0) return W5A; else @@ -1200,9 +1214,10 @@ static int asus_hotk_get_info(void) hotk->methods->mt_wled = NULL; /* L5D's WLED is not controlled by ACPI */ else if (strncmp(string, "M2N", 3) == 0 || + strncmp(string, "W3V", 3) == 0 || strncmp(string, "S1N", 3) == 0) hotk->methods->mt_wled = "WLED"; - /* M2N and S1N have a usable WLED */ + /* M2N, S1N and W3V have a usable WLED */ else if (asus_info) { if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) hotk->methods->mled_status = NULL; -- GitLab From 4d6bd5ea4ec4991901a8cf5a586babef68e1fa3f Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 22 Sep 2006 12:19:14 +0200 Subject: [PATCH 1179/1619] ACPI: ibm_acpi: Remove experimental status for brightness and volume. The brightness and volume features from ibm-acpi are stable. The experimental flag is no longer needed. Signed-off-by: Stefan Schmidt Acked-by: Borislav Deianov Signed-off-by: Len Brown --- drivers/acpi/ibm_acpi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 15fc12482ba..003a9876c96 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1702,13 +1702,11 @@ static struct ibm_struct ibms[] = { .name = "brightness", .read = brightness_read, .write = brightness_write, - .experimental = 1, }, { .name = "volume", .read = volume_read, .write = volume_write, - .experimental = 1, }, { .name = "fan", -- GitLab From 24f7ff0af855ece60064a2532d8b316df02983c6 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 22 Sep 2006 12:19:15 +0200 Subject: [PATCH 1180/1619] ACPI: ibm_acpi: Update documentation for brightness and volume. Document the change of the experimental flag for brightness and volume. Signed-off-by: Stefan Schmidt Acked-by: Borislav Deianov Signed-off-by: Len Brown --- Documentation/ibm-acpi.txt | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt index 71aa4034527..1672590d8ef 100644 --- a/Documentation/ibm-acpi.txt +++ b/Documentation/ibm-acpi.txt @@ -30,8 +30,8 @@ detailed description): - ACPI sounds - temperature sensors - Experimental: embedded controller register dump - - Experimental: LCD brightness control - - Experimental: volume control + - LCD brightness control + - Volume control - Experimental: fan speed, fan enable/disable A compatibility table by model and feature is maintained on the web @@ -523,13 +523,8 @@ registers contain the current battery capacity, etc. If you experiment with this, do send me your results (including some complete dumps with a description of the conditions when they were taken.) -EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness ------------------------------------------------------------------ - -This feature is marked EXPERIMENTAL because the implementation -directly accesses hardware registers and may not work as expected. USE -WITH CAUTION! To use this feature, you need to supply the -experimental=1 parameter when loading the module. +LCD brightness control -- /proc/acpi/ibm/brightness +--------------------------------------------------- This feature allows software control of the LCD brightness on ThinkPad models which don't have a hardware brightness slider. The available @@ -542,13 +537,8 @@ commands are: The number range is 0 to 7, although not all of them may be distinct. The current brightness level is shown in the file. -EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume ------------------------------------------------------ - -This feature is marked EXPERIMENTAL because the implementation -directly accesses hardware registers and may not work as expected. USE -WITH CAUTION! To use this feature, you need to supply the -experimental=1 parameter when loading the module. +Volume control -- /proc/acpi/ibm/volume +--------------------------------------- This feature allows volume control on ThinkPad models which don't have a hardware volume knob. The available commands are: -- GitLab From 28b779d127d3038ff83f42259d135a063b7cd848 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 22 Sep 2006 12:19:16 +0200 Subject: [PATCH 1181/1619] ACPI: ibm_acpi: Documentation the wan feature. Document the wan feature Jeremy Fitzhardinge added to ibm_acpi. Signed-off-by: Stefan Schmidt Acked-by: Borislav Deianov Signed-off-by: Len Brown --- Documentation/ibm-acpi.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt index 1672590d8ef..00b8cf3999c 100644 --- a/Documentation/ibm-acpi.txt +++ b/Documentation/ibm-acpi.txt @@ -33,6 +33,7 @@ detailed description): - LCD brightness control - Volume control - Experimental: fan speed, fan enable/disable + - Experimental: WAN enable and disable A compatibility table by model and feature is maintained on the web site, http://ibm-acpi.sf.net/. I appreciate any success or failure @@ -601,6 +602,23 @@ with the following command: echo 'level ' > /proc/acpi/ibm/thermal +EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan +--------------------------------------- + +This feature is marked EXPERIMENTAL because the implementation +directly accesses hardware registers and may not work as expected. USE +WITH CAUTION! To use this feature, you need to supply the +experimental=1 parameter when loading the module. + +This feature shows the presence and current state of a WAN (Sierra +Wireless EV-DO) device. If WAN is installed, the following commands can +be used: + + echo enable > /proc/acpi/ibm/wan + echo disable > /proc/acpi/ibm/wan + +It was tested on a Lenovo Thinkpad X60. It should probably work on other +Thinkpad models which come with this module installed. Multiple Commands, Module Parameters ------------------------------------ -- GitLab From 963497c12acb4d43caa9751b9291b014eea51a1a Mon Sep 17 00:00:00 2001 From: "Lebedev, Vladimir P" Date: Tue, 5 Sep 2006 19:49:13 +0400 Subject: [PATCH 1182/1619] ACPI: sbs: check for NULL device pointer Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 62bef0b3b61..79f38f03677 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_device *device) int acpi_sbs_remove(struct acpi_device *device, int type) { - struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device); + struct acpi_sbs *sbs = NULL; int id; - if (!device || !sbs) { + if (!device) { + return -EINVAL; + } + + sbs = (struct acpi_sbs *)acpi_driver_data(device); + + if (!sbs) { return -EINVAL; } -- GitLab From 3cd5b87d96db503f69a5892b8f5350d356d18969 Mon Sep 17 00:00:00 2001 From: "Lebedev, Vladimir P" Date: Tue, 5 Sep 2006 19:59:22 +0400 Subject: [PATCH 1183/1619] ACPI: sbs: fix module_param() initializers Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 79f38f03677..8908a975e57 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INFO_MODE; static int update_time = UPDATE_TIME; static int update_time2 = UPDATE_TIME2; -module_param(capacity_mode, int, CAPACITY_UNIT); -module_param(update_mode, int, UPDATE_MODE); -module_param(update_info_mode, int, UPDATE_INFO_MODE); -module_param(update_time, int, UPDATE_TIME); -module_param(update_time2, int, UPDATE_TIME2); +module_param(capacity_mode, int, 0); +module_param(update_mode, int, 0); +module_param(update_info_mode, int, 0); +module_param(update_time, int, 0); +module_param(update_time2, int, 0); static int acpi_sbs_add(struct acpi_device *device); static int acpi_sbs_remove(struct acpi_device *device, int type); -- GitLab From 991528d7348667924176f3e29addea0675298944 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Mon, 25 Sep 2006 16:28:13 -0700 Subject: [PATCH 1184/1619] ACPI: Processor native C-states using MWAIT Intel processors starting with the Core Duo support support processor native C-state using the MWAIT instruction. Refer: Intel Architecture Software Developer's Manual http://www.intel.com/design/Pentium4/manuals/253668.htm Platform firmware exports the support for Native C-state to OS using ACPI _PDC and _CST methods. Refer: Intel Processor Vendor-Specific ACPI: Interface Specification http://www.intel.com/technology/iapc/acpi/downloads/302223.htm With Processor Native C-state, we use 'MWAIT' instruction on the processor to enter different C-states (C1, C2, C3). We won't use the special IO ports to enter C-state and no SMM mode etc required to enter C-state. Overall this will mean better C-state support. One major advantage of using MWAIT for all C-states is, with this and "treat interrupt as break event" feature of MWAIT, we can now get accurate timing for the time spent in C1, C2, .. states. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- arch/i386/kernel/acpi/cstate.c | 122 ++++++++++++++++++++++++++++++++- arch/i386/kernel/process.c | 22 ++++-- arch/x86_64/kernel/process.c | 22 ++++-- drivers/acpi/processor_idle.c | 101 +++++++++++++++++---------- include/acpi/pdc_intel.h | 9 ++- include/acpi/processor.h | 18 +++++ include/asm-i386/processor.h | 2 + include/asm-x86_64/processor.h | 2 + 8 files changed, 242 insertions(+), 56 deletions(-) diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c index 25db49ef177..20563e52c62 100644 --- a/arch/i386/kernel/acpi/cstate.c +++ b/arch/i386/kernel/acpi/cstate.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -41,5 +42,124 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, flags->bm_check = 1; } } - EXPORT_SYMBOL(acpi_processor_power_init_bm_check); + +/* The code below handles cstate entry with monitor-mwait pair on Intel*/ + +struct cstate_entry_s { + struct { + unsigned int eax; + unsigned int ecx; + } states[ACPI_PROCESSOR_MAX_POWER]; +}; +static struct cstate_entry_s *cpu_cstate_entry; /* per CPU ptr */ + +static short mwait_supported[ACPI_PROCESSOR_MAX_POWER]; + +#define MWAIT_SUBSTATE_MASK (0xf) +#define MWAIT_SUBSTATE_SIZE (4) + +#define CPUID_MWAIT_LEAF (5) +#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1) +#define CPUID5_ECX_INTERRUPT_BREAK (0x2) + +#define MWAIT_ECX_INTERRUPT_BREAK (0x1) + +#define NATIVE_CSTATE_BEYOND_HALT (2) + +int acpi_processor_ffh_cstate_probe(unsigned int cpu, + struct acpi_processor_cx *cx, struct acpi_power_register *reg) +{ + struct cstate_entry_s *percpu_entry; + struct cpuinfo_x86 *c = cpu_data + cpu; + + cpumask_t saved_mask; + int retval; + unsigned int eax, ebx, ecx, edx; + unsigned int edx_part; + unsigned int cstate_type; /* C-state type and not ACPI C-state type */ + unsigned int num_cstate_subtype; + + if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF ) + return -1; + + if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT) + return -1; + + percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu); + percpu_entry->states[cx->index].eax = 0; + percpu_entry->states[cx->index].ecx = 0; + + /* Make sure we are running on right CPU */ + saved_mask = current->cpus_allowed; + retval = set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (retval) + return -1; + + cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx); + + /* Check whether this particular cx_type (in CST) is supported or not */ + cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1; + edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE); + num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK; + + retval = 0; + if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) { + retval = -1; + goto out; + } + + /* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */ + if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || + !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) { + retval = -1; + goto out; + } + percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK; + + /* Use the hint in CST */ + percpu_entry->states[cx->index].eax = cx->address; + + if (!mwait_supported[cstate_type]) { + mwait_supported[cstate_type] = 1; + printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d " + "state\n", cx->type); + } + +out: + set_cpus_allowed(current, saved_mask); + return retval; +} +EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe); + +void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx) +{ + unsigned int cpu = smp_processor_id(); + struct cstate_entry_s *percpu_entry; + + percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu); + mwait_idle_with_hints(percpu_entry->states[cx->index].eax, + percpu_entry->states[cx->index].ecx); +} +EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter); + +static int __init ffh_cstate_init(void) +{ + struct cpuinfo_x86 *c = &boot_cpu_data; + if (c->x86_vendor != X86_VENDOR_INTEL) + return -1; + + cpu_cstate_entry = alloc_percpu(struct cstate_entry_s); + return 0; +} + +static void __exit ffh_cstate_exit(void) +{ + if (cpu_cstate_entry) { + free_percpu(cpu_cstate_entry); + cpu_cstate_entry = NULL; + } +} + +arch_initcall(ffh_cstate_init); +__exitcall(ffh_cstate_exit); diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index b0a07801d9d..57d375900af 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -236,20 +236,28 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); * We execute MONITOR against need_resched and enter optimized wait state * through MWAIT. Whenever someone changes need_resched, we would be woken * up from MWAIT (without an IPI). + * + * New with Core Duo processors, MWAIT can take some hints based on CPU + * capability. */ -static void mwait_idle(void) +void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) { - local_irq_enable(); - - while (!need_resched()) { + if (!need_resched()) { __monitor((void *)¤t_thread_info()->flags, 0, 0); smp_mb(); - if (need_resched()) - break; - __mwait(0, 0); + if (!need_resched()) + __mwait(eax, ecx); } } +/* Default MONITOR/MWAIT with no hints, used for default C1 state */ +static void mwait_idle(void) +{ + local_irq_enable(); + while (!need_resched()) + mwait_idle_with_hints(0, 0); +} + void __devinit select_idle_routine(const struct cpuinfo_x86 *c) { if (cpu_has(c, X86_FEATURE_MWAIT)) { diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 5e95b257ee2..49f7fac6229 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -238,20 +238,28 @@ void cpu_idle (void) * We execute MONITOR against need_resched and enter optimized wait state * through MWAIT. Whenever someone changes need_resched, we would be woken * up from MWAIT (without an IPI). + * + * New with Core Duo processors, MWAIT can take some hints based on CPU + * capability. */ -static void mwait_idle(void) +void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) { - local_irq_enable(); - - while (!need_resched()) { + if (!need_resched()) { __monitor((void *)¤t_thread_info()->flags, 0, 0); smp_mb(); - if (need_resched()) - break; - __mwait(0, 0); + if (!need_resched()) + __mwait(eax, ecx); } } +/* Default MONITOR/MWAIT with no hints, used for default C1 state */ +static void mwait_idle(void) +{ + local_irq_enable(); + while (!need_resched()) + mwait_idle_with_hints(0,0); +} + void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) { static int printed; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0a395fca843..429a39dbd75 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -219,6 +219,23 @@ static void acpi_safe_halt(void) static atomic_t c3_cpu_count; +/* Common C-state entry for C2, C3, .. */ +static void acpi_cstate_enter(struct acpi_processor_cx *cstate) +{ + if (cstate->space_id == ACPI_CSTATE_FFH) { + /* Call into architectural FFH based C-state */ + acpi_processor_ffh_cstate_enter(cstate); + } else { + int unused; + /* IO port based C-state */ + inb(cstate->address); + /* Dummy wait op - must do something useless after P_LVL2 read + because chipsets cannot guarantee that STPCLK# signal + gets asserted in time to freeze execution properly. */ + unused = inl(acpi_fadt.xpm_tmr_blk.address); + } +} + static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -361,11 +378,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); /* Invoke C2 */ - inb(cx->address); - /* Dummy wait op - must do something useless after P_LVL2 read - because chipsets cannot guarantee that STPCLK# signal - gets asserted in time to freeze execution properly. */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); @@ -401,9 +414,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); /* Invoke C3 */ - inb(cx->address); - /* Dummy wait op (see above) */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); if (pr->flags.bm_check) { @@ -628,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) return 0; } -static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr) +static int acpi_processor_get_power_info_default(struct acpi_processor *pr) { - - /* Zero initialize all the C-states info. */ - memset(pr->power.states, 0, sizeof(pr->power.states)); - - /* set the first C-State to C1 */ - pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; - - /* the C0 state only exists as a filler in our array, - * and all processors need to support C1 */ + if (!pr->power.states[ACPI_STATE_C1].valid) { + /* set the first C-State to C1 */ + /* all processors need to support C1 */ + pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; + pr->power.states[ACPI_STATE_C1].valid = 1; + } + /* the C0 state only exists as a filler in our array */ pr->power.states[ACPI_STATE_C0].valid = 1; - pr->power.states[ACPI_STATE_C1].valid = 1; - return 0; } @@ -658,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) if (nocst) return -ENODEV; - current_count = 1; - - /* Zero initialize C2 onwards and prepare for fresh CST lookup */ - for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++) - memset(&(pr->power.states[i]), 0, - sizeof(struct acpi_processor_cx)); + current_count = 0; status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer); if (ACPI_FAILURE(status)) { @@ -718,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) continue; - cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ? - 0 : reg->address; - /* There should be an easy way to extract an integer... */ obj = (union acpi_object *)&(element->package.elements[1]); if (obj->type != ACPI_TYPE_INTEGER) continue; cx.type = obj->integer.value; - - if ((cx.type != ACPI_STATE_C1) && - (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) - continue; - - if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3)) - continue; + /* + * Some buggy BIOSes won't list C1 in _CST - + * Let acpi_processor_get_power_info_default() handle them later + */ + if (i == 1 && cx.type != ACPI_STATE_C1) + current_count++; + + cx.address = reg->address; + cx.index = current_count + 1; + + cx.space_id = ACPI_CSTATE_SYSTEMIO; + if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { + if (acpi_processor_ffh_cstate_probe + (pr->id, &cx, reg) == 0) { + cx.space_id = ACPI_CSTATE_FFH; + } else if (cx.type != ACPI_STATE_C1) { + /* + * C1 is a special case where FIXED_HARDWARE + * can be handled in non-MWAIT way as well. + * In that case, save this _CST entry info. + * That is, we retain space_id of SYSTEM_IO for + * halt based C1. + * Otherwise, ignore this info and continue. + */ + continue; + } + } obj = (union acpi_object *)&(element->package.elements[2]); if (obj->type != ACPI_TYPE_INTEGER) @@ -938,12 +957,18 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) /* NOTE: the idle thread may not be running while calling * this function */ - /* Adding C1 state */ - acpi_processor_get_power_info_default_c1(pr); + /* Zero initialize all the C-states info. */ + memset(pr->power.states, 0, sizeof(pr->power.states)); + result = acpi_processor_get_power_info_cst(pr); if (result == -ENODEV) acpi_processor_get_power_info_fadt(pr); + if (result) + return result; + + acpi_processor_get_power_info_default(pr); + pr->power.count = acpi_processor_power_verify(pr); /* diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h index c5472be6f3a..e72bfdd887f 100644 --- a/include/acpi/pdc_intel.h +++ b/include/acpi/pdc_intel.h @@ -13,6 +13,7 @@ #define ACPI_PDC_SMP_C_SWCOORD (0x0040) #define ACPI_PDC_SMP_T_SWCOORD (0x0080) #define ACPI_PDC_C_C1_FFH (0x0100) +#define ACPI_PDC_C_C2C3_FFH (0x0200) #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ ACPI_PDC_C_C1_HALT | \ @@ -23,8 +24,10 @@ ACPI_PDC_SMP_P_SWCOORD | \ ACPI_PDC_P_FFH) -#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ - ACPI_PDC_SMP_C1PT | \ - ACPI_PDC_C_C1_HALT) +#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ + ACPI_PDC_SMP_C1PT | \ + ACPI_PDC_C_C1_HALT | \ + ACPI_PDC_C_C1_FFH | \ + ACPI_PDC_C_C2C3_FFH) #endif /* __PDC_INTEL_H__ */ diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 9dd5b75961f..7798d2a9f79 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -29,6 +29,9 @@ #define DOMAIN_COORD_TYPE_SW_ANY 0xfd #define DOMAIN_COORD_TYPE_HW_ALL 0xfe +#define ACPI_CSTATE_SYSTEMIO (0) +#define ACPI_CSTATE_FFH (1) + /* Power Management */ struct acpi_processor_cx; @@ -58,6 +61,8 @@ struct acpi_processor_cx { u8 valid; u8 type; u32 address; + u8 space_id; + u8 index; u32 latency; u32 latency_ticks; u32 power; @@ -206,6 +211,9 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr); #ifdef ARCH_HAS_POWER_INIT void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, unsigned int cpu); +int acpi_processor_ffh_cstate_probe(unsigned int cpu, + struct acpi_processor_cx *cx, struct acpi_power_register *reg); +void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate); #else static inline void acpi_processor_power_init_bm_check(struct acpi_processor_flags @@ -214,6 +222,16 @@ static inline void acpi_processor_power_init_bm_check(struct flags->bm_check = 1; return; } +static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu, + struct acpi_processor_cx *cx, struct acpi_power_register *reg) +{ + return -1; +} +static inline void acpi_processor_ffh_cstate_enter( + struct acpi_processor_cx *cstate) +{ + return; +} #endif /* in processor_perflib.c */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 2277127696d..e0ddca94d50 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -306,6 +306,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx) : :"a" (eax), "c" (ecx)); } +extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); + /* from system description table in BIOS. Mostly for MCA use, but others may find it useful. */ extern unsigned int machine_id; diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index de9c3147ee4..cef17e0f828 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -475,6 +475,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx) : :"a" (eax), "c" (ecx)); } +extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); + #define stack_current() \ ({ \ struct thread_info *ti; \ -- GitLab From d7a76e4cb3b4469b1eccb6204c053e3ebcd4c196 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 5 Sep 2006 12:12:24 -0400 Subject: [PATCH 1185/1619] 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(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e5d79636285..a0dcbad97c4 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 88b5dfd8ee1..2b0c955590f 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*/ -- GitLab From 7c6db5e51227761f42c6ac8260753f5c24dc1dde Mon Sep 17 00:00:00 2001 From: "Denis M. Sadykov" Date: Tue, 26 Sep 2006 19:50:33 +0400 Subject: [PATCH 1186/1619] ACPI: EC: Remove unnecessary delay added by previous transation patch. Remove unnecessary delay (50 ms) while reading data from EC in interrupt mode. Signed-off-by: Alexey Y. Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 103 ++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 53 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a0dcbad97c4..b6f935d0c3a 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -100,7 +100,7 @@ union acpi_ec { struct acpi_generic_address command_addr; struct acpi_generic_address data_addr; unsigned long global_lock; - unsigned int expect_event; + u8 expect_event; atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ atomic_t pending_gpe; struct semaphore sem; @@ -121,7 +121,7 @@ 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_intr_wait(union acpi_ec *ec, u8 event); static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, const u8 *wdata, unsigned wdata_len, u8 *rdata, unsigned rdata_len); @@ -161,6 +161,22 @@ static u32 acpi_ec_read_status(union acpi_ec *ec) return status; } +static int acpi_ec_check_status(u32 status, u8 event) { + + switch (event) { + case ACPI_EC_EVENT_OBF: + if (status & ACPI_EC_FLAG_OBF) + return 1; + case ACPI_EC_EVENT_IBE: + if (!(status & ACPI_EC_FLAG_IBF)) + return 1; + default: + break; + } + + return 0; +} + static int acpi_ec_wait(union acpi_ec *ec, u8 event) { if (acpi_ec_poll_mode) @@ -203,47 +219,28 @@ static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event) return -ETIME; } -static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event) -{ - int result = 0; +static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event) +{ + long time_left; ec->intr.expect_event = event; - smp_mb(); - switch (event) { - case ACPI_EC_EVENT_IBE: - if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) { + if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { ec->intr.expect_event = 0; return 0; - } - break; - default: - break; } - result = wait_event_timeout(ec->intr.wait, - !ec->intr.expect_event, - msecs_to_jiffies(ACPI_EC_DELAY)); + time_left = wait_event_timeout(ec->intr.wait, !ec->intr.expect_event, + msecs_to_jiffies(ACPI_EC_DELAY)); ec->intr.expect_event = 0; - smp_mb(); - - /* - * Verify that the event in question has actually happened by - * querying EC status. Do the check even if operation timed-out - * to make sure that we did not miss interrupt. - */ - switch (event) { - case ACPI_EC_EVENT_OBF: - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) - return 0; - break; - - case ACPI_EC_EVENT_IBE: - if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) - return 0; - break; + if (time_left <= 0) { + if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { + return 0; + } + } else { + return 0; } return -ETIME; @@ -293,7 +290,7 @@ int acpi_ec_leave_burst_mode(union acpi_ec *ec) goto end; acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); - } + } atomic_set(&ec->intr.leaving_burst, 1); return 0; end: @@ -333,32 +330,32 @@ static int acpi_ec_transaction_unlocked(union acpi_ec *ec, u8 command, acpi_hw_low_level_write(8, command, &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - return result; - - for (; wdata_len > 0; wdata_len --) { - - acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr); + for (; wdata_len > 0; wdata_len --) { + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (result) + return result; - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - return result; + acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr); } + if (command == ACPI_EC_COMMAND_WRITE) { + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (result) + return result; + } - for (; rdata_len > 0; rdata_len --) { - u32 d; + for (; rdata_len > 0; rdata_len --) { + u32 d; - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) - return result; + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (result) + return result; - acpi_hw_low_level_read(8, &d, &ec->common.data_addr); - *(rdata++) = (u8) d; - } + acpi_hw_low_level_read(8, &d, &ec->common.data_addr); + *(rdata++) = (u8) d; + } - return 0; + return 0; } static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, -- GitLab From 703959d47e887a29dc58123c05aa0ffcbbfa131d Mon Sep 17 00:00:00 2001 From: "Denis M. Sadykov" Date: Tue, 26 Sep 2006 19:50:33 +0400 Subject: [PATCH 1187/1619] ACPI: EC: Remove unused variables and duplicated code Signed-off-by: Alexey Y. Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 711 +++++++++++++++++----------------------------- 1 file changed, 253 insertions(+), 458 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index b6f935d0c3a..c816b4eab50 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -45,203 +45,162 @@ ACPI_MODULE_NAME("acpi_ec") #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" + +/* EC status register */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ -#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ -#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ -#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ -#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ -#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ -#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ + +/* EC commands */ #define ACPI_EC_COMMAND_READ 0x80 #define ACPI_EC_COMMAND_WRITE 0x81 #define ACPI_EC_BURST_ENABLE 0x82 #define ACPI_EC_BURST_DISABLE 0x83 #define ACPI_EC_COMMAND_QUERY 0x84 -#define EC_POLL 0xFF -#define EC_INTR 0x00 + +/* EC events */ +enum { + ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ + ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ +}; + +#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ +#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ +#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ +#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ + +enum { + EC_INTR = 1, /* Output buffer full */ + EC_POLL, /* Input buffer empty */ +}; + static int acpi_ec_remove(struct acpi_device *device, int type); static int acpi_ec_start(struct acpi_device *device); static int acpi_ec_stop(struct acpi_device *device, int type); -static int acpi_ec_intr_add(struct acpi_device *device); -static int acpi_ec_poll_add(struct acpi_device *device); +static int acpi_ec_add(struct acpi_device *device); static struct acpi_driver acpi_ec_driver = { .name = ACPI_EC_DRIVER_NAME, .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { - .add = acpi_ec_intr_add, + .add = acpi_ec_add, .remove = acpi_ec_remove, .start = acpi_ec_start, .stop = acpi_ec_stop, }, }; -union acpi_ec { - struct { - u32 mode; - acpi_handle handle; - unsigned long uid; - unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; - unsigned long global_lock; - } common; - - struct { - u32 mode; - acpi_handle handle; - unsigned long uid; - unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; - unsigned long global_lock; - u8 expect_event; - atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ - atomic_t pending_gpe; - struct semaphore sem; - wait_queue_head_t wait; - } intr; - - struct { - u32 mode; - acpi_handle handle; - unsigned long uid; - unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; - unsigned long global_lock; - struct semaphore sem; - } poll; +struct acpi_ec { + acpi_handle handle; + unsigned long uid; + unsigned long gpe_bit; + struct acpi_generic_address status_addr; + struct acpi_generic_address command_addr; + struct acpi_generic_address data_addr; + unsigned long global_lock; + struct semaphore sem; + unsigned int expect_event; + atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ + wait_queue_head_t wait; }; -static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); -static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event); -static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, +/* If we find an EC via the ECDT, we need to keep a ptr to its context */ +static struct acpi_ec *ec_ecdt; + +/* External interfaces use first EC only, so remember */ +static struct acpi_device *first_ec; +static int acpi_ec_mode = EC_INTR; + +static int acpi_ec_poll_transaction(struct 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, +static int acpi_ec_intr_transaction(struct 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); static u32 acpi_ec_gpe_intr_handler(void *data); -static acpi_status __init -acpi_fake_ecdt_poll_callback(acpi_handle handle, - u32 Level, void *context, void **retval); - -static acpi_status __init -acpi_fake_ecdt_intr_callback(acpi_handle handle, - u32 Level, void *context, void **retval); - -static int __init acpi_ec_poll_get_real_ecdt(void); -static int __init acpi_ec_intr_get_real_ecdt(void); -/* If we find an EC via the ECDT, we need to keep a ptr to its context */ -static union acpi_ec *ec_ecdt; - -/* External interfaces use first EC only, so remember */ -static struct acpi_device *first_ec; -static int acpi_ec_poll_mode = EC_INTR; /* -------------------------------------------------------------------------- Transaction Management -------------------------------------------------------------------------- */ -static u32 acpi_ec_read_status(union acpi_ec *ec) +static u32 acpi_ec_read_status(struct acpi_ec *ec) { u32 status = 0; - acpi_hw_low_level_read(8, &status, &ec->common.status_addr); + acpi_hw_low_level_read(8, &status, &ec->status_addr); return status; } -static int acpi_ec_check_status(u32 status, u8 event) { - - switch (event) { - case ACPI_EC_EVENT_OBF: - if (status & ACPI_EC_FLAG_OBF) - return 1; - case ACPI_EC_EVENT_IBE: - if (!(status & ACPI_EC_FLAG_IBF)) - return 1; - default: - break; - } +static u32 acpi_ec_read_data(struct acpi_ec *ec) +{ + u32 data = 0; - return 0; + acpi_hw_low_level_read(8, &data, &ec->data_addr); + return data; } -static int acpi_ec_wait(union acpi_ec *ec, u8 event) +static void acpi_ec_write_cmd(struct acpi_ec *ec, u32 command) { - if (acpi_ec_poll_mode) - return acpi_ec_poll_wait(ec, event); - else - return acpi_ec_intr_wait(ec, event); + acpi_hw_low_level_write(8, command, &ec->command_addr); } -static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event) +static void acpi_ec_write_data(struct acpi_ec *ec, u32 data) { - u32 acpi_ec_status = 0; - u32 i = ACPI_EC_UDELAY_COUNT; + acpi_hw_low_level_write(8, data, &ec->data_addr); +} - if (!ec) - return -EINVAL; +static int acpi_ec_check_status(u32 status, u8 event) { - /* Poll the EC status register waiting for the event to occur. */ switch (event) { - case ACPI_EC_EVENT_OBF: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, - &ec->common.status_addr); - if (acpi_ec_status & ACPI_EC_FLAG_OBF) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i > 0); + case ACPI_EC_EVENT_OBF_1: + if (status & ACPI_EC_FLAG_OBF) + return 1; break; - case ACPI_EC_EVENT_IBE: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, - &ec->common.status_addr); - if (!(acpi_ec_status & ACPI_EC_FLAG_IBF)) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i > 0); + case ACPI_EC_EVENT_IBF_0: + if (!(status & ACPI_EC_FLAG_IBF)) + return 1; break; default: - return -EINVAL; + break; } - return -ETIME; + return 0; } -static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event) +static int acpi_ec_wait(struct acpi_ec *ec, u8 event) { - long time_left; - - ec->intr.expect_event = event; + int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0; + long time_left; + ec->expect_event = event; if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { - ec->intr.expect_event = 0; - return 0; + ec->expect_event = 0; + return 0; } - time_left = wait_event_timeout(ec->intr.wait, !ec->intr.expect_event, - msecs_to_jiffies(ACPI_EC_DELAY)); - - ec->intr.expect_event = 0; - if (time_left <= 0) { - if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { + do { + if (acpi_ec_mode == EC_POLL) { + udelay(ACPI_EC_UDELAY); + } else { + time_left = wait_event_timeout(ec->wait, + !ec->expect_event, + msecs_to_jiffies(ACPI_EC_DELAY)); + if (time_left > 0) { + ec->expect_event = 0; return 0; + } } - } else { - return 0; - } + if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { + ec->expect_event = 0; + return 0; + } + } while (--i > 0); + + ec->expect_event = 0; return -ETIME; } @@ -251,64 +210,63 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, u8 event) * Note: samsung nv5000 doesn't work with ec burst mode. * http://bugzilla.kernel.org/show_bug.cgi?id=4980 */ -int acpi_ec_enter_burst_mode(union acpi_ec *ec) +int acpi_ec_enter_burst_mode(struct acpi_ec *ec) { u32 tmp = 0; - int status = 0; + u32 status = 0; status = acpi_ec_read_status(ec); if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (status) goto end; - acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr); + acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); + tmp = acpi_ec_read_data(ec); if (tmp != 0x90) { /* Burst ACK byte */ return -EINVAL; } } - atomic_set(&ec->intr.leaving_burst, 0); + atomic_set(&ec->leaving_burst, 0); return 0; - end: - ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode"); + end: + ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); return -1; } -int acpi_ec_leave_burst_mode(union acpi_ec *ec) +int acpi_ec_leave_burst_mode(struct acpi_ec *ec) { - int status = 0; + u32 status = 0; status = acpi_ec_read_status(ec); if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){ - status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if(status) goto end; - acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); - acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE); + acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); } - atomic_set(&ec->intr.leaving_burst, 1); + atomic_set(&ec->leaving_burst, 1); return 0; -end: - ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"); + end: + ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode")); return -1; } #endif /* ACPI_FUTURE_USAGE */ -static int acpi_ec_transaction(union acpi_ec *ec, u8 command, +static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, const u8 *wdata, unsigned wdata_len, u8 *rdata, unsigned rdata_len) { - if (acpi_ec_poll_mode) + if (acpi_ec_mode == EC_POLL) return acpi_ec_poll_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); else 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) +static int acpi_ec_read(struct acpi_ec *ec, u8 address, u32 * data) { int result; u8 d; @@ -316,30 +274,30 @@ static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) *data = d; return result; } -static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data) +static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { u8 wdata[2] = { address, data }; return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, wdata, 2, NULL, 0); } -static int acpi_ec_transaction_unlocked(union acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) +static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { int result; - acpi_hw_low_level_write(8, command, &ec->common.command_addr); + acpi_ec_write_cmd(ec, command); for (; wdata_len > 0; wdata_len --) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (result) return result; - acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr); + acpi_ec_write_data(ec, *(wdata++)); } if (command == ACPI_EC_COMMAND_WRITE) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (result) return result; } @@ -347,18 +305,18 @@ static int acpi_ec_transaction_unlocked(union acpi_ec *ec, u8 command, for (; rdata_len > 0; rdata_len --) { u32 d; - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); if (result) return result; - acpi_hw_low_level_read(8, &d, &ec->common.data_addr); + d = acpi_ec_read_data(ec); *(rdata++) = (u8) d; } return 0; } -static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, +static int acpi_ec_poll_transaction(struct acpi_ec *ec, u8 command, const u8 *wdata, unsigned wdata_len, u8 *rdata, unsigned rdata_len) { @@ -372,13 +330,13 @@ static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, if (rdata) memset(rdata, 0, rdata_len); - if (ec->common.global_lock) { + if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) return -ENODEV; } - if (down_interruptible(&ec->poll.sem)) { + if (down_interruptible(&ec->sem)) { result = -ERESTARTSYS; goto end_nosem; } @@ -386,16 +344,16 @@ static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, result = acpi_ec_transaction_unlocked(ec, command, wdata, wdata_len, rdata, rdata_len); - up(&ec->poll.sem); + up(&ec->sem); end_nosem: - if (ec->common.global_lock) + if (ec->global_lock) acpi_release_global_lock(glk); return result; } -static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command, +static int acpi_ec_intr_transaction(struct acpi_ec *ec, u8 command, const u8 *wdata, unsigned wdata_len, u8 *rdata, unsigned rdata_len) { @@ -408,18 +366,18 @@ static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command, if (rdata) memset(rdata, 0, rdata_len); - if (ec->common.global_lock) { + if (ec->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); + down(&ec->sem); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (status) { - printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); + ACPI_EXCEPTION((AE_INFO, status, "read EC, IB not empty")); goto end; } @@ -428,9 +386,9 @@ static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command, rdata, rdata_len); end: - up(&ec->intr.sem); + up(&ec->sem); - if (ec->common.global_lock) + if (ec->global_lock) acpi_release_global_lock(glk); return status; @@ -441,7 +399,7 @@ end: */ int ec_read(u8 addr, u8 * val) { - union acpi_ec *ec; + struct acpi_ec *ec; int err; u32 temp_data; @@ -463,7 +421,7 @@ EXPORT_SYMBOL(ec_read); int ec_write(u8 addr, u8 val) { - union acpi_ec *ec; + struct acpi_ec *ec; int err; if (!first_ec) @@ -482,7 +440,7 @@ extern int ec_transaction(u8 command, const u8 *wdata, unsigned wdata_len, u8 *rdata, unsigned rdata_len) { - union acpi_ec *ec; + struct acpi_ec *ec; if (!first_ec) return -ENODEV; @@ -494,7 +452,7 @@ extern int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); -static int acpi_ec_query(union acpi_ec *ec, u32 * data) { +static int acpi_ec_query(struct acpi_ec *ec, u32 * data) { int result; u8 d; @@ -529,7 +487,7 @@ union acpi_ec_query_data { static void acpi_ec_gpe_query(void *ec_cxt) { - if (acpi_ec_poll_mode) + if (acpi_ec_mode == EC_POLL) acpi_ec_gpe_poll_query(ec_cxt); else acpi_ec_gpe_intr_query(ec_cxt); @@ -537,7 +495,7 @@ static void acpi_ec_gpe_query(void *ec_cxt) static void acpi_ec_gpe_poll_query(void *ec_cxt) { - union acpi_ec *ec = (union acpi_ec *)ec_cxt; + struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; u32 value = 0; static char object_name[5] = { '_', 'Q', '0', '0', '\0' }; const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -548,11 +506,11 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt) if (!ec_cxt) goto end; - if (down_interruptible (&ec->poll.sem)) { + if (down_interruptible (&ec->sem)) { return; } - acpi_hw_low_level_read(8, &value, &ec->common.command_addr); - up(&ec->poll.sem); + value = acpi_ec_read_status(ec); + up(&ec->sem); /* TBD: Implement asynch events! * NOTE: All we care about are EC-SCI's. Other EC events are @@ -571,14 +529,14 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); - acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL); + acpi_evaluate_object(ec->handle, object_name, NULL, NULL); end: - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } static void acpi_ec_gpe_intr_query(void *ec_cxt) { - union acpi_ec *ec = (union acpi_ec *)ec_cxt; + struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; u32 value; int result = -ENODATA; static char object_name[5] = { '_', 'Q', '0', '0', '\0' }; @@ -598,15 +556,14 @@ static void acpi_ec_gpe_intr_query(void *ec_cxt) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); - acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL); + acpi_evaluate_object(ec->handle, object_name, NULL, NULL); end: - atomic_dec(&ec->intr.pending_gpe); return; } static u32 acpi_ec_gpe_handler(void *data) { - if (acpi_ec_poll_mode) + if (acpi_ec_mode == EC_POLL) return acpi_ec_gpe_poll_handler(data); else return acpi_ec_gpe_intr_handler(data); @@ -614,12 +571,12 @@ static u32 acpi_ec_gpe_handler(void *data) static u32 acpi_ec_gpe_poll_handler(void *data) { acpi_status status = AE_OK; - union acpi_ec *ec = (union acpi_ec *)data; + struct acpi_ec *ec = (struct acpi_ec *)data; if (!ec) return ACPI_INTERRUPT_NOT_HANDLED; - acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); + acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec); @@ -632,39 +589,38 @@ static u32 acpi_ec_gpe_intr_handler(void *data) { acpi_status status = AE_OK; u32 value; - union acpi_ec *ec = (union acpi_ec *)data; + struct acpi_ec *ec = (struct acpi_ec *)data; if (!ec) return ACPI_INTERRUPT_NOT_HANDLED; - acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); + acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR); value = acpi_ec_read_status(ec); - switch (ec->intr.expect_event) { - case ACPI_EC_EVENT_OBF: + switch (ec->expect_event) { + case ACPI_EC_EVENT_OBF_1: if (!(value & ACPI_EC_FLAG_OBF)) break; - ec->intr.expect_event = 0; - wake_up(&ec->intr.wait); + ec->expect_event = 0; + wake_up(&ec->wait); break; - case ACPI_EC_EVENT_IBE: + case ACPI_EC_EVENT_IBF_0: if ((value & ACPI_EC_FLAG_IBF)) break; - ec->intr.expect_event = 0; - wake_up(&ec->intr.wait); + ec->expect_event = 0; + wake_up(&ec->wait); break; default: break; } if (value & ACPI_EC_FLAG_SCI) { - atomic_add(1, &ec->intr.pending_gpe); status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } @@ -695,7 +651,7 @@ acpi_ec_space_handler(u32 function, void *handler_context, void *region_context) { int result = 0; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; u64 temp = *value; acpi_integer f_v = 0; int i = 0; @@ -705,12 +661,10 @@ acpi_ec_space_handler(u32 function, return AE_BAD_PARAMETER; if (bit_width != 8 && acpi_strict) { - printk(KERN_WARNING PREFIX - "acpi_ec_space_handler: bit_width should be 8\n"); return AE_BAD_PARAMETER; } - ec = (union acpi_ec *)handler_context; + ec = (struct acpi_ec *)handler_context; next_byte: switch (function) { @@ -767,20 +721,20 @@ static struct proc_dir_entry *acpi_ec_dir; static int acpi_ec_read_info(struct seq_file *seq, void *offset) { - union acpi_ec *ec = (union acpi_ec *)seq->private; + struct acpi_ec *ec = (struct acpi_ec *)seq->private; if (!ec) goto end; seq_printf(seq, "gpe bit: 0x%02x\n", - (u32) ec->common.gpe_bit); + (u32) ec->gpe_bit); seq_printf(seq, "ports: 0x%02x, 0x%02x\n", - (u32) ec->common.status_addr.address, - (u32) ec->common.data_addr.address); + (u32) ec->status_addr.address, + (u32) ec->data_addr.address); seq_printf(seq, "use global lock: %s\n", - ec->common.global_lock ? "yes" : "no"); - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); + ec->global_lock ? "yes" : "no"); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); end: return 0; @@ -791,7 +745,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_ec_read_info, PDE(inode)->data); } -static const struct file_operations acpi_ec_info_ops = { +static struct file_operations acpi_ec_info_ops = { .open = acpi_ec_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -840,101 +794,35 @@ static int acpi_ec_remove_fs(struct acpi_device *device) Driver Interface -------------------------------------------------------------------------- */ -static int acpi_ec_poll_add(struct acpi_device *device) +static int acpi_ec_add(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) return -EINVAL; - ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); + ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec) return -ENOMEM; - memset(ec, 0, sizeof(union acpi_ec)); - - ec->common.handle = device->handle; - ec->common.uid = -1; - init_MUTEX(&ec->poll.sem); - strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_EC_CLASS); - acpi_driver_data(device) = ec; - - /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(ec->common.handle, "_GLK", NULL, - &ec->common.global_lock); - - /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: - http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ - if (ec_ecdt) { - acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, - ACPI_ADR_SPACE_EC, - &acpi_ec_space_handler); - - acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit, - &acpi_ec_gpe_handler); - - kfree(ec_ecdt); - } - - /* Get GPE bit assignment (EC events). */ - /* TODO: Add support for _GPE returning a package */ - status = - acpi_evaluate_integer(ec->common.handle, "_GPE", NULL, - &ec->common.gpe_bit); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit")); - result = -ENODEV; - goto end; + memset(ec, 0, sizeof(struct acpi_ec)); + + ec->handle = device->handle; + ec->uid = -1; + init_MUTEX(&ec->sem); + if (acpi_ec_mode == EC_INTR) { + atomic_set(&ec->leaving_burst, 1); + init_waitqueue_head(&ec->wait); } - - result = acpi_ec_add_fs(device); - if (result) - goto end; - - printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n", - acpi_device_name(device), acpi_device_bid(device), - (u32) ec->common.gpe_bit); - - if (!first_ec) - first_ec = device; - - end: - if (result) - kfree(ec); - - return result; -} -static int acpi_ec_intr_add(struct acpi_device *device) -{ - int result = 0; - acpi_status status = AE_OK; - union acpi_ec *ec = NULL; - - - if (!device) - return -EINVAL; - - ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); - if (!ec) - return -ENOMEM; - memset(ec, 0, sizeof(union acpi_ec)); - - ec->common.handle = device->handle; - ec->common.uid = -1; - atomic_set(&ec->intr.pending_gpe, 0); - atomic_set(&ec->intr.leaving_burst, 1); - init_MUTEX(&ec->intr.sem); - init_waitqueue_head(&ec->intr.wait); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(ec->common.handle, "_GLK", NULL, - &ec->common.global_lock); + acpi_evaluate_integer(ec->handle, "_GLK", NULL, + &ec->global_lock); /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ @@ -943,7 +831,7 @@ static int acpi_ec_intr_add(struct acpi_device *device) ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); - acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); kfree(ec_ecdt); @@ -952,10 +840,10 @@ static int acpi_ec_intr_add(struct acpi_device *device) /* Get GPE bit assignment (EC events). */ /* TODO: Add support for _GPE returning a package */ status = - acpi_evaluate_integer(ec->common.handle, "_GPE", NULL, - &ec->common.gpe_bit); + acpi_evaluate_integer(ec->handle, "_GPE", NULL, + &ec->gpe_bit); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n"); + ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment")); result = -ENODEV; goto end; } @@ -964,14 +852,14 @@ static int acpi_ec_intr_add(struct acpi_device *device) if (result) goto end; - printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", acpi_device_name(device), acpi_device_bid(device), - (u32) ec->common.gpe_bit); + (u32) ec->gpe_bit)); if (!first_ec) first_ec = device; - end: + end: if (result) kfree(ec); @@ -980,7 +868,7 @@ static int acpi_ec_intr_add(struct acpi_device *device) static int acpi_ec_remove(struct acpi_device *device, int type) { - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) @@ -998,7 +886,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type) static acpi_status acpi_ec_io_ports(struct acpi_resource *resource, void *context) { - union acpi_ec *ec = (union acpi_ec *)context; + struct acpi_ec *ec = (struct acpi_ec *)context; struct acpi_generic_address *addr; if (resource->type != ACPI_RESOURCE_TYPE_IO) { @@ -1010,10 +898,10 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context) * the second address region returned is the status/command * port. */ - if (ec->common.data_addr.register_bit_width == 0) { - addr = &ec->common.data_addr; - } else if (ec->common.command_addr.register_bit_width == 0) { - addr = &ec->common.command_addr; + if (ec->data_addr.register_bit_width == 0) { + addr = &ec->data_addr; + } else if (ec->command_addr.register_bit_width == 0) { + addr = &ec->command_addr; } else { return AE_CTRL_TERMINATE; } @@ -1029,7 +917,7 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context) static int acpi_ec_start(struct acpi_device *device) { acpi_status status = AE_OK; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) @@ -1043,39 +931,40 @@ static int acpi_ec_start(struct acpi_device *device) /* * Get I/O port addresses. Convert to GAS format. */ - status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS, + status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS, acpi_ec_io_ports, ec); if (ACPI_FAILURE(status) - || ec->common.command_addr.register_bit_width == 0) { - printk(KERN_ERR PREFIX "Error getting I/O port addresses\n"); + || ec->command_addr.register_bit_width == 0) { + ACPI_EXCEPTION((AE_INFO, status, + "Error getting I/O port addresses")); return -ENODEV; } - ec->common.status_addr = ec->common.command_addr; + ec->status_addr = ec->command_addr; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n", - (u32) ec->common.gpe_bit, - (u32) ec->common.command_addr.address, - (u32) ec->common.data_addr.address)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x", + (u32) ec->gpe_bit, + (u32) ec->command_addr.address, + (u32) ec->data_addr.address)); /* * Install GPE handler */ - status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit, + status = acpi_install_gpe_handler(NULL, ec->gpe_bit, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) { return -ENODEV; } - acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); + acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); - status = acpi_install_address_space_handler(ec->common.handle, + status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, &acpi_ec_space_setup, ec); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler); return -ENODEV; } @@ -1086,7 +975,7 @@ static int acpi_ec_start(struct acpi_device *device) static int acpi_ec_stop(struct acpi_device *device, int type) { acpi_status status = AE_OK; - union acpi_ec *ec = NULL; + struct acpi_ec *ec = NULL; if (!device) @@ -1094,14 +983,14 @@ static int acpi_ec_stop(struct acpi_device *device, int type) ec = acpi_driver_data(device); - status = acpi_remove_address_space_handler(ec->common.handle, + status = acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); if (ACPI_FAILURE(status)) return -ENODEV; status = - acpi_remove_gpe_handler(NULL, ec->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler); if (ACPI_FAILURE(status)) return -ENODEV; @@ -1113,76 +1002,33 @@ static acpi_status __init acpi_fake_ecdt_callback(acpi_handle handle, u32 Level, void *context, void **retval) { - - if (acpi_ec_poll_mode) - return acpi_fake_ecdt_poll_callback(handle, - Level, context, retval); - else - return acpi_fake_ecdt_intr_callback(handle, - Level, context, retval); -} - -static acpi_status __init -acpi_fake_ecdt_poll_callback(acpi_handle handle, - u32 Level, void *context, void **retval) -{ - acpi_status status; - - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - acpi_ec_io_ports, ec_ecdt); - if (ACPI_FAILURE(status)) - return status; - ec_ecdt->common.status_addr = ec_ecdt->common.command_addr; - - ec_ecdt->common.uid = -1; - acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid); - - status = - acpi_evaluate_integer(handle, "_GPE", NULL, - &ec_ecdt->common.gpe_bit); - if (ACPI_FAILURE(status)) - return status; - init_MUTEX(&ec_ecdt->poll.sem); - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.handle = handle; - - printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n", - (u32) ec_ecdt->common.gpe_bit, - (u32) ec_ecdt->common.command_addr.address, - (u32) ec_ecdt->common.data_addr.address); - - return AE_CTRL_TERMINATE; -} - -static acpi_status __init -acpi_fake_ecdt_intr_callback(acpi_handle handle, - u32 Level, void *context, void **retval) -{ acpi_status status; - init_MUTEX(&ec_ecdt->intr.sem); - init_waitqueue_head(&ec_ecdt->intr.wait); + init_MUTEX(&ec_ecdt->sem); + if (acpi_ec_mode == EC_INTR) { + init_waitqueue_head(&ec_ecdt->wait); + } status = acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_ec_io_ports, ec_ecdt); if (ACPI_FAILURE(status)) return status; - ec_ecdt->common.status_addr = ec_ecdt->common.command_addr; + ec_ecdt->status_addr = ec_ecdt->command_addr; - ec_ecdt->common.uid = -1; - acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid); + ec_ecdt->uid = -1; + acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); status = acpi_evaluate_integer(handle, "_GPE", NULL, - &ec_ecdt->common.gpe_bit); + &ec_ecdt->gpe_bit); if (ACPI_FAILURE(status)) return status; - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.handle = handle; + ec_ecdt->global_lock = TRUE; + ec_ecdt->handle = handle; - printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n", - (u32) ec_ecdt->common.gpe_bit, - (u32) ec_ecdt->common.command_addr.address, - (u32) ec_ecdt->common.data_addr.address); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02x, ports=0x%2x, 0x%2x", + (u32) ec_ecdt->gpe_bit, + (u32) ec_ecdt->command_addr.address, + (u32) ec_ecdt->data_addr.address)); return AE_CTRL_TERMINATE; } @@ -1202,14 +1048,14 @@ static int __init acpi_ec_fake_ecdt(void) acpi_status status; int ret = 0; - printk(KERN_INFO PREFIX "Try to make an fake ECDT\n"); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT")); - ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); + ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec_ecdt) { ret = -ENOMEM; goto error; } - memset(ec_ecdt, 0, sizeof(union acpi_ec)); + memset(ec_ecdt, 0, sizeof(struct acpi_ec)); status = acpi_get_devices(ACPI_EC_HID, acpi_fake_ecdt_callback, NULL, NULL); @@ -1217,23 +1063,15 @@ static int __init acpi_ec_fake_ecdt(void) kfree(ec_ecdt); ec_ecdt = NULL; ret = -ENODEV; + ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT")); goto error; } return 0; - error: - printk(KERN_ERR PREFIX "Can't make an fake ECDT\n"); + error: return ret; } static int __init acpi_ec_get_real_ecdt(void) -{ - if (acpi_ec_poll_mode) - return acpi_ec_poll_get_real_ecdt(); - else - return acpi_ec_intr_get_real_ecdt(); -} - -static int __init acpi_ec_poll_get_real_ecdt(void) { acpi_status status; struct acpi_table_ecdt *ecdt_ptr; @@ -1244,80 +1082,37 @@ static int __init acpi_ec_poll_get_real_ecdt(void) if (ACPI_FAILURE(status)) return -ENODEV; - printk(KERN_INFO PREFIX "Found ECDT\n"); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT")); /* * Generate a temporary ec context to use until the namespace is scanned */ - ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); + ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec_ecdt) return -ENOMEM; - memset(ec_ecdt, 0, sizeof(union acpi_ec)); - - ec_ecdt->common.command_addr = ecdt_ptr->ec_control; - ec_ecdt->common.status_addr = ecdt_ptr->ec_control; - ec_ecdt->common.data_addr = ecdt_ptr->ec_data; - ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit; - init_MUTEX(&ec_ecdt->poll.sem); - /* use the GL just to be safe */ - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.uid = ecdt_ptr->uid; + memset(ec_ecdt, 0, sizeof(struct acpi_ec)); - status = - acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle); - if (ACPI_FAILURE(status)) { - goto error; + init_MUTEX(&ec_ecdt->sem); + if (acpi_ec_mode == EC_INTR) { + init_waitqueue_head(&ec_ecdt->wait); } - - return 0; - error: - printk(KERN_ERR PREFIX "Could not use ECDT\n"); - kfree(ec_ecdt); - ec_ecdt = NULL; - - return -ENODEV; -} - -static int __init acpi_ec_intr_get_real_ecdt(void) -{ - acpi_status status; - struct acpi_table_ecdt *ecdt_ptr; - - status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &ecdt_ptr); - if (ACPI_FAILURE(status)) - return -ENODEV; - - printk(KERN_INFO PREFIX "Found ECDT\n"); - - /* - * Generate a temporary ec context to use until the namespace is scanned - */ - ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL); - if (!ec_ecdt) - return -ENOMEM; - memset(ec_ecdt, 0, sizeof(union acpi_ec)); - - init_MUTEX(&ec_ecdt->intr.sem); - init_waitqueue_head(&ec_ecdt->intr.wait); - ec_ecdt->common.command_addr = ecdt_ptr->ec_control; - ec_ecdt->common.status_addr = ecdt_ptr->ec_control; - ec_ecdt->common.data_addr = ecdt_ptr->ec_data; - ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit; + ec_ecdt->command_addr = ecdt_ptr->ec_control; + ec_ecdt->status_addr = ecdt_ptr->ec_control; + ec_ecdt->data_addr = ecdt_ptr->ec_data; + ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; /* use the GL just to be safe */ - ec_ecdt->common.global_lock = TRUE; - ec_ecdt->common.uid = ecdt_ptr->uid; + ec_ecdt->global_lock = TRUE; + ec_ecdt->uid = ecdt_ptr->uid; status = - acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle); + acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); if (ACPI_FAILURE(status)) { goto error; } return 0; - error: - printk(KERN_ERR PREFIX "Could not use ECDT\n"); + error: + ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); kfree(ec_ecdt); ec_ecdt = NULL; @@ -1342,14 +1137,14 @@ int __init acpi_ec_ecdt_probe(void) /* * Install GPE handler */ - status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit, + status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec_ecdt); if (ACPI_FAILURE(status)) { goto error; } - acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR); + acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, @@ -1357,7 +1152,7 @@ int __init acpi_ec_ecdt_probe(void) &acpi_ec_space_setup, ec_ecdt); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); goto error; } @@ -1365,7 +1160,7 @@ int __init acpi_ec_ecdt_probe(void) return 0; error: - printk(KERN_ERR PREFIX "Could not use ECDT\n"); + ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); kfree(ec_ecdt); ec_ecdt = NULL; @@ -1424,13 +1219,13 @@ static int __init acpi_ec_set_intr_mode(char *str) return 0; if (intr) { - acpi_ec_poll_mode = EC_INTR; - acpi_ec_driver.ops.add = acpi_ec_intr_add; + acpi_ec_mode = EC_INTR; } else { - acpi_ec_poll_mode = EC_POLL; - acpi_ec_driver.ops.add = acpi_ec_poll_add; + acpi_ec_mode = EC_POLL; } - printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling"); + acpi_ec_driver.ops.add = acpi_ec_add; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling")); + return 1; } -- GitLab From 3576cf619b73d850f5b21375609645f221e6270f Mon Sep 17 00:00:00 2001 From: "Denis M. Sadykov" Date: Tue, 26 Sep 2006 19:50:33 +0400 Subject: [PATCH 1188/1619] ACPI: EC: Unify poll and interrupt mode transaction functions Signed-off-by: Alexey Y. Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 110 ++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 81 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c816b4eab50..9c7fce6a42e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -112,12 +112,6 @@ static struct acpi_ec *ec_ecdt; static struct acpi_device *first_ec; static int acpi_ec_mode = EC_INTR; -static int acpi_ec_poll_transaction(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len); -static int acpi_ec_intr_transaction(struct 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); @@ -257,32 +251,9 @@ int acpi_ec_leave_burst_mode(struct acpi_ec *ec) } #endif /* ACPI_FUTURE_USAGE */ -static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) -{ - if (acpi_ec_mode == EC_POLL) - return acpi_ec_poll_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); - else - return acpi_ec_intr_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); -} -static int acpi_ec_read(struct 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(struct acpi_ec *ec, u8 address, u8 data) -{ - u8 wdata[2] = { address, data }; - return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, wdata, 2, NULL, 0); -} - static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { int result; @@ -292,9 +263,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (result) return result; - acpi_ec_write_data(ec, *(wdata++)); - } + } if (command == ACPI_EC_COMMAND_WRITE) { result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); @@ -316,46 +286,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, return 0; } -static int acpi_ec_poll_transaction(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) -{ - acpi_status status = AE_OK; - int result; - u32 glk = 0; - - if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) - return -EINVAL; - - if (rdata) - memset(rdata, 0, rdata_len); - - if (ec->global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } - - if (down_interruptible(&ec->sem)) { - result = -ERESTARTSYS; - goto end_nosem; - } - - result = acpi_ec_transaction_unlocked(ec, command, - wdata, wdata_len, - rdata, rdata_len); - up(&ec->sem); - -end_nosem: - if (ec->global_lock) - acpi_release_global_lock(glk); - - return result; -} - -static int acpi_ec_intr_transaction(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) +static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { int status; u32 glk; @@ -371,13 +304,11 @@ static int acpi_ec_intr_transaction(struct acpi_ec *ec, u8 command, if (ACPI_FAILURE(status)) return -ENODEV; } - - WARN_ON(in_interrupt()); down(&ec->sem); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (status) { - ACPI_EXCEPTION((AE_INFO, status, "read EC, IB not empty")); + printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); goto end; } @@ -394,6 +325,23 @@ end: return status; } +static int acpi_ec_read(struct 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(struct acpi_ec *ec, u8 address, u8 data) +{ + u8 wdata[2] = { address, data }; + return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, + wdata, 2, NULL, 0); +} + /* * Externally callable EC access functions. For now, assume 1 EC only */ @@ -447,13 +395,13 @@ extern int ec_transaction(u8 command, ec = acpi_driver_data(first_ec); - return acpi_ec_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); + return acpi_ec_transaction(ec, command, wdata, + wdata_len, rdata, rdata_len); } -EXPORT_SYMBOL(ec_transaction); - -static int acpi_ec_query(struct acpi_ec *ec, u32 * data) { - int result; +static int acpi_ec_query(struct acpi_ec *ec, u32 * data) +{ + int result; u8 d; if (!ec || !data) -- GitLab From 8e0341ba791cc72c643340b0d8119141ae5a80c5 Mon Sep 17 00:00:00 2001 From: "Denis M. Sadykov" Date: Tue, 26 Sep 2006 19:50:33 +0400 Subject: [PATCH 1189/1619] ACPI: EC: Unify poll and interrupt gpe handlers Signed-off-by: Alexey Y. Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 107 ++++++---------------------------------------- 1 file changed, 12 insertions(+), 95 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9c7fce6a42e..0f232e719da 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -112,11 +112,6 @@ static struct acpi_ec *ec_ecdt; static struct acpi_device *first_ec; static int acpi_ec_mode = EC_INTR; -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); -static u32 acpi_ec_gpe_intr_handler(void *data); - /* -------------------------------------------------------------------------- Transaction Management -------------------------------------------------------------------------- */ @@ -428,20 +423,12 @@ static int acpi_ec_query(struct acpi_ec *ec, u32 * data) Event Management -------------------------------------------------------------------------- */ -union acpi_ec_query_data { +struct acpi_ec_query_data { acpi_handle handle; u8 data; }; static void acpi_ec_gpe_query(void *ec_cxt) -{ - if (acpi_ec_mode == EC_POLL) - acpi_ec_gpe_poll_query(ec_cxt); - else - acpi_ec_gpe_intr_query(ec_cxt); -} - -static void acpi_ec_gpe_poll_query(void *ec_cxt) { struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; u32 value = 0; @@ -454,18 +441,8 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt) if (!ec_cxt) goto end; - if (down_interruptible (&ec->sem)) { - return; - } value = acpi_ec_read_status(ec); - up(&ec->sem); - /* TBD: Implement asynch events! - * NOTE: All we care about are EC-SCI's. Other EC events are - * handled via polling (yuck!). This is because some systems - * treat EC-SCIs as level (versus EDGE!) triggered, preventing - * a purely interrupt-driven approach (grumble, grumble). - */ if (!(value & ACPI_EC_FLAG_SCI)) goto end; @@ -475,96 +452,36 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt) object_name[2] = hex[((value >> 4) & 0x0F)]; object_name[3] = hex[(value & 0x0F)]; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); end: acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } -static void acpi_ec_gpe_intr_query(void *ec_cxt) -{ - struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; - u32 value; - int result = -ENODATA; - static char object_name[5] = { '_', 'Q', '0', '0', '\0' }; - const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - - - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) - result = acpi_ec_query(ec, &value); - - if (result) - goto end; - - object_name[2] = hex[((value >> 4) & 0x0F)]; - object_name[3] = hex[(value & 0x0F)]; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); - - acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - end: - return; -} static u32 acpi_ec_gpe_handler(void *data) -{ - if (acpi_ec_mode == EC_POLL) - return acpi_ec_gpe_poll_handler(data); - else - return acpi_ec_gpe_intr_handler(data); -} -static u32 acpi_ec_gpe_poll_handler(void *data) -{ - acpi_status status = AE_OK; - struct acpi_ec *ec = (struct acpi_ec *)data; - - if (!ec) - return ACPI_INTERRUPT_NOT_HANDLED; - - acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); - - status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec); - - if (status == AE_OK) - return ACPI_INTERRUPT_HANDLED; - else - return ACPI_INTERRUPT_NOT_HANDLED; -} -static u32 acpi_ec_gpe_intr_handler(void *data) { acpi_status status = AE_OK; u32 value; + u8 exec_mode; struct acpi_ec *ec = (struct acpi_ec *)data; - if (!ec) - return ACPI_INTERRUPT_NOT_HANDLED; - acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR); value = acpi_ec_read_status(ec); - switch (ec->expect_event) { - case ACPI_EC_EVENT_OBF_1: - if (!(value & ACPI_EC_FLAG_OBF)) - break; - ec->expect_event = 0; - wake_up(&ec->wait); - break; - case ACPI_EC_EVENT_IBF_0: - if ((value & ACPI_EC_FLAG_IBF)) - break; - ec->expect_event = 0; - wake_up(&ec->wait); - break; - default: - break; + if (acpi_ec_mode == EC_INTR) { + if (acpi_ec_check_status(value, ec->expect_event)) { + ec->expect_event = 0; + wake_up(&ec->wait); + } + exec_mode = OSL_EC_BURST_HANDLER; + } else { + exec_mode = OSL_EC_POLL_HANDLER; } if (value & ACPI_EC_FLAG_SCI) { - status = acpi_os_execute(OSL_EC_BURST_HANDLER, - acpi_ec_gpe_query, ec); + status = acpi_os_execute(exec_mode, acpi_ec_gpe_query, ec); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } -- GitLab From 6ffb221a82de962f31034b45d945e203a0f0500f Mon Sep 17 00:00:00 2001 From: "Denis M. Sadykov" Date: Tue, 26 Sep 2006 19:50:33 +0400 Subject: [PATCH 1190/1619] ACPI: EC: Simplify acpi_hw_low_level*() with inb()/outb(). Simplify acpi_hw_low_level_xxx() functions to inb() and outb(). Signed-off-by: Alexey Y. Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 124 +++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 79 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 0f232e719da..ae05e8c1148 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -72,7 +72,7 @@ enum { enum { EC_INTR = 1, /* Output buffer full */ - EC_POLL, /* Input buffer empty */ + EC_POLL, /* Input buffer empty */ }; static int acpi_ec_remove(struct acpi_device *device, int type); @@ -91,22 +91,20 @@ static struct acpi_driver acpi_ec_driver = { .stop = acpi_ec_stop, }, }; + +/* If we find an EC via the ECDT, we need to keep a ptr to its context */ struct acpi_ec { acpi_handle handle; unsigned long uid; unsigned long gpe_bit; - struct acpi_generic_address status_addr; - struct acpi_generic_address command_addr; - struct acpi_generic_address data_addr; + unsigned long command_addr; + unsigned long data_addr; unsigned long global_lock; struct semaphore sem; unsigned int expect_event; atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ wait_queue_head_t wait; -}; - -/* If we find an EC via the ECDT, we need to keep a ptr to its context */ -static struct acpi_ec *ec_ecdt; +} *ec_ecdt; /* External interfaces use first EC only, so remember */ static struct acpi_device *first_ec; @@ -116,34 +114,28 @@ static int acpi_ec_mode = EC_INTR; Transaction Management -------------------------------------------------------------------------- */ -static u32 acpi_ec_read_status(struct acpi_ec *ec) +static inline u8 acpi_ec_read_status(struct acpi_ec *ec) { - u32 status = 0; - - acpi_hw_low_level_read(8, &status, &ec->status_addr); - return status; + return inb(ec->command_addr); } -static u32 acpi_ec_read_data(struct acpi_ec *ec) +static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { - u32 data = 0; - - acpi_hw_low_level_read(8, &data, &ec->data_addr); - return data; + return inb(ec->data_addr); } -static void acpi_ec_write_cmd(struct acpi_ec *ec, u32 command) +static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) { - acpi_hw_low_level_write(8, command, &ec->command_addr); + outb(command, ec->command_addr); } -static void acpi_ec_write_data(struct acpi_ec *ec, u32 data) +static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) { - acpi_hw_low_level_write(8, data, &ec->data_addr); + outb(data, ec->data_addr); } -static int acpi_ec_check_status(u32 status, u8 event) { - +static int acpi_ec_check_status(u8 status, u8 event) +{ switch (event) { case ACPI_EC_EVENT_OBF_1: if (status & ACPI_EC_FLAG_OBF) @@ -201,8 +193,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, u8 event) */ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) { - u32 tmp = 0; - u32 status = 0; + u8 tmp = 0; + u8 status = 0; status = acpi_ec_read_status(ec); @@ -227,7 +219,7 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) int acpi_ec_leave_burst_mode(struct acpi_ec *ec) { - u32 status = 0; + u8 status = 0; status = acpi_ec_read_status(ec); @@ -268,14 +260,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, } for (; rdata_len > 0; rdata_len --) { - u32 d; - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); if (result) return result; - d = acpi_ec_read_data(ec); - *(rdata++) = (u8) d; + *(rdata++) = acpi_ec_read_data(ec); } return 0; @@ -320,7 +309,7 @@ end: return status; } -static int acpi_ec_read(struct acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) { int result; u8 d; @@ -330,6 +319,7 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u32 * data) *data = d; return result; } + static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { u8 wdata[2] = { address, data }; @@ -340,11 +330,11 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) /* * Externally callable EC access functions. For now, assume 1 EC only */ -int ec_read(u8 addr, u8 * val) +int ec_read(u8 addr, u8 *val) { struct acpi_ec *ec; int err; - u32 temp_data; + u8 temp_data; if (!first_ec) return -ENODEV; @@ -394,7 +384,7 @@ extern int ec_transaction(u8 command, wdata_len, rdata, rdata_len); } -static int acpi_ec_query(struct acpi_ec *ec, u32 * data) +static int acpi_ec_query(struct acpi_ec *ec, u8 *data) { int result; u8 d; @@ -431,14 +421,10 @@ struct acpi_ec_query_data { static void acpi_ec_gpe_query(void *ec_cxt) { struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; - u32 value = 0; - static char object_name[5] = { '_', 'Q', '0', '0', '\0' }; - const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - + u8 value = 0; + static char object_name[8]; - if (!ec_cxt) + if (!ec) goto end; value = acpi_ec_read_status(ec); @@ -449,8 +435,7 @@ static void acpi_ec_gpe_query(void *ec_cxt) if (acpi_ec_query(ec, &value)) goto end; - object_name[2] = hex[((value >> 4) & 0x0F)]; - object_name[3] = hex[(value & 0x0F)]; + snprintf(object_name, 8, "_Q%2.2X", value); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); @@ -463,8 +448,7 @@ static void acpi_ec_gpe_query(void *ec_cxt) static u32 acpi_ec_gpe_handler(void *data) { acpi_status status = AE_OK; - u32 value; - u8 exec_mode; + u8 value; struct acpi_ec *ec = (struct acpi_ec *)data; acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR); @@ -475,13 +459,10 @@ static u32 acpi_ec_gpe_handler(void *data) ec->expect_event = 0; wake_up(&ec->wait); } - exec_mode = OSL_EC_BURST_HANDLER; - } else { - exec_mode = OSL_EC_POLL_HANDLER; } if (value & ACPI_EC_FLAG_SCI) { - status = acpi_os_execute(exec_mode, acpi_ec_gpe_query, ec); + status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } @@ -535,7 +516,7 @@ acpi_ec_space_handler(u32 function, switch (function) { case ACPI_READ: temp = 0; - result = acpi_ec_read(ec, (u8) address, (u32 *) & temp); + result = acpi_ec_read(ec, (u8) address, (u8 *) &temp); break; case ACPI_WRITE: result = acpi_ec_write(ec, (u8) address, (u8) temp); @@ -595,8 +576,8 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset) seq_printf(seq, "gpe bit: 0x%02x\n", (u32) ec->gpe_bit); seq_printf(seq, "ports: 0x%02x, 0x%02x\n", - (u32) ec->status_addr.address, - (u32) ec->data_addr.address); + (u32) ec->command_addr, + (u32) ec->data_addr); seq_printf(seq, "use global lock: %s\n", ec->global_lock ? "yes" : "no"); acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); @@ -752,7 +733,6 @@ static acpi_status acpi_ec_io_ports(struct acpi_resource *resource, void *context) { struct acpi_ec *ec = (struct acpi_ec *)context; - struct acpi_generic_address *addr; if (resource->type != ACPI_RESOURCE_TYPE_IO) { return AE_OK; @@ -763,19 +743,14 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context) * the second address region returned is the status/command * port. */ - if (ec->data_addr.register_bit_width == 0) { - addr = &ec->data_addr; - } else if (ec->command_addr.register_bit_width == 0) { - addr = &ec->command_addr; + if (ec->data_addr == 0) { + ec->data_addr = resource->data.io.minimum; + } else if (ec->command_addr == 0) { + ec->command_addr = resource->data.io.minimum; } else { return AE_CTRL_TERMINATE; } - addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO; - addr->register_bit_width = 8; - addr->register_bit_offset = 0; - addr->address = resource->data.io.minimum; - return AE_OK; } @@ -798,19 +773,14 @@ static int acpi_ec_start(struct acpi_device *device) */ status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS, acpi_ec_io_ports, ec); - if (ACPI_FAILURE(status) - || ec->command_addr.register_bit_width == 0) { + if (ACPI_FAILURE(status) || ec->command_addr == 0) { ACPI_EXCEPTION((AE_INFO, status, "Error getting I/O port addresses")); return -ENODEV; } - ec->status_addr = ec->command_addr; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x", - (u32) ec->gpe_bit, - (u32) ec->command_addr.address, - (u32) ec->data_addr.address)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", + ec->gpe_bit, ec->command_addr, ec->data_addr)); /* * Install GPE handler @@ -877,7 +847,6 @@ acpi_fake_ecdt_callback(acpi_handle handle, acpi_ec_io_ports, ec_ecdt); if (ACPI_FAILURE(status)) return status; - ec_ecdt->status_addr = ec_ecdt->command_addr; ec_ecdt->uid = -1; acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); @@ -890,10 +859,8 @@ acpi_fake_ecdt_callback(acpi_handle handle, ec_ecdt->global_lock = TRUE; ec_ecdt->handle = handle; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02x, ports=0x%2x, 0x%2x", - (u32) ec_ecdt->gpe_bit, - (u32) ec_ecdt->command_addr.address, - (u32) ec_ecdt->data_addr.address)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", + ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr)); return AE_CTRL_TERMINATE; } @@ -961,9 +928,8 @@ static int __init acpi_ec_get_real_ecdt(void) if (acpi_ec_mode == EC_INTR) { init_waitqueue_head(&ec_ecdt->wait); } - ec_ecdt->command_addr = ecdt_ptr->ec_control; - ec_ecdt->status_addr = ecdt_ptr->ec_control; - ec_ecdt->data_addr = ecdt_ptr->ec_data; + ec_ecdt->command_addr = ecdt_ptr->ec_control.address; + ec_ecdt->data_addr = ecdt_ptr->ec_data.address; ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; /* use the GL just to be safe */ ec_ecdt->global_lock = TRUE; -- GitLab From ab9e43c640b2b7d6e296fc39dd8cbcb96f9ae393 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 3 Oct 2006 22:49:00 -0400 Subject: [PATCH 1191/1619] ACPI: EC: export ec_transaction() for msi-laptop driver Signed-off-by: Lennart Poettering Signed-off-by: Len Brown --- drivers/acpi/ec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ae05e8c1148..e6d4b084dca 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -384,6 +384,8 @@ extern int ec_transaction(u8 command, wdata_len, rdata, rdata_len); } +EXPORT_SYMBOL(ec_transaction); + static int acpi_ec_query(struct acpi_ec *ec, u8 *data) { int result; -- GitLab From 8c4c731a89ea6458001f48033f8988447736fb38 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 Oct 2006 01:27:02 -0400 Subject: [PATCH 1192/1619] MSI S270 Laptop support: backlight, wlan, bluetooth states Create a driver to support the platform-specific features of MSI S270 laptops (and maybe other MSI laptops). This driver implements a backlight device for controlling LCD brightness (/sys/class/backlight/msi-laptop-bl/). In addition it allows access to the WLAN and Bluetooth states through a platform driver (/sys/devices/platform/msi-laptop-pf/). Signed-off-by: Lennart Poettering Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- MAINTAINERS | 7 + drivers/misc/Kconfig | 19 ++ drivers/misc/Makefile | 1 + drivers/misc/msi-laptop.c | 395 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 422 insertions(+) create mode 100644 drivers/misc/msi-laptop.c diff --git a/MAINTAINERS b/MAINTAINERS index 1b5430a49fd..a2b6d9fa350 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1998,6 +1998,13 @@ M: rubini@ipvvis.unipv.it L: linux-kernel@vger.kernel.org S: Maintained +MSI LAPTOP SUPPORT +P: Lennart Poettering +M: mzxreary@0pointer.de +L: https://tango.0pointer.de/mailman/listinfo/s270-linux +W: http://0pointer.de/lennart/tchibo.html +S: Maintained + MTRR AND SIMILAR SUPPORT [i386] P: Richard Gooch M: rgooch@atnf.csiro.au diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3df0e7a07c4..fa7acc2c5c6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -57,4 +57,23 @@ config TIFM_7XX1 To compile this driver as a module, choose M here: the module will be called tifm_7xx1. +config MSI_LAPTOP + tristate "MSI Laptop Extras" + depends on X86 + depends on ACPI_EC + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by MSI (MICRO-STAR + INTERNATIONAL): + + MSI MegaBook S270 (MS-1013) + Cytron/TCM/Medion/Tchibo MD96100/SAM2000 + + It adds support for Bluetooth, WLAN and LCD brightness control. + + More information about this driver is available at + . + + If you have an MSI S270 laptop, say Y or M here. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d65ece76095..9a91c1ee849 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -5,6 +5,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ +obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c new file mode 100644 index 00000000000..fdb7153f442 --- /dev/null +++ b/drivers/misc/msi-laptop.c @@ -0,0 +1,395 @@ +/*-*-linux-c-*-*/ + +/* + Copyright (C) 2006 Lennart Poettering + + 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. + */ + +/* + * msi-laptop.c - MSI S270 laptop support. This laptop is sold under + * various brands, including "Cytron/TCM/Medion/Tchibo MD96100". + * + * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/: + * + * lcd_level - Screen brightness: contains a single integer in the + * range 0..8. (rw) + * + * auto_brightness - Enable automatic brightness control: contains + * either 0 or 1. If set to 1 the hardware adjusts the screen + * brightness automatically when the power cord is + * plugged/unplugged. (rw) + * + * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro) + * + * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1 + * Please note that this file is constantly 0 if no Bluetooth + * hardware is available. (ro) + * + * In addition to these platform device attributes the driver + * registers itself in the Linux backlight control subsystem and is + * available to userspace under /sys/class/backlight/msi-laptop-bl/. + * + * This driver might work on other laptops produced by MSI. If you + * want to try it you can pass force=1 as argument to the module which + * will force it to load even when the DMI data doesn't identify the + * laptop as MSI S270. YMMV. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSI_DRIVER_VERSION "0.5" + +#define MSI_LCD_LEVEL_MAX 9 + +#define MSI_EC_COMMAND_WIRELESS 0x10 +#define MSI_EC_COMMAND_LCD_LEVEL 0x11 + +static int force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); + +static int auto_brightness; +module_param(auto_brightness, int, 0); +MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); + +/* Hardware access */ + +static int set_lcd_level(int level) +{ + u8 buf[2]; + + if (level < 0 || level >= MSI_LCD_LEVEL_MAX) + return -EINVAL; + + buf[0] = 0x80; + buf[1] = (u8) (level*31); + + return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0); +} + +static int get_lcd_level(void) +{ + u8 wdata = 0, rdata; + int result; + + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); + if (result < 0) + return result; + + return (int) rdata / 31; +} + +static int get_auto_brightness(void) +{ + u8 wdata = 4, rdata; + int result; + + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); + if (result < 0) + return result; + + return !!(rdata & 8); +} + +static int set_auto_brightness(int enable) +{ + u8 wdata[2], rdata; + int result; + + wdata[0] = 4; + + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1); + if (result < 0) + return result; + + wdata[0] = 0x84; + wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); + + return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0); +} + +static int get_wireless_state(int *wlan, int *bluetooth) +{ + u8 wdata = 0, rdata; + int result; + + result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1); + if (result < 0) + return -1; + + if (wlan) + *wlan = !!(rdata & 8); + + if (bluetooth) + *bluetooth = !!(rdata & 128); + + return 0; +} + +/* Backlight device stuff */ + +static int bl_get_brightness(struct backlight_device *b) +{ + return get_lcd_level(); +} + + +static int bl_update_status(struct backlight_device *b) +{ + return set_lcd_level(b->props->brightness); +} + +static struct backlight_properties msibl_props = { + .owner = THIS_MODULE, + .get_brightness = bl_get_brightness, + .update_status = bl_update_status, + .max_brightness = MSI_LCD_LEVEL_MAX-1, +}; + +static struct backlight_device *msibl_device; + +/* Platform device */ + +static ssize_t show_wlan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret, enabled; + + ret = get_wireless_state(&enabled, NULL); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", enabled); +} + +static ssize_t show_bluetooth(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret, enabled; + + ret = get_wireless_state(NULL, &enabled); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", enabled); +} + +static ssize_t show_lcd_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_lcd_level(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t store_lcd_level(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + int level, ret; + + if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX)) + return -EINVAL; + + ret = set_lcd_level(level); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t show_auto_brightness(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_auto_brightness(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t store_auto_brightness(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + int enable, ret; + + if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1))) + return -EINVAL; + + ret = set_auto_brightness(enable); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); +static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness); +static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); +static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); + +static struct attribute *msipf_attributes[] = { + &dev_attr_lcd_level.attr, + &dev_attr_auto_brightness.attr, + &dev_attr_bluetooth.attr, + &dev_attr_wlan.attr, + NULL +}; + +static struct attribute_group msipf_attribute_group = { + .attrs = msipf_attributes +}; + +static struct platform_driver msipf_driver = { + .driver = { + .name = "msi-laptop-pf", + .owner = THIS_MODULE, + } +}; + +static struct platform_device *msipf_device; + +/* Initialization */ + +static struct dmi_system_id __initdata msi_dmi_table[] = { + { + .ident = "MSI S270", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"), + } + }, + { + .ident = "Medion MD96100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"), + DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"), + } + }, + { } +}; + + +static int __init msi_init(void) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + + if (!force && !dmi_check_system(msi_dmi_table)) + return -ENODEV; + + if (auto_brightness < 0 || auto_brightness > 2) + return -EINVAL; + + /* Register backlight stuff */ + + msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props); + if (IS_ERR(msibl_device)) + return PTR_ERR(msibl_device); + + ret = platform_driver_register(&msipf_driver); + if (ret) + goto fail_backlight; + + /* Register platform stuff */ + + msipf_device = platform_device_alloc("msi-laptop-pf", -1); + if (!msipf_device) { + ret = -ENOMEM; + goto fail_platform_driver; + } + + ret = platform_device_add(msipf_device); + if (ret) + goto fail_platform_device1; + + ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group); + if (ret) + goto fail_platform_device2; + + /* Disable automatic brightness control by default because + * this module was probably loaded to do brightness control in + * software. */ + + if (auto_brightness != 2) + set_auto_brightness(auto_brightness); + + printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); + + return 0; + +fail_platform_device2: + + platform_device_del(msipf_device); + +fail_platform_device1: + + platform_device_put(msipf_device); + +fail_platform_driver: + + platform_driver_unregister(&msipf_driver); + +fail_backlight: + + backlight_device_unregister(msibl_device); + + return ret; +} + +static void __exit msi_cleanup(void) +{ + + sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); + platform_device_unregister(msipf_device); + platform_driver_unregister(&msipf_driver); + backlight_device_unregister(msibl_device); + + /* Enable automatic brightness control again */ + if (auto_brightness != 2) + set_auto_brightness(1); + + printk(KERN_INFO "msi-laptop: driver unloaded.\n"); +} + +module_init(msi_init); +module_exit(msi_cleanup); + +MODULE_AUTHOR("Lennart Poettering"); +MODULE_DESCRIPTION("MSI Laptop Support"); +MODULE_VERSION(MSI_DRIVER_VERSION); +MODULE_LICENSE("GPL"); -- GitLab From fcfc638c6b1345b6646523dbab0065b36a868ffc Mon Sep 17 00:00:00 2001 From: "Alexey Y. Starikovskiy" Date: Tue, 26 Sep 2006 04:18:16 -0400 Subject: [PATCH 1193/1619] ACPI: Remove deferred execution from global lock acquire wakeup path On acquiring the ACPI global lock, if there were sleepers on the lock, we used to use acpi_os_execute() to defer a thread which would signal sleepers. Now just signal the semaphore directly. http://bugzilla.kernel.org/show_bug.cgi?id=5534#c159 Signed-off-by: Len Brown --- drivers/acpi/events/evmisc.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 6eef4efddcf..ee2a10bf907 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -342,20 +342,8 @@ static u32 acpi_ev_global_lock_handler(void *context) if (acquired) { /* Got the lock, now wake all threads waiting for it */ - acpi_gbl_global_lock_acquired = TRUE; - - /* Run the Global Lock thread which will signal all waiting threads */ - - status = - acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER, - acpi_ev_global_lock_thread, context); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not queue Global Lock thread")); - - return (ACPI_INTERRUPT_NOT_HANDLED); - } + acpi_ev_global_lock_thread(context); } return (ACPI_INTERRUPT_HANDLED); -- GitLab From 37605a6900f6b4d886d995751fcfeef88c4e462c Mon Sep 17 00:00:00 2001 From: "Alexey Y. Starikovskiy" Date: Tue, 26 Sep 2006 04:20:47 -0400 Subject: [PATCH 1194/1619] ACPI: created a dedicated workqueue for notify() execution http://bugzilla.kernel.org/show_bug.cgi?id=5534#c160 Signed-off-by: Len Brown --- drivers/acpi/osl.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 068fe4f100b..c84286cbbe2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -73,6 +73,7 @@ static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; +static struct workqueue_struct *kacpi_notify_wq; acpi_status acpi_os_initialize(void) { @@ -91,8 +92,9 @@ acpi_status acpi_os_initialize1(void) return AE_NULL_ENTRY; } kacpid_wq = create_singlethread_workqueue("kacpid"); + kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify"); BUG_ON(!kacpid_wq); - + BUG_ON(!kacpi_notify_wq); return AE_OK; } @@ -104,6 +106,7 @@ acpi_status acpi_os_terminate(void) } destroy_workqueue(kacpid_wq); + destroy_workqueue(kacpi_notify_wq); return AE_OK; } @@ -566,10 +569,7 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ static void acpi_os_execute_deferred(void *context) { - struct acpi_os_dpc *dpc = NULL; - - - dpc = (struct acpi_os_dpc *)context; + struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context; if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); return; @@ -604,14 +604,12 @@ acpi_status acpi_os_execute(acpi_execute_type type, struct acpi_os_dpc *dpc; struct work_struct *task; - ACPI_FUNCTION_TRACE("os_queue_for_execution"); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); if (!function) - return_ACPI_STATUS(AE_BAD_PARAMETER); + return AE_BAD_PARAMETER; /* * Allocate/initialize DPC structure. Note that this memory will be @@ -624,26 +622,20 @@ acpi_status acpi_os_execute(acpi_execute_type type, * from the same memory. */ - dpc = - kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct), - GFP_ATOMIC); + dpc = kmalloc(sizeof(struct acpi_os_dpc) + + sizeof(struct work_struct), GFP_ATOMIC); if (!dpc) - return_ACPI_STATUS(AE_NO_MEMORY); - + return 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)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Call to queue_work() failed.\n")); - kfree(dpc); + if (!queue_work((type == OSL_NOTIFY_HANDLER)? + kacpi_notify_wq : kacpid_wq, task)) { status = AE_ERROR; + kfree(dpc); } - - return_ACPI_STATUS(status); + return status; } EXPORT_SYMBOL(acpi_os_execute); -- GitLab From 2fe6dffabb06bfa0591c8c490b092b458fba1f06 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Thu, 31 Aug 2006 14:15:54 +0200 Subject: [PATCH 1195/1619] ACPI: ibm_acpi: delete obsolete documentation As this module is now part of the kernel tree, there is no need for instructions on how to download it and build an external module. Signed-off-by: Pavel Machek Signed-off-by: Len Brown --- Documentation/ibm-acpi.txt | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt index 00b8cf3999c..e50595bfd8e 100644 --- a/Documentation/ibm-acpi.txt +++ b/Documentation/ibm-acpi.txt @@ -53,40 +53,7 @@ Installation If you are compiling this driver as included in the Linux kernel sources, simply enable the CONFIG_ACPI_IBM option (Power Management / -ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes -how to install this driver when downloaded from the web site. - -First, you need to get a kernel with ACPI support up and running. -Please refer to http://acpi.sourceforge.net/ for help with this -step. How successful you will be depends a lot on you ThinkPad model, -the kernel you are using and any additional patches applied. The -kernel provided with your distribution may not be good enough. I -needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get -ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not -be supported at all. - -Assuming you have the basic ACPI support working (e.g. you can see the -/proc/acpi directory), follow the following steps to install this -driver: - - - unpack the archive: - - tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y - - - compile the driver: - - make - - - install the module in your kernel modules directory: - - make install - - - load the module: - - modprobe ibm_acpi - -After loading the module, check the "dmesg" output for any error messages. - +ACPI / IBM ThinkPad Laptop Extras). Features -------- -- GitLab From 786f18c666d7202a86a8aa42a98783b115fe8739 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 23 Aug 2006 23:18:06 -0400 Subject: [PATCH 1196/1619] ACPI: fix potential OOPS in power driver with CONFIG_ACPI_DEBUG device was set to null and used before set in a debug printk Signed-off-by: Dmitry Torokhov Signed-off-by: Len Brown --- drivers/acpi/power.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index fec225d1b6b..fe67a8af520 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -216,10 +216,8 @@ static int acpi_power_off_device(acpi_handle handle) { int result = 0; acpi_status status = AE_OK; - struct acpi_device *device = NULL; struct acpi_power_resource *resource = NULL; - result = acpi_power_get_context(handle, &resource); if (result) return result; @@ -230,13 +228,13 @@ static int acpi_power_off_device(acpi_handle handle) if (resource->references) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is still in use, dereferencing\n", - device->pnp.bus_id)); + resource->device->pnp.bus_id)); return 0; } if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n", - device->pnp.bus_id)); + resource->device->pnp.bus_id)); return 0; } @@ -251,8 +249,7 @@ static int acpi_power_off_device(acpi_handle handle) return -ENOEXEC; /* Update the power resource's _device_ power state */ - device = resource->device; - device->power.state = ACPI_STATE_D3; + resource->device->power.state = ACPI_STATE_D3; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n", resource->name)); -- GitLab From 168a328f30e9d1a8bc6ff55c0501e0bdc08bee60 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 24 Aug 2006 00:36:19 -0400 Subject: [PATCH 1197/1619] ACPI: acpi_pci_link_set() can allocate with either GFP_ATOMIC or GFP_KERNEL acpi_pci_link_set() allocates both with interrupts on and with interrupts off (resume-time), so check interrupts and decide on GFP_ATOMIC or GFP_KERNEL at run-time. Signed-off-by: Jiri Kosina Signed-off-by: Len Brown --- drivers/acpi/pci_link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 7f3e7e77e79..d53bd9878ca 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -307,7 +307,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) if (!link || !irq) return -EINVAL; - resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC); + resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); if (!resource) return -ENOMEM; -- GitLab From f4d2e2d87eac0338884b2c26f6bafed115dbac5e Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 14 Sep 2006 17:16:22 -0400 Subject: [PATCH 1198/1619] ACPI: update comments in motherboard.c Signed-off-by: Len Brown --- drivers/acpi/motherboard.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c index ec6b7f9ede3..2e17ec75af0 100644 --- a/drivers/acpi/motherboard.c +++ b/drivers/acpi/motherboard.c @@ -48,6 +48,12 @@ ACPI_MODULE_NAME("acpi_motherboard") * the io ports if they really know they can use it, while * still preventing hotplug PCI devices from using it. */ + +/* + * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01 + * and PNP0C02, redundant with acpi_reserve_io_ranges(). + * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP. + */ static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data) { struct resource *requested_res = NULL; -- GitLab From 7af8b66004fa827958b4871112e59a07db5b3f6b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 10 Oct 2006 14:20:31 -0700 Subject: [PATCH 1199/1619] ACPI: fix section for CPU init functions The ACPI processor init functions should be marked as __cpuinit as they use structures marked with __cpuinitdata. Signed-off-by: Pierre Ossman Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 2 +- drivers/acpi/processor_idle.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b13d64415b7..1908e0d2022 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -519,7 +519,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr) static void *processor_device_array[NR_CPUS]; -static int acpi_processor_start(struct acpi_device *device) +static int __cpuinit acpi_processor_start(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0a395fca843..8537c429a02 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1105,7 +1105,7 @@ static struct notifier_block acpi_processor_latency_notifier = { .notifier_call = acpi_processor_latency_notify, }; -int acpi_processor_power_init(struct acpi_processor *pr, +int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; -- GitLab From a790b323fb1b73f9388426bf3b96f153d1c90d2c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 10 Oct 2006 14:20:32 -0700 Subject: [PATCH 1200/1619] ACPI: fix printk format warnings Fix printk format warnings in drivers/acpi: drivers/acpi/tables/tbget.c:326: warning: format '%X' expects type 'unsigned int', but argument 5 has type 'long unsigned int' drivers/acpi/tables/tbrsdt.c:189: warning: format '%X' expects type 'unsigned int', but argument 5 has type 'long unsigned int' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/tables/tbget.c | 2 +- drivers/acpi/tables/tbrsdt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 7856db759af..11e2d4454e0 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -324,7 +324,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, if (header->length < sizeof(struct acpi_table_header)) { ACPI_ERROR((AE_INFO, - "Table length (%X) is smaller than minimum (%X)", + "Table length (%X) is smaller than minimum (%zX)", header->length, sizeof(struct acpi_table_header))); return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 0ad3dbb9ebc..86a5fca9b73 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -187,7 +187,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) if (table_ptr->length < sizeof(struct acpi_table_header)) { ACPI_ERROR((AE_INFO, - "RSDT/XSDT length (%X) is smaller than minimum (%X)", + "RSDT/XSDT length (%X) is smaller than minimum (%zX)", table_ptr->length, sizeof(struct acpi_table_header))); -- GitLab From 281ea49b0c294649a6de47a6f8fbe5611137726b Mon Sep 17 00:00:00 2001 From: Kimball Murray Date: Tue, 10 Oct 2006 14:20:33 -0700 Subject: [PATCH 1201/1619] ACPI: SCI interrupt source override The Linux group at Stratus Technologies has come across an issue with SCI routing under ACPI. We were bitten by this when we made an x86_64 platform whose BIOS provides an Interrupt Source Override for the SCI itself. Apparently the override has no effect for the System Control Interrupt, and this appears to be because of the way the SCI is setup in the ACPI code. It does not handle the case where busirq != gsi. The code that sets up the SCI routing assumes that bus irq == global irq. So there is simply no provision for telling it otherwise. The attached patch provides this mechanism. This patch provided by David Bulkow, was tested on an i386 platform, which does not use the SCI override, and also on an x86_64 platform which does use an override. Signed-off-by: David Bulkow Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 92f79cdd9a4..ab974ff9707 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -332,7 +332,7 @@ acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end) /* * Parse Interrupt Source Override for the ACPI SCI */ -static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) +static void acpi_sci_ioapic_setup(u32 bus_irq, u32 gsi, u16 polarity, u16 trigger) { if (trigger == 0) /* compatible SCI trigger is level */ trigger = 3; @@ -352,13 +352,13 @@ static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) * If GSI is < 16, this will update its flags, * else it will create a new mp_irqs[] entry. */ - mp_override_legacy_irq(gsi, polarity, trigger, gsi); + mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); /* * stash over-ride to indicate we've been here * and for later update of acpi_fadt */ - acpi_sci_override_gsi = gsi; + acpi_sci_override_gsi = bus_irq; return; } @@ -376,7 +376,7 @@ acpi_parse_int_src_ovr(acpi_table_entry_header * header, acpi_table_print_madt_entry(header); if (intsrc->bus_irq == acpi_fadt.sci_int) { - acpi_sci_ioapic_setup(intsrc->global_irq, + acpi_sci_ioapic_setup(intsrc->bus_irq, intsrc->global_irq, intsrc->flags.polarity, intsrc->flags.trigger); return 0; @@ -879,7 +879,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) * pretend we got one so we can set the SCI flags. */ if (!acpi_sci_override_gsi) - acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + acpi_sci_ioapic_setup(acpi_fadt.sci_int, acpi_fadt.sci_int, 0, 0); /* Fill in identity legacy mapings where no override */ mp_config_acpi_legacy_irqs(); -- GitLab From 6311f0dac006032b82e3556874a1e18b31e80de2 Mon Sep 17 00:00:00 2001 From: Darren Jenkins Date: Tue, 10 Oct 2006 14:20:35 -0700 Subject: [PATCH 1202/1619] ACPI: asus_acpi: fix proc files parsing ICC complains about a "Pointless comparsion of unsigned interger with zero" @ line 760 & 808 of asus_acpi.c parse_arg() mentioned below returns -E but it's copied into unsigned variable... Signed-off-by: Darren Jenkins Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 46 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index ebc033f87e7..33eaca108f4 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -567,11 +567,11 @@ static int write_led(const char __user * buffer, unsigned long count, char *ledname, int ledmask, int invert) { - int value; + int rv, value; int led_out = 0; - count = parse_arg(buffer, count, &value); - if (count > 0) + rv = parse_arg(buffer, count, &value); + if (rv > 0) led_out = value ? 1 : 0; hotk->status = @@ -584,7 +584,7 @@ write_led(const char __user * buffer, unsigned long count, printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n", ledname); - return count; + return rv; } /* @@ -619,20 +619,20 @@ static int proc_write_ledd(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) { + rv = parse_arg(buffer, count, &value); + if (rv > 0) { if (!write_acpi_int (hotk->handle, hotk->methods->mt_ledd, value, NULL)) printk(KERN_WARNING "Asus ACPI: LED display write failed\n"); else hotk->ledd_status = (u32) value; - } else if (count < 0) + } else if (rv < 0) printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); - return count; + return rv; } /* @@ -773,12 +773,12 @@ static int proc_write_lcd(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) + rv = parse_arg(buffer, count, &value); + if (rv > 0) set_lcd_state(value); - return count; + return rv; } static int read_brightness(void) @@ -842,18 +842,18 @@ static int proc_write_brn(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) { + rv = parse_arg(buffer, count, &value); + if (rv > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ set_brightness(value); - } else if (count < 0) { + } else if (rv < 0) { printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } - return count; + return rv; } static void set_display(int value) @@ -892,15 +892,15 @@ static int proc_write_disp(struct file *file, const char __user * buffer, unsigned long count, void *data) { - int value; + int rv, value; - count = parse_arg(buffer, count, &value); - if (count > 0) + rv = parse_arg(buffer, count, &value); + if (rv > 0) set_display(value); - else if (count < 0) + else if (rv < 0) printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); - return count; + return rv; } typedef int (proc_readfunc) (char *page, char **start, off_t off, int count, -- GitLab From 6df05702f97f99e038ab817f4466386f6255f58d Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Oct 2006 14:20:36 -0700 Subject: [PATCH 1203/1619] ACPI: asus_acpi: don't printk on writing garbage to proc files This reporting is useless (we errno anyway). Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 33eaca108f4..c7ac9297a20 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -629,9 +629,7 @@ proc_write_ledd(struct file *file, const char __user * buffer, "Asus ACPI: LED display write failed\n"); else hotk->ledd_status = (u32) value; - } else if (rv < 0) - printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); - + } return rv; } @@ -849,10 +847,7 @@ proc_write_brn(struct file *file, const char __user * buffer, value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ set_brightness(value); - } else if (rv < 0) { - printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } - return rv; } @@ -897,9 +892,6 @@ proc_write_disp(struct file *file, const char __user * buffer, rv = parse_arg(buffer, count, &value); if (rv > 0) set_display(value); - else if (rv < 0) - printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); - return rv; } -- GitLab From aeb1104814e1177b865eec4f4b364602f5fcb6d1 Mon Sep 17 00:00:00 2001 From: Eiichiro Oiwa Date: Mon, 2 Oct 2006 19:18:03 +0400 Subject: [PATCH 1204/1619] ACPICA: Fix incorrect handling of PCI Express Root Bridge _HID I could not get correct PCI Express bus number from the structure of acpi_object_extra. I always get zero as bus number regardless of bus location. I found that there is incorrect comparison with _HID (PNP0A08) in acpi/events/evrgnini.c and PCI Express _BBN method always fail. Therefore, we always get zero as PCI Express bus number. http://bugzilla.kernel.org/show_bug.cgi?id=7145 Signed-off-by: Bob Moore Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/events/evrgnini.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 5b3c7a85eb9..203d1359190 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, if (! (ACPI_STRNCMP (object_hID.value, PCI_ROOT_HID_STRING, - sizeof(PCI_ROOT_HID_STRING)) - || - !(ACPI_STRNCMP - (object_hID.value, - PCI_EXPRESS_ROOT_HID_STRING, - sizeof(PCI_EXPRESS_ROOT_HID_STRING))))) - { + sizeof(PCI_ROOT_HID_STRING))) + || + !(ACPI_STRNCMP + (object_hID.value, + PCI_EXPRESS_ROOT_HID_STRING, + sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { /* Install a handler for this PCI root bridge */ -- GitLab From 34c4415ab857dc6d51db08d62bcd45d4b8513bb6 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 10 Oct 2006 14:20:41 -0700 Subject: [PATCH 1205/1619] ACPI: check battery status on resume for un/plug events during sleep Add ->resume method to the ACPI battery handler to check if the battery state has changed during sleep. If yes, update the ACPI internal data structures for benefit of /proc/acpi/battery/. Signed-off-by: Jiri Kosina Cc: Stefan Seyfried Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/battery.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9810e2a55d0..026e40755cd 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); static int acpi_battery_add(struct acpi_device *device); static int acpi_battery_remove(struct acpi_device *device, int type); +static int acpi_battery_resume(struct acpi_device *device, int status); static struct acpi_driver acpi_battery_driver = { .name = ACPI_BATTERY_DRIVER_NAME, @@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_driver = { .ids = ACPI_BATTERY_HID, .ops = { .add = acpi_battery_add, + .resume = acpi_battery_resume, .remove = acpi_battery_remove, }, }; @@ -753,6 +755,18 @@ static int acpi_battery_remove(struct acpi_device *device, int type) return 0; } +/* this is needed to learn about changes made in suspended state */ +static int acpi_battery_resume(struct acpi_device *device, int state) +{ + struct acpi_battery *battery; + + if (!device) + return -EINVAL; + + battery = device->driver_data; + return acpi_battery_check(battery); +} + static int __init acpi_battery_init(void) { int result; -- GitLab From 69f0304e174c765c624d75b79c35e49b7ba67ed4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 5 Oct 2006 13:22:42 +0100 Subject: [PATCH 1206/1619] [ARM] 3888/1: add pxa27x SSP FSRT register bit definition This patch adds a register bit definition for the pxa27x SSP port Frame Sync Relative Timing (FSRT) bit. Signed-off-by: Liam Girdwood Signed-off-by: Russell King --- include/asm-arm/arch-pxa/pxa-regs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index f5cc65dd7d0..68731e0923a 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -1681,6 +1681,7 @@ #define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */ #define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */ +#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */ #define SSPSP_DMYSTOP(x) (x << 23) /* Dummy Stop */ #define SSPSP_SFRMWDTH(x) (x << 16) /* Serial Frame Width */ #define SSPSP_SFRMDLY(x) (x << 9) /* Serial Frame Delay */ -- GitLab From 48e3becbee8906b44050c9300b668227b85f0c95 Mon Sep 17 00:00:00 2001 From: Kristoffer Ericson Date: Sun, 8 Oct 2006 19:52:30 +0100 Subject: [PATCH 1207/1619] [ARM] 3889/1: [Jornada7xx] Addition of correct SDRAM params into cpu-sa1110.c This adds correct sdram params for K4S281632B-1H and sets the jornada to use them by default. Signed-off-by: Kristoffer Ericson Signed-off-by: Russell King --- arch/arm/mach-sa1100/cpu-sa1110.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c index 63959772993..90a4130114a 100644 --- a/arch/arm/mach-sa1100/cpu-sa1110.c +++ b/arch/arm/mach-sa1100/cpu-sa1110.c @@ -82,6 +82,14 @@ static struct sdram_params sdram_tbl[] __initdata = { .twr = 9, .refresh = 64000, .cas_latency = 3, + }, { /* Samsung K4S281632B-1H */ + .name = "K4S281632b-1H", + .rows = 12, + .tck = 10, + .trp = 20, + .twr = 10, + .refresh = 64000, + .cas_latency = 3, }, { /* Samsung KM416S4030CT */ .name = "KM416S4030CT", .rows = 13, @@ -366,6 +374,8 @@ static int __init sa1110_clk_init(void) if (machine_is_h3100()) name = "KM416S4030CT"; + if (machine_is_jornada720()) + name = "K4S281632B-1H"; } sdram = sa1110_find_sdram(name); -- GitLab From 8e25b84e76a0b2c117218405818cadd591512ff8 Mon Sep 17 00:00:00 2001 From: Kristoffer Ericson Date: Sun, 8 Oct 2006 20:00:53 +0100 Subject: [PATCH 1208/1619] [ARM] 3890/1: [Jornada7xx] Addition of MCU commands into jornada720.h This adds relevant MCU commands for the j7xx chipset. Signed-off-by: Kristoffer Ericson Signed-off-by: Russell King --- include/asm-arm/arch-sa1100/jornada720.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/asm-arm/arch-sa1100/jornada720.h b/include/asm-arm/arch-sa1100/jornada720.h index 1b8e8a30480..3f37ca07806 100644 --- a/include/asm-arm/arch-sa1100/jornada720.h +++ b/include/asm-arm/arch-sa1100/jornada720.h @@ -19,6 +19,20 @@ #define GPIO_JORNADA720_KEYBOARD_IRQ IRQ_GPIO0 #define GPIO_JORNADA720_MOUSE_IRQ IRQ_GPIO9 +/* MCU COMMANDS */ +#define MCU_GetBatteryData 0xc0 +#define MCU_GetScanKeyCode 0x90 +#define MCU_GetTouchSamples 0xa0 +#define MCU_GetContrast 0xD0 +#define MCU_SetContrast 0xD1 +#define MCU_GetBrightness 0xD2 +#define MCU_SetBrightness 0xD3 +#define MCU_ContrastOff 0xD8 +#define MCU_BrightnessOff 0xD9 +#define MCU_PWMOFF 0xDF +#define MCU_TxDummy 0x11 +#define MCU_ErrorCode 0x00 + #ifndef __ASSEMBLY__ void jornada720_mcu_init(void); -- GitLab From 2326eb985b8844f44e150489c76f5cb56fa381b4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 15 Oct 2006 13:48:37 +0100 Subject: [PATCH 1209/1619] [ARM] Fix fallout from IRQ regs changes Some ARM platforms were still broken as a result of the IRQ register passing changes, mostly due to a missing linux/irq.h include. Signed-off-by: Russell King --- arch/arm/mach-footbridge/dc21285.c | 1 + arch/arm/mach-pxa/lubbock.c | 2 +- arch/arm/oprofile/op_model_xscale.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c index fa5d4976f51..1463330ed8e 100644 --- a/arch/arm/mach-footbridge/dc21285.c +++ b/arch/arm/mach-footbridge/dc21285.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index ee80d62119d..142c33c3dff 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -397,7 +397,7 @@ static void lubbock_mmc_poll(unsigned long data) if (LUB_IRQ_SET_CLR & (1 << 0)) mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE); else { - (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL); + (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data); enable_irq(LUBBOCK_SD_IRQ); } } diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c index 7899d3ca75a..7c3289c2acd 100644 --- a/arch/arm/oprofile/op_model_xscale.c +++ b/arch/arm/oprofile/op_model_xscale.c @@ -20,7 +20,8 @@ #include #include #include -#include +#include + #include #include "op_counter.h" -- GitLab From 36bd262b3f2ac723dadd20ce35539c8c738877f1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 15 Oct 2006 13:50:02 +0100 Subject: [PATCH 1210/1619] [ARM] Fix Zaurii keyboard/touchscreen drivers The Zaurii drivers were partially fixed up for the IRQ register changes, but unfortunately missed some bits, resulting in build errors. Fix these. Signed-off-by: Russell King --- drivers/input/keyboard/corgikbd.c | 2 +- drivers/input/keyboard/locomokbd.c | 2 +- drivers/input/keyboard/spitzkbd.c | 2 +- drivers/input/touchscreen/corgi_ts.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index cb70970625b..befdd6006b5 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -207,7 +207,7 @@ static irqreturn_t corgikbd_interrupt(int irq, void *dev_id) static void corgikbd_timer_callback(unsigned long data) { struct corgikbd *corgikbd_data = (struct corgikbd *) data; - corgikbd_scankeyboard(corgikbd_data, NULL); + corgikbd_scankeyboard(corgikbd_data); } /* diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index fd33c9cc327..5788dbc317b 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -186,7 +186,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) static void locomokbd_timer_callback(unsigned long data) { struct locomokbd *locomokbd = (struct locomokbd *) data; - locomokbd_scankeyboard(locomokbd, NULL); + locomokbd_scankeyboard(locomokbd); } static int locomokbd_probe(struct locomo_dev *dev) diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 8b18c009e3e..28b2748e82d 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -257,7 +257,7 @@ static void spitzkbd_timer_callback(unsigned long data) { struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; - spitzkbd_scankeyboard(spitzkbd_data, NULL); + spitzkbd_scankeyboard(spitzkbd_data); } /* diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index ca79b224619..66121f6a89a 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -219,7 +219,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer) static void corgi_ts_timer(unsigned long data) { struct corgi_ts *corgits_data = (struct corgi_ts *) data; - ts_interrupt_main(corgits_data, 1, NULL); + ts_interrupt_main(corgits_data, 1); } static irqreturn_t ts_interrupt(int irq, void *dev_id) @@ -237,7 +237,7 @@ static int corgits_suspend(struct platform_device *dev, pm_message_t state) if (corgi_ts->pendown) { del_timer_sync(&corgi_ts->timer); corgi_ts->tc.pressure = 0; - new_data(corgi_ts, NULL); + new_data(corgi_ts); corgi_ts->pendown = 0; } corgi_ts->power_mode = PWR_MODE_SUSPEND; -- GitLab From 645408d1ffe9f27b176a88302c22420f301607db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2006 16:50:38 +0100 Subject: [PATCH 1211/1619] [PATCH] gfp_t in netlabel Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/net/netlabel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 113337c2795..12c214b9ead 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -136,7 +136,7 @@ struct netlbl_lsm_secattr { * on success, NULL on failure. * */ -static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(int flags) +static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags) { struct netlbl_lsm_cache *cache; -- GitLab From 733f99acc82543030ce0417e2f2201ddc63097af Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2006 16:48:26 +0100 Subject: [PATCH 1212/1619] [PATCH] new cifs endianness bugs * missing cpu_to_le64() for ChangeTime (introduced by [CIFS] Legacy time handling for Win9x and OS/2 part 1) * missing le16_to_cpu() for DialectIndex (introduced by [CIFS] Do not send newer QFSInfo to legacy servers which can not support it) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/cifs/cifssmb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5dc5a966bd5..098790eb2aa 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -399,6 +399,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) struct TCP_Server_Info * server; u16 count; unsigned int secFlags; + u16 dialect; if(ses->server) server = ses->server; @@ -438,9 +439,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if (rc != 0) goto neg_err_exit; - cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); + dialect = le16_to_cpu(pSMBr->DialectIndex); + cFYI(1,("Dialect: %d", dialect)); /* Check wct = 1 error case */ - if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { + if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) { /* core returns wct = 1, but we do not ask for core - otherwise small wct just comes when dialect index is -1 indicating we could not negotiate a common dialect */ @@ -448,8 +450,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if((pSMBr->hdr.WordCount == 13) - && ((pSMBr->DialectIndex == LANMAN_PROT) - || (pSMBr->DialectIndex == LANMAN2_PROT))) { + && ((dialect == LANMAN_PROT) + || (dialect == LANMAN2_PROT))) { __s16 tmp; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; @@ -2943,7 +2945,7 @@ QInfRetry: ts.tv_nsec = 0; ts.tv_sec = time; /* decode time fields */ - pFinfo->ChangeTime = cifs_UnixTimeToNT(ts); + pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); pFinfo->LastWriteTime = pFinfo->ChangeTime; pFinfo->LastAccessTime = 0; pFinfo->AllocationSize = -- GitLab From 6ce6b3aeeae75eee34670bcd42870ac839bfec4c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2006 16:52:36 +0100 Subject: [PATCH 1213/1619] [PATCH] hp drivers/input stuff: C99 initializers, NULL noise removal, __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/input/misc/hp_sdc_rtc.c | 8 ++++---- drivers/input/serio/hil_mlc.c | 18 +++++++++--------- drivers/input/serio/hp_sdc.c | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 1be963961c1..ab4da79ee56 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -60,7 +60,7 @@ static struct fasync_struct *hp_sdc_rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); -static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, +static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, @@ -385,14 +385,14 @@ static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) return 0; } -static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, +static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ssize_t retval; if (count < sizeof(unsigned long)) return -EINVAL; - retval = put_user(68, (unsigned long *)buf); + retval = put_user(68, (unsigned long __user *)buf); return retval; } @@ -696,7 +696,7 @@ static int __init hp_sdc_rtc_init(void) if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) return ret; misc_register(&hp_sdc_rtc_dev); - create_proc_read_entry ("driver/rtc", 0, 0, + create_proc_read_entry ("driver/rtc", 0, NULL, hp_sdc_rtc_read_proc, NULL); printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index bdfde046b74..49e11e2c1d5 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -391,23 +391,23 @@ static int hilse_operate(hil_mlc *mlc, int repoll) { } #define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \ -{ HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc }, +{ HILSE_FUNC, { .func = funct }, funct_arg, zero_rc, neg_rc, pos_rc }, #define OUT(pack) \ -{ HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, +{ HILSE_OUT, { .packet = pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, #define CTS \ -{ HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, +{ HILSE_CTS, { .packet = 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, #define EXPECT(comp, to, got, got_wrong, timed_out) \ -{ HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out }, +{ HILSE_EXPECT, { .packet = comp }, to, got, got_wrong, timed_out }, #define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \ -{ HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out }, +{ HILSE_EXPECT_LAST, { .packet = comp }, to, got, got_wrong, timed_out }, #define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \ -{ HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out }, +{ HILSE_EXPECT_DISC, { .packet = comp }, to, got, got_wrong, timed_out }, #define IN(to, got, got_error, timed_out) \ -{ HILSE_IN, { packet: 0 }, to, got, got_error, timed_out }, +{ HILSE_IN, { .packet = 0 }, to, got, got_error, timed_out }, #define OUT_DISC(pack) \ -{ HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 }, +{ HILSE_OUT_DISC, { .packet = pack }, 0, 0, 0, 0 }, #define OUT_LAST(pack) \ -{ HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 }, +{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 }, struct hilse_node hil_mlc_se[HILSEN_END] = { diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index ba7b920347e..9907ad3bea2 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -310,7 +310,7 @@ static void hp_sdc_tasklet(unsigned long foo) { * in tasklet/bh context. */ if (curr->act.irqhook) - curr->act.irqhook(0, 0, 0, 0); + curr->act.irqhook(0, NULL, 0, 0); } curr->actidx = curr->idx; curr->idx++; @@ -525,7 +525,7 @@ actdone: up(curr->act.semaphore); } else if (act & HP_SDC_ACT_CALLBACK) { - curr->act.irqhook(0,0,0,0); + curr->act.irqhook(0,NULL,0,0); } if (curr->idx >= curr->endidx) { /* This transaction is over. */ if (act & HP_SDC_ACT_DEALLOC) kfree(curr); -- GitLab From cbff67668d597da48f8bc48549a9630cbf968f34 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2006 16:53:38 +0100 Subject: [PATCH 1214/1619] [PATCH] sun3_ioremap() prototype Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/asm-m68k/sun3mmu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/asm-m68k/sun3mmu.h b/include/asm-m68k/sun3mmu.h index 6c8c17d047a..d8f17a0d8c9 100644 --- a/include/asm-m68k/sun3mmu.h +++ b/include/asm-m68k/sun3mmu.h @@ -4,6 +4,7 @@ #ifndef __SUN3_MMU_H__ #define __SUN3_MMU_H__ +#include #include #include @@ -160,7 +161,7 @@ static inline void sun3_put_context(unsigned char c) return; } -extern void *sun3_ioremap(unsigned long phys, unsigned long size, +extern void __iomem *sun3_ioremap(unsigned long phys, unsigned long size, unsigned long type); extern int sun3_map_test(unsigned long addr, char *val); -- GitLab From e5a301ee02e53acf000bb8331587129930bc2290 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2006 16:51:49 +0100 Subject: [PATCH 1215/1619] [PATCH] serial167 __user annotations, NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/serial167.c | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 461bfe0234c..3af7f0958c5 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -839,7 +839,7 @@ shutdown(struct cyclades_port * info) local_irq_save(flags); if (info->xmit_buf){ free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; + info->xmit_buf = NULL; } base_addr[CyCAR] = (u_char)channel; @@ -1354,7 +1354,7 @@ cy_unthrottle(struct tty_struct * tty) static int get_serial_info(struct cyclades_port * info, - struct serial_struct * retinfo) + struct serial_struct __user * retinfo) { struct serial_struct tmp; @@ -1376,7 +1376,7 @@ get_serial_info(struct cyclades_port * info, static int set_serial_info(struct cyclades_port * info, - struct serial_struct * new_info) + struct serial_struct __user * new_info) { struct serial_struct new_serial; struct cyclades_port old_info; @@ -1503,7 +1503,7 @@ send_break( struct cyclades_port * info, int duration) } /* send_break */ static int -get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) +get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon) { if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) @@ -1516,7 +1516,7 @@ get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) } static int -set_threshold(struct cyclades_port * info, unsigned long *arg) +set_threshold(struct cyclades_port * info, unsigned long __user *arg) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long value; @@ -1533,7 +1533,7 @@ set_threshold(struct cyclades_port * info, unsigned long *arg) } static int -get_threshold(struct cyclades_port * info, unsigned long *value) +get_threshold(struct cyclades_port * info, unsigned long __user *value) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; @@ -1546,7 +1546,7 @@ get_threshold(struct cyclades_port * info, unsigned long *value) } static int -set_default_threshold(struct cyclades_port * info, unsigned long *arg) +set_default_threshold(struct cyclades_port * info, unsigned long __user *arg) { unsigned long value; @@ -1558,13 +1558,13 @@ set_default_threshold(struct cyclades_port * info, unsigned long *arg) } static int -get_default_threshold(struct cyclades_port * info, unsigned long *value) +get_default_threshold(struct cyclades_port * info, unsigned long __user *value) { return put_user(info->default_threshold,value); } static int -set_timeout(struct cyclades_port * info, unsigned long *arg) +set_timeout(struct cyclades_port * info, unsigned long __user *arg) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; @@ -1581,7 +1581,7 @@ set_timeout(struct cyclades_port * info, unsigned long *arg) } static int -get_timeout(struct cyclades_port * info, unsigned long *value) +get_timeout(struct cyclades_port * info, unsigned long __user *value) { volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; @@ -1601,7 +1601,7 @@ set_default_timeout(struct cyclades_port * info, unsigned long value) } static int -get_default_timeout(struct cyclades_port * info, unsigned long *value) +get_default_timeout(struct cyclades_port * info, unsigned long __user *value) { return put_user(info->default_timeout,value); } @@ -1613,6 +1613,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file, unsigned long val; struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int ret_val = 0; + void __user *argp = (void __user *)arg; #ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ @@ -1620,28 +1621,28 @@ cy_ioctl(struct tty_struct *tty, struct file * file, switch (cmd) { case CYGETMON: - ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); + ret_val = get_mon_info(info, argp); break; case CYGETTHRESH: - ret_val = get_threshold(info, (unsigned long *)arg); + ret_val = get_threshold(info, argp); break; case CYSETTHRESH: - ret_val = set_threshold(info, (unsigned long *)arg); + ret_val = set_threshold(info, argp); break; case CYGETDEFTHRESH: - ret_val = get_default_threshold(info, (unsigned long *)arg); + ret_val = get_default_threshold(info, argp); break; case CYSETDEFTHRESH: - ret_val = set_default_threshold(info, (unsigned long *)arg); + ret_val = set_default_threshold(info, argp); break; case CYGETTIMEOUT: - ret_val = get_timeout(info, (unsigned long *)arg); + ret_val = get_timeout(info, argp); break; case CYSETTIMEOUT: - ret_val = set_timeout(info, (unsigned long *)arg); + ret_val = set_timeout(info, argp); break; case CYGETDEFTIMEOUT: - ret_val = get_default_timeout(info, (unsigned long *)arg); + ret_val = get_default_timeout(info, argp); break; case CYSETDEFTIMEOUT: ret_val = set_default_timeout(info, (unsigned long)arg); @@ -1664,21 +1665,20 @@ cy_ioctl(struct tty_struct *tty, struct file * file, /* The following commands are incompletely implemented!!! */ case TIOCGSOFTCAR: - ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp); break; case TIOCSSOFTCAR: - ret_val = get_user(val, (unsigned long *) arg); + ret_val = get_user(val, (unsigned long __user *) argp); if (ret_val) break; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); break; case TIOCGSERIAL: - ret_val = get_serial_info(info, (struct serial_struct *) arg); + ret_val = get_serial_info(info, argp); break; case TIOCSSERIAL: - ret_val = set_serial_info(info, - (struct serial_struct *) arg); + ret_val = set_serial_info(info, argp); break; default: ret_val = -ENOIOCTLCMD; @@ -1773,7 +1773,7 @@ cy_close(struct tty_struct * tty, struct file * filp) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); info->event = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); @@ -2250,7 +2250,7 @@ scrn[1] = '\0'; info->card = index; info->line = port_num; info->flags = STD_COM_FLAGS; - info->tty = 0; + info->tty = NULL; info->xmit_fifo_size = 12; info->cor1 = CyPARITY_NONE|Cy_8_BITS; info->cor2 = CyETC; -- GitLab From a7a0d86f5aa40a2215e36fe21d7911cf718ba428 Mon Sep 17 00:00:00 2001 From: Petr Vandrovec Date: Fri, 13 Oct 2006 18:42:07 +0200 Subject: [PATCH 1216/1619] [PATCH] Fix core files so they make sense to gdb... It is silly to use non-static variable for writting zeroes to the file. And more seriously, foffset in core dump file dump function was incremented too much, so some parts of core dump were shifted by size of few phdrs and notes down, so although gdb was able to load that file, it did not make lot of sense - in my test case data pages were shifted down by about 900 bytes. Signed-off-by: Petr Vandrovec Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 56100612790..79b05a1a436 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1220,7 +1220,7 @@ static int notesize(struct memelfnote *en) static int alignfile(struct file *file, loff_t *foffset) { - char buf[4] = { 0, }; + static const char buf[4] = { 0, }; DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); return 1; } @@ -1569,7 +1569,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) DUMP_WRITE(elf, sizeof(*elf)); offset += sizeof(*elf); /* Elf header */ - offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ + offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */ + foffset = offset; /* Write notes phdr entry */ { @@ -1586,8 +1587,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) DUMP_WRITE(&phdr, sizeof(phdr)); } - foffset = offset; - dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); /* Write program headers for segments dump */ @@ -1612,7 +1611,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) phdr.p_align = ELF_EXEC_PAGESIZE; DUMP_WRITE(&phdr, sizeof(phdr)); - foffset += sizeof(phdr); } #ifdef ELF_CORE_WRITE_EXTRA_PHDRS -- GitLab From 80c5606c3b45e0176c32d3108ade1e1cb0b954f3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 15 Oct 2006 14:09:55 -0700 Subject: [PATCH 1217/1619] Fix VM_MAYEXEC calculation .. and clean up the file mapping code while at it. No point in having a "if (file)" repeated twice, and generally doing similar checks in two different sections of the same code Signed-off-by: Linus Torvalds --- mm/mmap.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index eea8eefd51a..497e502dfd6 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -900,17 +900,6 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, int accountable = 1; unsigned long charged = 0, reqprot = prot; - if (file) { - if (is_file_hugepages(file)) - accountable = 0; - - if (!file->f_op || !file->f_op->mmap) - return -ENODEV; - - if ((prot & PROT_EXEC) && - (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)) - return -EPERM; - } /* * Does the application expect PROT_READ to imply PROT_EXEC? * @@ -1000,6 +989,16 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, case MAP_PRIVATE: if (!(file->f_mode & FMODE_READ)) return -EACCES; + if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) { + if (vm_flags & VM_EXEC) + return -EPERM; + vm_flags &= ~VM_MAYEXEC; + } + if (is_file_hugepages(file)) + accountable = 0; + + if (!file->f_op || !file->f_op->mmap) + return -ENODEV; break; default: -- GitLab From 51018b0a3160d253283173c2f54f16746cee5852 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 15 Oct 2006 15:03:48 -0400 Subject: [PATCH 1218/1619] [PATCH] make UML compile (FC6/x86-64) I need this patch to get a UML kernel to compile. This is with the kernel headers in FC6 which are automatically generated from the kernel tree. Some headers are missing but those files don't need them. At least it appears so since the resuling kernel works fine. Tested on x86-64. Signed-off-by: Ulrich Drepper Signed-off-by: Linus Torvalds --- arch/um/include/kern_util.h | 1 - arch/um/sys-x86_64/stub_segv.c | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 59cfa9e0cad..cec9fcc57bf 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -6,7 +6,6 @@ #ifndef __KERN_UTIL_H__ #define __KERN_UTIL_H__ -#include "linux/threads.h" #include "sysdep/ptrace.h" #include "sysdep/faultinfo.h" diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c index 1c967026c95..652fa34c2cd 100644 --- a/arch/um/sys-x86_64/stub_segv.c +++ b/arch/um/sys-x86_64/stub_segv.c @@ -5,7 +5,6 @@ #include #include -#include #include #include "uml-config.h" #include "sysdep/sigcontext.h" -- GitLab From e5267b4b376cfbdc4518abcc68d5a7fffb505638 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 10 Oct 2006 15:14:12 +1000 Subject: [PATCH 1219/1619] [POWERPC] Don't crash on cell with 2 BEs when !CONFIG_NUMA The SPU code will crash if CONFIG_NUMA is not set and SPUs are found on a non-0 node. This workaround will ignore those SPEs and just print an message in the kernel log. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ccfd0c4db87..d0fb959e3ef 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -781,6 +781,17 @@ static int __init create_spu(struct device_node *spe) if (!spu) goto out; + spu->node = find_spu_node_id(spe); + if (spu->node >= MAX_NUMNODES) { + printk(KERN_WARNING "SPE %s on node %d ignored," + " node number too big\n", spe->full_name, spu->node); + printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); + return -ENODEV; + } + spu->nid = of_node_to_nid(spe); + if (spu->nid == -1) + spu->nid = 0; + ret = spu_map_device(spu, spe); /* try old method */ if (ret) @@ -788,10 +799,6 @@ static int __init create_spu(struct device_node *spe) if (ret) goto out_free; - spu->node = find_spu_node_id(spe); - spu->nid = of_node_to_nid(spe); - if (spu->nid == -1) - spu->nid = 0; ret = spu_map_interrupts(spu, spe); if (ret) ret = spu_map_interrupts_old(spu, spe); -- GitLab From 654e4aee495bec1e4fc71ba1af25735da7cadc15 Mon Sep 17 00:00:00 2001 From: "Noguchi, Masato" Date: Tue, 10 Oct 2006 10:27:29 +0200 Subject: [PATCH 1220/1619] [POWERPC] spufs: fix support for read/write on cntl This fixes a memory leak introduced by "spufs: add support for read/write oncntl", which was missing a call to simple_attr_close. Signed-off-by: Masato Noguchi Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index e0d73004526..0de8e114e6b 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -246,6 +246,7 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) static struct file_operations spufs_cntl_fops = { .open = spufs_cntl_open, + .release = simple_attr_close, .read = simple_attr_read, .write = simple_attr_write, .mmap = spufs_cntl_mmap, -- GitLab From ee4ea82c07fa8aa46037962ec3e8b40c5144b5eb Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 10 Oct 2006 11:53:26 -0500 Subject: [PATCH 1221/1619] [POWERPC] Add DOS partition table support to mpc834x_itx_defconfig The default configuration file for the MPC8349E-mITX reference board, mpc834x_itx_defconfig, did not include support for DOS partition table types. This support is necessary because the hard drive that comes with the ITX is formatted with this partition table type. Without this config option, no partitions on the drive can be mounted. Signed-off-by: Timur Tabi Signed-off-by: Paul Mackerras --- arch/powerpc/configs/mpc834x_itx_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/configs/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig index cd3535e1a09..0561b73a918 100644 --- a/arch/powerpc/configs/mpc834x_itx_defconfig +++ b/arch/powerpc/configs/mpc834x_itx_defconfig @@ -1248,7 +1248,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_AMIGA_PARTITION is not set # CONFIG_ATARI_PARTITION is not set # CONFIG_MAC_PARTITION is not set -# CONFIG_MSDOS_PARTITION is not set +CONFIG_MSDOS_PARTITION=y # CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set -- GitLab From bb579cf1d413b930be0241987b848e0f0c1b292f Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Tue, 10 Oct 2006 14:37:29 -0700 Subject: [PATCH 1222/1619] [POWERPC] Off-by-one in /arch/ppc/platforms/mpc8* A find -iname \*.[ch] | xargs grep "> ARRAY_SIZE(" revealed several incorrect usages of ARRAY_SIZE in the mpc drivers. The last element in the array is always ARRAY_SIZE()-1, this patch modifies the bounds checks accordingly. Signed-off-by: Eric Sesterhenn Cc: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/ppc/platforms/mpc8272ads_setup.c | 4 ++-- arch/ppc/platforms/mpc866ads_setup.c | 4 ++-- arch/ppc/platforms/mpc885ads_setup.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c index d7b3a6afa78..1f9ea36837b 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c +++ b/arch/ppc/platforms/mpc8272ads_setup.c @@ -196,7 +196,7 @@ static void __init mpc8272ads_fixup_enet_pdata(struct platform_device *pdev, bd_t* bi = (void*)__res; int fs_no = fsid_fcc1+pdev->id-1; - if(fs_no > ARRAY_SIZE(mpc82xx_enet_pdata)) { + if(fs_no >= ARRAY_SIZE(mpc82xx_enet_pdata)) { return; } @@ -222,7 +222,7 @@ static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev, int id = fs_uart_id_scc2fsid(idx); /* no need to alter anything if console */ - if ((id <= num) && (!pdev->dev.platform_data)) { + if ((id < num) && (!pdev->dev.platform_data)) { pinfo = &mpc8272_uart_pdata[id]; pinfo->uart_clk = bd->bi_intfreq; pdev->dev.platform_data = pinfo; diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index 5f130dca377..e95d2c11174 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c @@ -259,7 +259,7 @@ static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no) /* Get pointer to Communication Processor */ cp = cpmp; - if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) { + if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) { printk(KERN_ERR"No network-suitable #%d device on bus", fs_no); return; } @@ -305,7 +305,7 @@ static void __init mpc866ads_fixup_uart_pdata(struct platform_device *pdev, int id = fs_uart_id_smc2fsid(idx); /* no need to alter anything if console */ - if ((id <= num) && (!pdev->dev.platform_data)) { + if ((id < num) && (!pdev->dev.platform_data)) { pinfo = &mpc866_uart_pdata[id]; pinfo->uart_clk = bd->bi_intfreq; pdev->dev.platform_data = pinfo; diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c index 02293141efb..f8161f3557f 100644 --- a/arch/ppc/platforms/mpc885ads_setup.c +++ b/arch/ppc/platforms/mpc885ads_setup.c @@ -263,7 +263,7 @@ static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no) char *e; int i; - if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) { + if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) { printk(KERN_ERR"No network-suitable #%d device on bus", fs_no); return; } @@ -371,7 +371,7 @@ static void __init mpc885ads_fixup_uart_pdata(struct platform_device *pdev, int id = fs_uart_id_smc2fsid(idx); /* no need to alter anything if console */ - if ((id <= num) && (!pdev->dev.platform_data)) { + if ((id < num) && (!pdev->dev.platform_data)) { pinfo = &mpc885_uart_pdata[id]; pinfo->uart_clk = bd->bi_intfreq; pdev->dev.platform_data = pinfo; -- GitLab From 7d2bd30f67e231920091d55d0fffc3a4bf43e68a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 11 Oct 2006 02:06:59 -0500 Subject: [PATCH 1223/1619] [POWERPC] ppc: Add missing calls to set_irq_regs In the timer_interrupt we were not calling set_irq_regs() and if we are profiling we will end up calling get_irq_regs(). This causes bad things to happen. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/time.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index d4b2cf74da6..18ee851e33e 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -62,6 +62,7 @@ #include #include #include +#include #include @@ -129,6 +130,7 @@ void wakeup_decrementer(void) */ void timer_interrupt(struct pt_regs * regs) { + struct pt_regs *old_regs; int next_dec; unsigned long cpu = smp_processor_id(); unsigned jiffy_stamp = last_jiffy_stamp(cpu); @@ -137,6 +139,7 @@ void timer_interrupt(struct pt_regs * regs) if (atomic_read(&ppc_n_lost_interrupts) != 0) do_IRQ(regs); + old_regs = set_irq_regs(regs); irq_enter(); while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { @@ -188,6 +191,7 @@ void timer_interrupt(struct pt_regs * regs) ppc_md.heartbeat(); irq_exit(); + set_irq_regs(old_regs); } /* -- GitLab From f5a37b066165f9938a93653f6940f3dc85ce751d Mon Sep 17 00:00:00 2001 From: Li Yang Date: Wed, 11 Oct 2006 19:04:22 +0800 Subject: [PATCH 1224/1619] [POWERPC] Fix MPC8360EMDS PB board support MPC8360EMDS PB support is broken as some code was missing in last submission. This patch adds missing code and makes MPC8360EMDS PB support working. Signed-off-by: Li Yang Signed-off-by: Kim Phillips Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/83xx/Kconfig | 13 +++++++++++++ arch/powerpc/platforms/83xx/Makefile | 1 + arch/powerpc/platforms/83xx/mpc8360e_pb.c | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 0975e94ac7c..7edb6b46138 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -32,6 +32,13 @@ config MPC834x_ITX Be aware that PCI initialization is the bootloader's responsiblilty. +config MPC8360E_PB + bool "Freescale MPC8360E PB" + select DEFAULT_UIMAGE + select QUICC_ENGINE + help + This option enables support for the MPC836x EMDS Processor Board. + endchoice config PPC_MPC832x @@ -46,4 +53,10 @@ config MPC834x select PPC_INDIRECT_PCI default y if MPC834x_SYS || MPC834x_ITX +config PPC_MPC836x + bool + select PPC_UDBG_16550 + select PPC_INDIRECT_PCI + default y if MPC8360E_PB + endmenu diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 9387a110d28..e60fd7567fc 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -5,3 +5,4 @@ obj-y := misc.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o +obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c index c0191900fc2..1a523c81c06 100644 --- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c +++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -141,6 +142,24 @@ static void __init mpc8360_sys_setup_arch(void) #endif } +static int __init mpc8360_declare_of_platform_devices(void) +{ + struct device_node *np; + + for (np = NULL; (np = of_find_compatible_node(np, "network", + "ucc_geth")) != NULL;) { + int ucc_num; + char bus_id[BUS_ID_SIZE]; + + ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1; + snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num); + of_platform_device_create(np, bus_id, NULL); + } + + return 0; +} +device_initcall(mpc8360_declare_of_platform_devices); + void __init mpc8360_sys_init_IRQ(void) { -- GitLab From 8ba738c2bb8fb83c0c99f680444d3ffd4c178ca2 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Wed, 11 Oct 2006 19:27:57 +0800 Subject: [PATCH 1225/1619] [POWERPC] Add Makefile entry for MPC832x_mds support Add missing entry in Makefile for MPC832x MDS support. It also change white space to tab in MPC8360 entry. Signed-off-by: Li Yang Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/83xx/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index e60fd7567fc..f1aa7e24a93 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -5,4 +5,5 @@ obj-y := misc.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o -obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o +obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o +obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o -- GitLab From 60b2a46cd60c54bd6551ddfa01f0aab08ca58a5d Mon Sep 17 00:00:00 2001 From: Randy Vinson Date: Thu, 12 Oct 2006 13:36:23 -0700 Subject: [PATCH 1226/1619] [POWERPC] Fix IO Window Updates on P2P bridges. When update_bridge_base() updates the IO window on a PCI-to-PCI bridge, it fails to zero the upper 16 bits of the base and limit registers if the window size is less than 64K. This fixes it. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_32.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 9b49f8691d2..0d9ff72e285 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -441,14 +441,14 @@ update_bridge_base(struct pci_bus *bus, int i) end = res->end - off; io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK; io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK; - if (end > 0xffff) { - pci_write_config_word(dev, PCI_IO_BASE_UPPER16, - start >> 16); - pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, - end >> 16); + if (end > 0xffff) io_base_lo |= PCI_IO_RANGE_TYPE_32; - } else + else io_base_lo |= PCI_IO_RANGE_TYPE_16; + pci_write_config_word(dev, PCI_IO_BASE_UPPER16, + start >> 16); + pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, + end >> 16); pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo); pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo); -- GitLab From 6c4841c2b6c32a134f9f36e5e08857138cc12b10 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 13 Oct 2006 11:41:00 +1000 Subject: [PATCH 1227/1619] [POWERPC] Never panic when taking altivec exceptions from userspace At the moment we rely on a cpu feature bit or a firmware property to detect altivec. If we dont have either of these and the cpu does in fact support altivec we can cause a panic from userspace. It seems safer to always send a signal if we manage to get an 0xf20 exception from userspace. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index d9f10f2fc37..5ed4c2ceb5c 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -900,14 +900,13 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs) void altivec_unavailable_exception(struct pt_regs *regs) { -#if !defined(CONFIG_ALTIVEC) if (user_mode(regs)) { /* A user program has executed an altivec instruction, but this kernel doesn't support altivec. */ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); return; } -#endif + printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " "%lx at %lx\n", regs->trap, regs->nip); die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); -- GitLab From 99f48610252b736908fa5bdea505a480368308d6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 13 Oct 2006 12:13:12 +1000 Subject: [PATCH 1228/1619] [POWERPC] POWER6 has 6 PMCs Change ->num_pmcs to match the number of PMCs in POWER6. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 47a613cdd77..95382f99440 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -268,7 +268,7 @@ struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_POWER6, .icache_bsize = 128, .dcache_bsize = 128, - .num_pmcs = 8, + .num_pmcs = 6, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, -- GitLab From 00ae36de49cc718d4122e1c8aac96fd1a5a2553c Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 13 Oct 2006 12:17:16 +1000 Subject: [PATCH 1229/1619] [POWERPC] Better check in show_instructions Instead of just checking that an address is in the right range, use the provided __kernel_text_address() helper which covers both the kernel and module text sections. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7b2f6452ba7..f3d4dd580dd 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -341,13 +341,6 @@ struct task_struct *__switch_to(struct task_struct *prev, static int instructions_to_print = 16; -#ifdef CONFIG_PPC64 -#define BAD_PC(pc) ((REGION_ID(pc) != KERNEL_REGION_ID) && \ - (REGION_ID(pc) != VMALLOC_REGION_ID)) -#else -#define BAD_PC(pc) ((pc) < KERNELBASE) -#endif - static void show_instructions(struct pt_regs *regs) { int i; @@ -366,7 +359,8 @@ static void show_instructions(struct pt_regs *regs) * bad address because the pc *should* only be a * kernel address. */ - if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) { + if (!__kernel_text_address(pc) || + __get_user(instr, (unsigned int __user *)pc)) { printk("XXXXXXXX "); } else { if (regs->nip == pc) -- GitLab From 284a940675a64df253e3dffc60b09bb4bbb149e4 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 13 Oct 2006 12:26:57 +1000 Subject: [PATCH 1230/1619] [POWERPC] Check for offline nodes in pci NUMA code During boot we bring up all memory and cpu nodes. Normally a PCI device will be in one of these online nodes, however in some weird setups it may not. We have only seen this in the lab but we may as well check for the case and fallback to -1 (all nodes). Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_64.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 78d3c0fc8df..9bae8a5bf67 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -199,8 +199,14 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev) pci_setup_pci_controller(phb); phb->arch_data = dev; phb->is_dynamic = mem_init_done; - if (dev) - PHB_SET_NODE(phb, of_node_to_nid(dev)); + if (dev) { + int nid = of_node_to_nid(dev); + + if (nid < 0 || !node_online(nid)) + nid = -1; + + PHB_SET_NODE(phb, nid); + } return phb; } -- GitLab From be60358e948484e472c88bf8a2d77e644ff5ed83 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 13:53:32 -0700 Subject: [PATCH 1231/1619] [DECNET]: Use correct config option for routing by fwmark in compare_keys() Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/decnet/dn_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index a2a43d8d93f..491429ce939 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -269,7 +269,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) | (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) | -#ifdef CONFIG_IP_ROUTE_FWMARK +#ifdef CONFIG_DECNET_ROUTE_FWMARK (fl1->nl_u.dn_u.fwmark ^ fl2->nl_u.dn_u.fwmark) | #endif (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) | -- GitLab From f64ad5bb044326c6ebc6535d661c1abe78a0e5f2 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 14:07:52 -0700 Subject: [PATCH 1232/1619] [NETFILTER]: fix cut-and-paste error in exit functions Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_NFQUEUE.c | 2 +- net/netfilter/xt_connmark.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index db9b896e57c..39e117502bd 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -68,7 +68,7 @@ static int __init xt_nfqueue_init(void) static void __exit xt_nfqueue_fini(void) { - xt_register_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target)); + xt_unregister_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target)); } module_init(xt_nfqueue_init); diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 92a5726ef23..a8f03057dbd 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -147,7 +147,7 @@ static int __init xt_connmark_init(void) static void __exit xt_connmark_fini(void) { - xt_register_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match)); + xt_unregister_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match)); } module_init(xt_connmark_init); -- GitLab From f603b6ec50faabbabde53ae2e2ce774968524c40 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 14:08:11 -0700 Subject: [PATCH 1233/1619] [NETFILTER]: arp_tables: missing unregistration on module unload Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/arp_tables.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 17e1a687ab4..0849f1cced1 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1196,6 +1196,8 @@ err1: static void __exit arp_tables_fini(void) { nf_unregister_sockopt(&arpt_sockopts); + xt_unregister_target(&arpt_error_target); + xt_unregister_target(&arpt_standard_target); xt_proto_fini(NF_ARP); } -- GitLab From a9f54596fa20be3edefaa0b24c8714edb945eeaa Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 14:08:26 -0700 Subject: [PATCH 1234/1619] [NETFILTER]: ipt_ECN/ipt_TOS: fix incorrect checksum update Even though the tos field is only a single byte large, the values need to be converted to net-endian for the checkum update so they are in the corrent byte position. Also fix incorrect endian annotations. Reported by Stephane Chazelas Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_ECN.c | 6 +++--- net/ipv4/netfilter/ipt_TOS.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 12a818a2462..1aa4517fbcd 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; - __be16 oldtos; + u_int16_t oldtos; if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { if (!skb_make_writable(pskb, sizeof(struct iphdr))) @@ -37,8 +37,8 @@ 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 ^ htons(0xFFFF), iph->tos, - iph->check); + iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), + htons(iph->tos), iph->check); } return 1; } diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 6b8b14ccc3d..83b80b3a5d2 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; - __be16 oldtos; + u_int16_t oldtos; if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { if (!skb_make_writable(pskb, sizeof(struct iphdr))) @@ -38,8 +38,8 @@ 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 ^ htons(0xFFFF), iph->tos, - iph->check); + iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), + htons(iph->tos), iph->check); } return IPT_CONTINUE; } -- GitLab From c08de5d5308ae0d20290344551ddd9cea8ded661 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 14:08:41 -0700 Subject: [PATCH 1235/1619] [NETFILTER]: xt_CONNSECMARK: fix Kconfig dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONNSECMARK needs conntrack, add missing dependency to fix linking error with CONNSECMARK=y and CONNTRACK=m. Reported by Toralf Förster . Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index ce94732b8e2..f619c652726 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -209,7 +209,9 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_CONNSECMARK tristate '"CONNSECMARK" target support' - depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK) + depends on NETFILTER_XTABLES && \ + ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \ + (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK)) help The CONNSECMARK target copies security markings from packets to connections, and restores security markings from connections -- GitLab From 82b985434c5e9ceee772ca206889a856a7a4a200 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 12 Oct 2006 14:08:55 -0700 Subject: [PATCH 1236/1619] [NETFILTER]: Update MAINTAINERS entry Patches should go to myself CC netfilter-devel. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- MAINTAINERS | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a2b6d9fa350..208da3c320c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2049,11 +2049,13 @@ P: Marc Boucher P: James Morris P: Harald Welte P: Jozsef Kadlecsik -M: coreteam@netfilter.org +P: Patrick McHardy +M: kaber@trash.net +L: netfilter-devel@lists.netfilter.org +L: netfilter@lists.netfilter.org +L: coreteam@netfilter.org W: http://www.netfilter.org/ W: http://www.iptables.org/ -L: netfilter@lists.netfilter.org -L: netfilter-devel@lists.netfilter.org S: Supported NETLABEL -- GitLab From 9ea8cfd6aa74e710f0cb0731ecb9dee53fbebfb9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Oct 2006 14:09:16 -0700 Subject: [PATCH 1237/1619] [NETFILTER]: ctnetlink: Remove debugging messages Remove (compilation-breaking) debugging messages introduced at early development stage. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_netlink.c | 72 +---------------------- net/netfilter/nf_conntrack_netlink.c | 72 +---------------------- 2 files changed, 6 insertions(+), 138 deletions(-) diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 53b6dffea6c..262d0d44ec1 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -44,13 +44,6 @@ MODULE_LICENSE("GPL"); static char __initdata version[] = "0.90"; -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(format, args...) -#endif - - static inline int ctnetlink_dump_tuples_proto(struct sk_buff *skb, const struct ip_conntrack_tuple *tuple, @@ -398,7 +391,6 @@ nfattr_failure: static int ctnetlink_done(struct netlink_callback *cb) { - DEBUGP("entered %s\n", __FUNCTION__); if (cb->args[1]) ip_conntrack_put((struct ip_conntrack *)cb->args[1]); return 0; @@ -411,9 +403,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct ip_conntrack_tuple_hash *h; struct list_head *i; - DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, - cb->args[0], *id); - read_lock_bh(&ip_conntrack_lock); last = (struct ip_conntrack *)cb->args[1]; for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) { @@ -452,7 +441,6 @@ out: if (last) ip_conntrack_put(last); - DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); return skb->len; } @@ -466,8 +454,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) { struct nfattr *tb[CTA_IP_MAX]; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_IP_MAX, attr); if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) @@ -481,8 +467,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) return -EINVAL; tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); - DEBUGP("leaving\n"); - return 0; } @@ -503,8 +487,6 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr, struct ip_conntrack_protocol *proto; int ret = 0; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) @@ -531,8 +513,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple, struct nfattr *tb[CTA_TUPLE_MAX]; int err; - DEBUGP("entered %s\n", __FUNCTION__); - memset(tuple, 0, sizeof(*tuple)); nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); @@ -557,10 +537,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple, else tuple->dst.dir = IP_CT_DIR_ORIGINAL; - DUMP_TUPLE(tuple); - - DEBUGP("leaving\n"); - return 0; } @@ -577,8 +553,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, struct nfattr *tb[CTA_PROTONAT_MAX]; struct ip_nat_protocol *npt; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) @@ -597,7 +571,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, ip_nat_proto_put(npt); - DEBUGP("leaving\n"); return 0; } @@ -613,8 +586,6 @@ ctnetlink_parse_nat(struct nfattr *nat, struct nfattr *tb[CTA_NAT_MAX]; int err; - DEBUGP("entered %s\n", __FUNCTION__); - memset(range, 0, sizeof(*range)); nfattr_parse_nested(tb, CTA_NAT_MAX, nat); @@ -640,7 +611,6 @@ ctnetlink_parse_nat(struct nfattr *nat, if (err < 0) return err; - DEBUGP("leaving\n"); return 0; } #endif @@ -650,8 +620,6 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name) { struct nfattr *tb[CTA_HELP_MAX]; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_HELP_MAX, attr); if (!tb[CTA_HELP_NAME-1]) @@ -679,8 +647,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, struct ip_conntrack *ct; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; @@ -698,10 +664,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, return err; h = ip_conntrack_find_get(&tuple, NULL); - if (!h) { - DEBUGP("tuple not found in conntrack hash\n"); + if (!h) return -ENOENT; - } ct = tuplehash_to_ctrack(h); @@ -716,7 +680,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ct->timeout.function((unsigned long)ct); ip_conntrack_put(ct); - DEBUGP("leaving\n"); return 0; } @@ -731,8 +694,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, struct sk_buff *skb2 = NULL; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nlh->nlmsg_flags & NLM_F_DUMP) { struct nfgenmsg *msg = NLMSG_DATA(nlh); u32 rlen; @@ -770,11 +731,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, return err; h = ip_conntrack_find_get(&tuple, NULL); - if (!h) { - DEBUGP("tuple not found in conntrack hash"); + if (!h) return -ENOENT; - } - DEBUGP("tuple found\n"); + ct = tuplehash_to_ctrack(h); err = -ENOMEM; @@ -795,7 +754,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) goto out; - DEBUGP("leaving\n"); return 0; free: @@ -866,8 +824,6 @@ ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]) char *helpname; int err; - DEBUGP("entered %s\n", __FUNCTION__); - /* don't change helper of sibling connections */ if (ct->master) return -EINVAL; @@ -938,8 +894,6 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) { int err; - DEBUGP("entered %s\n", __FUNCTION__); - if (cda[CTA_HELP-1]) { err = ctnetlink_change_helper(ct, cda); if (err < 0) @@ -969,7 +923,6 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); #endif - DEBUGP("all done\n"); return 0; } @@ -981,8 +934,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[], struct ip_conntrack *ct; int err = -EINVAL; - DEBUGP("entered %s\n", __FUNCTION__); - ct = ip_conntrack_alloc(otuple, rtuple); if (ct == NULL || IS_ERR(ct)) return -ENOMEM; @@ -1017,7 +968,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[], if (ct->helper) ip_conntrack_helper_put(ct->helper); - DEBUGP("conntrack with id %u inserted\n", ct->id); return 0; err: @@ -1033,8 +983,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, struct ip_conntrack_tuple_hash *h = NULL; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; @@ -1058,7 +1006,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (h == NULL) { write_unlock_bh(&ip_conntrack_lock); - DEBUGP("no such conntrack, create new\n"); err = -ENOENT; if (nlh->nlmsg_flags & NLM_F_CREATE) err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); @@ -1074,7 +1021,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, /* We manipulate the conntrack inside the global conntrack table lock, * so there's no need to increase the refcount */ - DEBUGP("conntrack found\n"); err = -EEXIST; if (!(nlh->nlmsg_flags & NLM_F_EXCL)) err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda); @@ -1249,8 +1195,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct list_head *i; u_int32_t *id = (u_int32_t *) &cb->args[0]; - DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id); - read_lock_bh(&ip_conntrack_lock); list_for_each_prev(i, &ip_conntrack_expect_list) { exp = (struct ip_conntrack_expect *) i; @@ -1266,8 +1210,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) out: read_unlock_bh(&ip_conntrack_lock); - DEBUGP("leaving, last id=%llu\n", *id); - return skb->len; } @@ -1285,8 +1227,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, struct sk_buff *skb2; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; @@ -1437,8 +1377,6 @@ ctnetlink_create_expect(struct nfattr *cda[]) struct ip_conntrack *ct; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - /* caller guarantees that those three CTA_EXPECT_* exist */ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); if (err < 0) @@ -1490,8 +1428,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, struct ip_conntrack_expect *exp; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; @@ -1520,8 +1456,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_change_expect(exp, cda); write_unlock_bh(&ip_conntrack_lock); - DEBUGP("leaving\n"); - return err; } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1721f7c78c7..bd0156a28ec 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -47,13 +47,6 @@ MODULE_LICENSE("GPL"); static char __initdata version[] = "0.93"; -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(format, args...) -#endif - - static inline int ctnetlink_dump_tuples_proto(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple, @@ -410,7 +403,6 @@ static int ctnetlink_done(struct netlink_callback *cb) { if (cb->args[1]) nf_ct_put((struct nf_conn *)cb->args[1]); - DEBUGP("entered %s\n", __FUNCTION__); return 0; } @@ -425,9 +417,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; - DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, - cb->args[0], *id); - read_lock_bh(&nf_conntrack_lock); last = (struct nf_conn *)cb->args[1]; for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { @@ -471,7 +460,6 @@ out: if (last) nf_ct_put(last); - DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); return skb->len; } @@ -482,8 +470,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) struct nf_conntrack_l3proto *l3proto; int ret = 0; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_IP_MAX, attr); l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); @@ -493,8 +479,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) nf_ct_l3proto_put(l3proto); - DEBUGP("leaving\n"); - return ret; } @@ -510,8 +494,6 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr, struct nf_conntrack_protocol *proto; int ret = 0; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) @@ -538,8 +520,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, struct nfattr *tb[CTA_TUPLE_MAX]; int err; - DEBUGP("entered %s\n", __FUNCTION__); - memset(tuple, 0, sizeof(*tuple)); nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); @@ -566,10 +546,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, else tuple->dst.dir = IP_CT_DIR_ORIGINAL; - NF_CT_DUMP_TUPLE(tuple); - - DEBUGP("leaving\n"); - return 0; } @@ -586,8 +562,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, struct nfattr *tb[CTA_PROTONAT_MAX]; struct ip_nat_protocol *npt; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) @@ -606,7 +580,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, ip_nat_proto_put(npt); - DEBUGP("leaving\n"); return 0; } @@ -622,8 +595,6 @@ ctnetlink_parse_nat(struct nfattr *nat, struct nfattr *tb[CTA_NAT_MAX]; int err; - DEBUGP("entered %s\n", __FUNCTION__); - memset(range, 0, sizeof(*range)); nfattr_parse_nested(tb, CTA_NAT_MAX, nat); @@ -649,7 +620,6 @@ ctnetlink_parse_nat(struct nfattr *nat, if (err < 0) return err; - DEBUGP("leaving\n"); return 0; } #endif @@ -659,8 +629,6 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name) { struct nfattr *tb[CTA_HELP_MAX]; - DEBUGP("entered %s\n", __FUNCTION__); - nfattr_parse_nested(tb, CTA_HELP_MAX, attr); if (!tb[CTA_HELP_NAME-1]) @@ -690,8 +658,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; @@ -709,10 +675,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, return err; h = nf_conntrack_find_get(&tuple, NULL); - if (!h) { - DEBUGP("tuple not found in conntrack hash\n"); + if (!h) return -ENOENT; - } ct = nf_ct_tuplehash_to_ctrack(h); @@ -727,7 +691,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ct->timeout.function((unsigned long)ct); nf_ct_put(ct); - DEBUGP("leaving\n"); return 0; } @@ -744,8 +707,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nlh->nlmsg_flags & NLM_F_DUMP) { u32 rlen; @@ -779,11 +740,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, return err; h = nf_conntrack_find_get(&tuple, NULL); - if (!h) { - DEBUGP("tuple not found in conntrack hash"); + if (!h) return -ENOENT; - } - DEBUGP("tuple found\n"); + ct = nf_ct_tuplehash_to_ctrack(h); err = -ENOMEM; @@ -804,7 +763,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) goto out; - DEBUGP("leaving\n"); return 0; free: @@ -876,8 +834,6 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) char *helpname; int err; - DEBUGP("entered %s\n", __FUNCTION__); - if (!help) { /* FIXME: we need to reallocate and rehash */ return -EBUSY; @@ -954,8 +910,6 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) { int err; - DEBUGP("entered %s\n", __FUNCTION__); - if (cda[CTA_HELP-1]) { err = ctnetlink_change_helper(ct, cda); if (err < 0) @@ -985,7 +939,6 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); #endif - DEBUGP("all done\n"); return 0; } @@ -997,8 +950,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[], struct nf_conn *ct; int err = -EINVAL; - DEBUGP("entered %s\n", __FUNCTION__); - ct = nf_conntrack_alloc(otuple, rtuple); if (ct == NULL || IS_ERR(ct)) return -ENOMEM; @@ -1028,7 +979,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[], add_timer(&ct->timeout); nf_conntrack_hash_insert(ct); - DEBUGP("conntrack with id %u inserted\n", ct->id); return 0; err: @@ -1046,8 +996,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; @@ -1071,7 +1019,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (h == NULL) { write_unlock_bh(&nf_conntrack_lock); - DEBUGP("no such conntrack, create new\n"); err = -ENOENT; if (nlh->nlmsg_flags & NLM_F_CREATE) err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); @@ -1087,7 +1034,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, /* We manipulate the conntrack inside the global conntrack table lock, * so there's no need to increase the refcount */ - DEBUGP("conntrack found\n"); err = -EEXIST; if (!(nlh->nlmsg_flags & NLM_F_EXCL)) err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda); @@ -1268,8 +1214,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; - DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id); - read_lock_bh(&nf_conntrack_lock); list_for_each_prev(i, &nf_conntrack_expect_list) { exp = (struct nf_conntrack_expect *) i; @@ -1287,8 +1231,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) out: read_unlock_bh(&nf_conntrack_lock); - DEBUGP("leaving, last id=%llu\n", *id); - return skb->len; } @@ -1308,8 +1250,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; @@ -1460,8 +1400,6 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) struct nf_conn_help *help; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - /* caller guarantees that those three CTA_EXPECT_* exist */ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); if (err < 0) @@ -1516,8 +1454,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - DEBUGP("entered %s\n", __FUNCTION__); - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; @@ -1546,8 +1482,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_change_expect(exp, cda); write_unlock_bh(&nf_conntrack_lock); - DEBUGP("leaving\n"); - return err; } -- GitLab From 1a620698c29b5e18150ec04ace0609fb07d08d3e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 12 Oct 2006 14:45:38 -0700 Subject: [PATCH 1238/1619] [BRIDGE]: flush forwarding table when device carrier off Flush the forwarding table when carrier is lost. This helps for availability because we don't want to forward to a downed device and new packets may come in on other links. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 7 ++++++- net/bridge/br_if.c | 4 ++-- net/bridge/br_private.h | 2 +- net/bridge/br_stp_if.c | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 3a73b8c9427..d9f04864d15 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -128,7 +128,10 @@ void br_fdb_cleanup(unsigned long _data) mod_timer(&br->gc_timer, jiffies + HZ/10); } -void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p) + +void br_fdb_delete_by_port(struct net_bridge *br, + const struct net_bridge_port *p, + int do_all) { int i; @@ -142,6 +145,8 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p) if (f->dst != p) continue; + if (f->is_static && !do_all) + continue; /* * if multiple ports all have the same device address * then when one port is deleted, assign diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index b1211d5342f..f753c40c11d 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -163,7 +163,7 @@ static void del_nbp(struct net_bridge_port *p) br_stp_disable_port(p); spin_unlock_bh(&br->lock); - br_fdb_delete_by_port(br, p); + br_fdb_delete_by_port(br, p, 1); list_del_rcu(&p->list); @@ -448,7 +448,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) return 0; err2: - br_fdb_delete_by_port(br, p); + br_fdb_delete_by_port(br, p, 1); err1: kobject_del(&p->kobj); err0: diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c491fb2f280..74258d86f25 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -143,7 +143,7 @@ extern void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr); extern void br_fdb_cleanup(unsigned long arg); extern void br_fdb_delete_by_port(struct net_bridge *br, - struct net_bridge_port *p); + const struct net_bridge_port *p, int do_all); extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, const unsigned char *addr); extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 14cd025079a..d294224592d 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -113,6 +113,8 @@ void br_stp_disable_port(struct net_bridge_port *p) del_timer(&p->forward_delay_timer); del_timer(&p->hold_timer); + br_fdb_delete_by_port(br, p, 0); + br_configuration_update(br); br_port_state_selection(br); -- GitLab From 044a68ed8a692f643cf3c0a54c380a922584f34f Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 11 Oct 2006 19:10:47 -0400 Subject: [PATCH 1239/1619] NetLabel: only deref the CIPSOv4 standard map fields when using standard mapping Fix several places in the CIPSO code where it was dereferencing fields which did not have valid pointers by moving those pointer dereferences into code blocks where the pointers are valid. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index bde8ccaa153..d19c9ac7727 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -773,13 +773,15 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, { int cat = -1; u32 bitmap_len_bits = bitmap_len * 8; - u32 cipso_cat_size = doi_def->map.std->cat.cipso_size; - u32 *cipso_array = doi_def->map.std->cat.cipso; + u32 cipso_cat_size; + u32 *cipso_array; switch (doi_def->type) { case CIPSO_V4_MAP_PASS: return 0; case CIPSO_V4_MAP_STD: + cipso_cat_size = doi_def->map.std->cat.cipso_size; + cipso_array = doi_def->map.std->cat.cipso; for (;;) { cat = cipso_v4_bitmap_walk(bitmap, bitmap_len_bits, @@ -825,8 +827,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, u32 net_spot_max = 0; u32 host_clen_bits = host_cat_len * 8; u32 net_clen_bits = net_cat_len * 8; - u32 host_cat_size = doi_def->map.std->cat.local_size; - u32 *host_cat_array = doi_def->map.std->cat.local; + u32 host_cat_size; + u32 *host_cat_array; switch (doi_def->type) { case CIPSO_V4_MAP_PASS: @@ -838,6 +840,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, memcpy(net_cat, host_cat, net_spot_max); return net_spot_max; case CIPSO_V4_MAP_STD: + host_cat_size = doi_def->map.std->cat.local_size; + host_cat_array = doi_def->map.std->cat.local; for (;;) { host_spot = cipso_v4_bitmap_walk(host_cat, host_clen_bits, @@ -893,8 +897,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, int net_spot = -1; u32 net_clen_bits = net_cat_len * 8; u32 host_clen_bits = host_cat_len * 8; - u32 net_cat_size = doi_def->map.std->cat.cipso_size; - u32 *net_cat_array = doi_def->map.std->cat.cipso; + u32 net_cat_size; + u32 *net_cat_array; switch (doi_def->type) { case CIPSO_V4_MAP_PASS: @@ -903,6 +907,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, memcpy(host_cat, net_cat, net_cat_len); return net_cat_len; case CIPSO_V4_MAP_STD: + net_cat_size = doi_def->map.std->cat.cipso_size; + net_cat_array = doi_def->map.std->cat.cipso; for (;;) { net_spot = cipso_v4_bitmap_walk(net_cat, net_clen_bits, -- GitLab From bf0edf39296097f20c5fcc4919ed7d339194bd75 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 11 Oct 2006 19:10:48 -0400 Subject: [PATCH 1240/1619] NetLabel: better error handling involving mls_export_cat() Upon inspection it looked like the error handling for mls_export_cat() was rather poor. This patch addresses this by NULL'ing out kfree()'d pointers before returning and checking the return value of the function everywhere it is called. Signed-off-by: Paul Moore Signed-off-by: James Morris --- security/selinux/ss/ebitmap.c | 8 ++++++-- security/selinux/ss/mls.c | 17 ++++++++++++++--- security/selinux/ss/services.c | 18 ++++++++++-------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index cfed1d30fa6..d539346ab3a 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -93,11 +93,15 @@ int ebitmap_export(const struct ebitmap *src, size_t bitmap_byte; unsigned char bitmask; + if (src->highbit == 0) { + *dst = NULL; + *dst_len = 0; + return 0; + } + bitmap_len = src->highbit / 8; if (src->highbit % 7) bitmap_len += 1; - if (bitmap_len == 0) - return -EINVAL; bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) + sizeof(MAPTYPE), diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index c713af23250..2cca8e25162 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -640,8 +640,13 @@ int mls_export_cat(const struct context *context, { int rc = -EPERM; - if (!selinux_mls_enabled) + if (!selinux_mls_enabled) { + *low = NULL; + *low_len = 0; + *high = NULL; + *high_len = 0; return 0; + } if (low != NULL) { rc = ebitmap_export(&context->range.level[0].cat, @@ -661,10 +666,16 @@ int mls_export_cat(const struct context *context, return 0; export_cat_failure: - if (low != NULL) + if (low != NULL) { kfree(*low); - if (high != NULL) + *low = NULL; + *low_len = 0; + } + if (high != NULL) { kfree(*high); + *high = NULL; + *high_len = 0; + } return rc; } diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 18274b00509..b1f6fb36c69 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2399,31 +2399,33 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) if (!ss_initialized) return 0; + netlbl_secattr_init(&secattr); + POLICY_RDLOCK; ctx = sidtab_search(&sidtab, sid); if (ctx == NULL) goto netlbl_socket_setsid_return; - netlbl_secattr_init(&secattr); secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], GFP_ATOMIC); mls_export_lvl(ctx, &secattr.mls_lvl, NULL); secattr.mls_lvl_vld = 1; - mls_export_cat(ctx, - &secattr.mls_cat, - &secattr.mls_cat_len, - NULL, - NULL); + rc = mls_export_cat(ctx, + &secattr.mls_cat, + &secattr.mls_cat_len, + NULL, + NULL); + if (rc != 0) + goto netlbl_socket_setsid_return; rc = netlbl_socket_setattr(sock, &secattr); if (rc == 0) sksec->nlbl_state = NLBL_LABELED; - netlbl_secattr_destroy(&secattr); - netlbl_socket_setsid_return: POLICY_RDUNLOCK; + netlbl_secattr_destroy(&secattr); return rc; } -- GitLab From ea614d7f4fb2d436b7a5ee490d1011615f6b38d5 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 11 Oct 2006 19:10:49 -0400 Subject: [PATCH 1241/1619] NetLabel: the CIPSOv4 passthrough mapping does not pass categories correctly The CIPSO passthrough mapping had a problem when sending categories which would cause no or incorrect categories to be sent on the wire with a packet. This patch fixes the problem which was a simple off-by-one bug. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index d19c9ac7727..e2077a3aa8c 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -832,8 +832,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, switch (doi_def->type) { case CIPSO_V4_MAP_PASS: - net_spot_max = host_cat_len - 1; - while (net_spot_max > 0 && host_cat[net_spot_max] == 0) + net_spot_max = host_cat_len; + while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0) net_spot_max--; if (net_spot_max > net_cat_len) return -EINVAL; -- GitLab From 4663afe2c848e2abc8791202beecf40684f13eb4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 12 Oct 2006 21:21:06 -0700 Subject: [PATCH 1242/1619] [NET]: reduce sizeof(struct inet_peer), cleanup, change in peer_check_expire() 1) shrink struct inet_peer on 64 bits platforms. --- include/net/inetpeer.h | 17 ++--------------- net/ipv4/inetpeer.c | 29 ++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 925573fd2ae..f13cc0c2b16 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -19,7 +19,7 @@ struct inet_peer { struct inet_peer *avl_left, *avl_right; struct inet_peer *unused_next, **unused_prevp; - unsigned long dtime; /* the time of last use of not + __u32 dtime; /* the time of last use of not * referenced entries */ atomic_t refcnt; __be32 v4daddr; /* peer's address */ @@ -35,21 +35,8 @@ void inet_initpeers(void) __init; /* can be called with or without local BH being disabled */ struct inet_peer *inet_getpeer(__be32 daddr, int create); -extern spinlock_t inet_peer_unused_lock; -extern struct inet_peer **inet_peer_unused_tailp; /* can be called from BH context or outside */ -static inline void inet_putpeer(struct inet_peer *p) -{ - spin_lock_bh(&inet_peer_unused_lock); - if (atomic_dec_and_test(&p->refcnt)) { - p->unused_prevp = inet_peer_unused_tailp; - p->unused_next = NULL; - *inet_peer_unused_tailp = p; - inet_peer_unused_tailp = &p->unused_next; - p->dtime = jiffies; - } - spin_unlock_bh(&inet_peer_unused_lock); -} +extern void inet_putpeer(struct inet_peer *p); extern spinlock_t inet_peer_idlock; /* can be called with or without local BH being disabled */ diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 2b1a54b59c4..f072f3875af 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -94,10 +94,8 @@ int inet_peer_minttl = 120 * HZ; /* TTL under high load: 120 sec */ int inet_peer_maxttl = 10 * 60 * HZ; /* usual time to live: 10 min */ static struct inet_peer *inet_peer_unused_head; -/* Exported for inet_putpeer inline function. */ -struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head; -DEFINE_SPINLOCK(inet_peer_unused_lock); -#define PEER_MAX_CLEANUP_WORK 30 +static struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head; +static DEFINE_SPINLOCK(inet_peer_unused_lock); static void peer_check_expire(unsigned long dummy); static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0); @@ -340,7 +338,8 @@ static int cleanup_once(unsigned long ttl) spin_lock_bh(&inet_peer_unused_lock); p = inet_peer_unused_head; if (p != NULL) { - if (time_after(p->dtime + ttl, jiffies)) { + __u32 delta = (__u32)jiffies - p->dtime; + if (delta < ttl) { /* Do not prune fresh entries. */ spin_unlock_bh(&inet_peer_unused_lock); return -1; @@ -432,7 +431,7 @@ out_free: /* Called with local BH disabled. */ static void peer_check_expire(unsigned long dummy) { - int i; + unsigned long now = jiffies; int ttl; if (peer_total >= inet_peer_threshold) @@ -441,7 +440,10 @@ static void peer_check_expire(unsigned long dummy) ttl = inet_peer_maxttl - (inet_peer_maxttl - inet_peer_minttl) / HZ * peer_total / inet_peer_threshold * HZ; - for (i = 0; i < PEER_MAX_CLEANUP_WORK && !cleanup_once(ttl); i++); + while (!cleanup_once(ttl)) { + if (jiffies != now) + break; + } /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime * interval depending on the total number of entries (more entries, @@ -455,3 +457,16 @@ static void peer_check_expire(unsigned long dummy) peer_total / inet_peer_threshold * HZ; add_timer(&peer_periodic_timer); } + +void inet_putpeer(struct inet_peer *p) +{ + spin_lock_bh(&inet_peer_unused_lock); + if (atomic_dec_and_test(&p->refcnt)) { + p->unused_prevp = inet_peer_unused_tailp; + p->unused_next = NULL; + *inet_peer_unused_tailp = p; + inet_peer_unused_tailp = &p->unused_next; + p->dtime = (__u32)jiffies; + } + spin_unlock_bh(&inet_peer_unused_lock); +} -- GitLab From 918049f0135854a1583f9b3b88f44dbf2b027329 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 Oct 2006 22:03:24 -0700 Subject: [PATCH 1243/1619] [XFRM]: Fix xfrm_state_num going negative. Missing counter bump when hashing in a new ACQ xfrm_state. Now that we have two spots to do the hash grow check, break it out into a helper function. Signed-off-by: David S. Miller --- net/xfrm/xfrm_state.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 39b8bf3a9de..84bbf8474f3 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -614,6 +614,14 @@ out: return x; } +static void xfrm_hash_grow_check(int have_hash_collision) +{ + if (have_hash_collision && + (xfrm_state_hmask + 1) < xfrm_state_hashmax && + xfrm_state_num > xfrm_state_hmask) + schedule_work(&xfrm_hash_work); +} + static void __xfrm_state_insert(struct xfrm_state *x) { unsigned int h; @@ -642,10 +650,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) xfrm_state_num++; - if (x->bydst.next != NULL && - (xfrm_state_hmask + 1) < xfrm_state_hashmax && - xfrm_state_num > xfrm_state_hmask) - schedule_work(&xfrm_hash_work); + xfrm_hash_grow_check(x->bydst.next != NULL); } /* xfrm_state_lock is held */ @@ -753,6 +758,10 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re h = xfrm_src_hash(daddr, saddr, family); hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); wake_up(&km_waitq); + + xfrm_state_num++; + + xfrm_hash_grow_check(x->bydst.next != NULL); } return x; -- GitLab From adaa70bbdfbc725e485179b06c8b23a20fbb7952 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 13 Oct 2006 15:01:03 -0700 Subject: [PATCH 1244/1619] [IPv6] rules: Use RT6_LOOKUP_F_HAS_SADDR and fix source based selectors Fixes rt6_lookup() to provide the source address in the flow and sets RT6_LOOKUP_F_HAS_SADDR whenever it is present in the flow. Avoids unnecessary prefix comparisons by checking for a prefix length first. Fixes the rule logic to not match packets if a source selector has been specified but no source address is available. Thanks to Kim Nordlund for working on this patch with me. Signed-off-by: Thomas Graf Acked-by: Ville Nuorvala Signed-off-by: David S. Miller --- net/ipv6/fib6_rules.c | 11 +++++++---- net/ipv6/route.c | 19 ++++++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index d8c1057e8b0..1896ecb5289 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -117,12 +117,15 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) { struct fib6_rule *r = (struct fib6_rule *) rule; - if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) + if (r->dst.plen && + !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) return 0; - if ((flags & RT6_LOOKUP_F_HAS_SADDR) && - !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) - return 0; + if (r->src.plen) { + if (!(flags & RT6_LOOKUP_F_HAS_SADDR) || + !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) + return 0; + } if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) return 0; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d6b4b4f48d1..a1b0f075462 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -529,13 +529,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, .nl_u = { .ip6_u = { .daddr = *daddr, - /* TODO: saddr */ }, }, }; struct dst_entry *dst; int flags = strict ? RT6_LOOKUP_F_IFACE : 0; + if (saddr) { + memcpy(&fl.fl6_src, saddr, sizeof(*saddr)); + flags |= RT6_LOOKUP_F_HAS_SADDR; + } + dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); if (dst->error == 0) return (struct rt6_info *) dst; @@ -697,6 +701,7 @@ out2: void ip6_route_input(struct sk_buff *skb) { struct ipv6hdr *iph = skb->nh.ipv6h; + int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi fl = { .iif = skb->dev->ifindex, .nl_u = { @@ -711,7 +716,9 @@ void ip6_route_input(struct sk_buff *skb) }, .proto = iph->nexthdr, }; - int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0; + + if (rt6_need_strict(&iph->daddr)) + flags |= RT6_LOOKUP_F_IFACE; skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); } @@ -794,6 +801,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) if (rt6_need_strict(&fl->fl6_dst)) flags |= RT6_LOOKUP_F_IFACE; + if (!ipv6_addr_any(&fl->fl6_src)) + flags |= RT6_LOOKUP_F_HAS_SADDR; + return fib6_rule_lookup(fl, flags, ip6_pol_route_output); } @@ -1345,6 +1355,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, struct in6_addr *gateway, struct net_device *dev) { + int flags = RT6_LOOKUP_F_HAS_SADDR; struct ip6rd_flowi rdfl = { .fl = { .oif = dev->ifindex, @@ -1357,7 +1368,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, }, .gateway = *gateway, }; - int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0; + + if (rt6_need_strict(dest)) + flags |= RT6_LOOKUP_F_IFACE; return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); } -- GitLab From f1a95859a86fcdfd94f8b6dc3255d70d037e1caf Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 13 Oct 2006 15:03:34 -0700 Subject: [PATCH 1245/1619] [IPV6]: Remove bogus WARN_ON in Proxy-NA handling. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0304b5fe8d6..41a8a5f0660 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -967,8 +967,6 @@ static void ndisc_recv_na(struct sk_buff *skb) ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) { /* XXX: idev->cnf.prixy_ndp */ - WARN_ON(skb->dst != NULL && - ((struct rt6_info *)skb->dst)->rt6i_idev); goto out; } -- GitLab From 39c850863d5e36e72ecf9bc3537ec717bcce97fd Mon Sep 17 00:00:00 2001 From: Jan Dittmer Date: Fri, 13 Oct 2006 15:05:53 -0700 Subject: [PATCH 1246/1619] [IPV6] sit: Add missing MODULE_LICENSE This is missing the MODULE_LICENSE statements and taints the kernel upon loading. License is obvious from the beginning of the file. Signed-off-by: Jan Dittmer Signed-off-by: Joerg Roedel Signed-off-by: David S. Miller --- net/ipv6/sit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index dc5765b62b8..b481a4d780c 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -853,3 +853,4 @@ int __init sit_init(void) module_init(sit_init); module_exit(sit_cleanup); +MODULE_LICENSE("GPL"); -- GitLab From e9c5702e3c5558dade169949abd730173e87ef9c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:30:22 +0200 Subject: [PATCH 1247/1619] [Bluetooth] Fix compat ioctl for BNEP, CMTP and HIDP There exists no attempt do deal with the fact that a structure with a uint32_t followed by a pointer is going to be different for 32-bit and 64-bit userspace. Any 32-bit process trying to use it will be failing with -EFAULT if it's lucky; suffering from having data dumped at a random address if it's not. Signed-off-by: David Woodhouse Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/sock.c | 67 ++++++++++++++++++++++++--------- net/bluetooth/cmtp/sock.c | 33 +++++++++++++++++ net/bluetooth/hidp/sock.c | 78 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 17 deletions(-) diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 28c55835422..5d9d6f14b31 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -146,24 +147,56 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return 0; } +#ifdef CONFIG_COMPAT +static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + if (cmd == BNEPGETCONNLIST) { + struct bnep_connlist_req cl; + uint32_t uci; + int err; + + if (get_user(cl.cnum, (uint32_t __user *) arg) || + get_user(uci, (u32 __user *) (arg + 4))) + return -EFAULT; + + cl.ci = compat_ptr(uci); + + if (cl.cnum <= 0) + return -EINVAL; + + err = bnep_get_connlist(&cl); + + if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + err = -EFAULT; + + return err; + } + + return bnep_sock_ioctl(sock, cmd, arg); +} +#endif + static const struct proto_ops bnep_sock_ops = { - .family = PF_BLUETOOTH, - .owner = THIS_MODULE, - .release = bnep_sock_release, - .ioctl = bnep_sock_ioctl, - .bind = sock_no_bind, - .getname = sock_no_getname, - .sendmsg = sock_no_sendmsg, - .recvmsg = sock_no_recvmsg, - .poll = sock_no_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .mmap = sock_no_mmap + .family = PF_BLUETOOTH, + .owner = THIS_MODULE, + .release = bnep_sock_release, + .ioctl = bnep_sock_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = bnep_sock_compat_ioctl, +#endif + .bind = sock_no_bind, + .getname = sock_no_getname, + .sendmsg = sock_no_sendmsg, + .recvmsg = sock_no_recvmsg, + .poll = sock_no_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .mmap = sock_no_mmap }; static struct proto bnep_proto = { diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 10ad7fd91d8..0547edd5773 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -137,11 +138,43 @@ static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return -EINVAL; } +#ifdef CONFIG_COMPAT +static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + if (cmd == CMTPGETCONNLIST) { + struct cmtp_connlist_req cl; + uint32_t uci; + int err; + + if (get_user(cl.cnum, (uint32_t __user *) arg) || + get_user(uci, (u32 __user *) (arg + 4))) + return -EFAULT; + + cl.ci = compat_ptr(uci); + + if (cl.cnum <= 0) + return -EINVAL; + + err = cmtp_get_connlist(&cl); + + if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + err = -EFAULT; + + return err; + } + + return cmtp_sock_ioctl(sock, cmd, arg); +} +#endif + static const struct proto_ops cmtp_sock_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .release = cmtp_sock_release, .ioctl = cmtp_sock_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = cmtp_sock_compat_ioctl, +#endif .bind = sock_no_bind, .getname = sock_no_getname, .sendmsg = sock_no_sendmsg, diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 099646e4e2e..6242446aa27 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "hidp.h" @@ -143,11 +144,88 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return -EINVAL; } +#ifdef CONFIG_COMPAT +struct compat_hidp_connadd_req { + int ctrl_sock; // Connected control socket + int intr_sock; // Connteted interrupt socket + __u16 parser; + __u16 rd_size; + compat_uptr_t rd_data; + __u8 country; + __u8 subclass; + __u16 vendor; + __u16 product; + __u16 version; + __u32 flags; + __u32 idle_to; + char name[128]; +}; + +static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + if (cmd == HIDPGETCONNLIST) { + struct hidp_connlist_req cl; + uint32_t uci; + int err; + + if (get_user(cl.cnum, (uint32_t __user *) arg) || + get_user(uci, (u32 __user *) (arg + 4))) + return -EFAULT; + + cl.ci = compat_ptr(uci); + + if (cl.cnum <= 0) + return -EINVAL; + + err = hidp_get_connlist(&cl); + + if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + err = -EFAULT; + + return err; + } else if (cmd == HIDPCONNADD) { + struct compat_hidp_connadd_req ca; + struct hidp_connadd_req __user *uca; + + uca = compat_alloc_user_space(sizeof(*uca)); + + if (copy_from_user(&ca, (void *) arg, sizeof(ca))) + return -EFAULT; + + if (put_user(ca.ctrl_sock, &uca->ctrl_sock) || + put_user(ca.intr_sock, &uca->intr_sock) || + put_user(ca.parser, &uca->parser) || + put_user(ca.rd_size, &uca->parser) || + put_user(compat_ptr(ca.rd_data), &uca->rd_data) || + put_user(ca.country, &uca->country) || + put_user(ca.subclass, &uca->subclass) || + put_user(ca.vendor, &uca->vendor) || + put_user(ca.product, &uca->product) || + put_user(ca.version, &uca->version) || + put_user(ca.flags, &uca->flags) || + put_user(ca.idle_to, &uca->idle_to) || + copy_to_user(&uca->name[0], &ca.name[0], 128)) + return -EFAULT; + + arg = (unsigned long) uca; + + /* Fall through. We don't actually write back any _changes_ + to the structure anyway, so there's no need to copy back + into the original compat version */ + } + + return hidp_sock_ioctl(sock, cmd, arg); +} +#endif + static const struct proto_ops hidp_sock_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .release = hidp_sock_release, .ioctl = hidp_sock_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = hidp_sock_compat_ioctl, +#endif .bind = sock_no_bind, .getname = sock_no_getname, .sendmsg = sock_no_sendmsg, -- GitLab From df5c37ea9a3820a9515d8204450aec00f48f8f88 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:30:45 +0200 Subject: [PATCH 1248/1619] [Bluetooth] Handle return values from driver core functions Some return values of the driver core register and create functions are not handled and so might cause unexpected problems. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sysfs.c | 11 ++++++++--- net/bluetooth/l2cap.c | 3 ++- net/bluetooth/rfcomm/core.c | 3 ++- net/bluetooth/rfcomm/sock.c | 3 ++- net/bluetooth/sco.c | 3 ++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 989b22d9042..c7e079d3c48 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -242,10 +242,14 @@ static void add_conn(void *data) struct hci_conn *conn = data; int i; - device_register(&conn->dev); + if (device_register(&conn->dev) < 0) { + BT_ERR("Failed to register connection device"); + return; + } for (i = 0; conn_attrs[i]; i++) - device_create_file(&conn->dev, conn_attrs[i]); + if (device_create_file(&conn->dev, conn_attrs[i]) < 0) + BT_ERR("Failed to create connection attribute"); } void hci_conn_add_sysfs(struct hci_conn *conn) @@ -312,7 +316,8 @@ int hci_register_sysfs(struct hci_dev *hdev) return err; for (i = 0; bt_attrs[i]; i++) - device_create_file(dev, bt_attrs[i]); + if (device_create_file(dev, bt_attrs[i]) < 0) + BT_ERR("Failed to create device attribute"); return 0; } diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index d56f60b392a..66fc621a077 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2216,7 +2216,8 @@ static int __init l2cap_init(void) goto error; } - class_create_file(bt_class, &class_attr_l2cap); + if (class_create_file(bt_class, &class_attr_l2cap) < 0) + BT_ERR("Failed to create L2CAP info file"); BT_INFO("L2CAP ver %s", VERSION); BT_INFO("L2CAP socket layer initialized"); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 468df3b953f..ddc4e9d5963 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2058,7 +2058,8 @@ static int __init rfcomm_init(void) kernel_thread(rfcomm_run, NULL, CLONE_KERNEL); - class_create_file(bt_class, &class_attr_rfcomm_dlc); + if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0) + BT_ERR("Failed to create RFCOMM info file"); rfcomm_init_sockets(); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 220fee04e7f..530cc41f3a2 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -944,7 +944,8 @@ int __init rfcomm_init_sockets(void) if (err < 0) goto error; - class_create_file(bt_class, &class_attr_rfcomm); + if (class_create_file(bt_class, &class_attr_rfcomm) < 0) + BT_ERR("Failed to create RFCOMM info file"); BT_INFO("RFCOMM socket layer initialized"); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 7714a2ec385..14b0f693063 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -967,7 +967,8 @@ static int __init sco_init(void) goto error; } - class_create_file(bt_class, &class_attr_sco); + if (class_create_file(bt_class, &class_attr_sco) < 0) + BT_ERR("Failed to create SCO info file"); BT_INFO("SCO (Voice Link) ver %s", VERSION); BT_INFO("SCO socket layer initialized"); -- GitLab From e9c4bec63eac001651d6d30239dd4175cc3698ef Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:30:50 +0200 Subject: [PATCH 1249/1619] [Bluetooth] Make use of virtual devices tree The Bluetooth subsystem currently uses a platform device for devices with no parent. It is a better idea to use the new virtual devices tree for these. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sysfs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index c7e079d3c48..954eb74eb37 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -299,11 +299,7 @@ int hci_register_sysfs(struct hci_dev *hdev) BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); dev->class = bt_class; - - if (hdev->parent) - dev->parent = hdev->parent; - else - dev->parent = &bt_platform->dev; + dev->parent = hdev->parent; strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE); -- GitLab From 4c67bc74f016b0d360b8573e18969c0ff7926974 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:30:56 +0200 Subject: [PATCH 1250/1619] [Bluetooth] Support concurrent connect requests Most Bluetooth chips don't support concurrent connect requests, because this would involve a multiple baseband page with only one radio. In the case an upper layer like L2CAP requests a concurrent connect these chips return the error "Command Disallowed" for the second request. If this happens it the responsibility of the Bluetooth core to queue the request and try again after the previous connect attempt has been completed. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 17 +++++++++++++++++ net/bluetooth/af_bluetooth.c | 2 +- net/bluetooth/hci_conn.c | 6 ++++-- net/bluetooth/hci_event.c | 15 +++++++++++---- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index df22efcfcc0..c0fc39620f3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -153,6 +153,7 @@ struct hci_conn { __u8 mode; __u8 type; __u8 out; + __u8 attempt; __u8 dev_class[3]; __u8 features[8]; __u16 interval; @@ -289,6 +290,22 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, return NULL; } +static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, + __u8 type, __u16 state) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->type == type && c->state == state) + return c; + } + return NULL; +} + +void hci_acl_connect(struct hci_conn *conn); void hci_acl_disconn(struct hci_conn *conn, __u8 reason); void hci_add_sco(struct hci_conn *conn, __u16 handle); diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 305a099b747..a91fee4f270 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -48,7 +48,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.10" +#define VERSION "2.11" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 90e3a285a17..6cd5711fa28 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -51,7 +51,7 @@ #define BT_DBG(D...) #endif -static void hci_acl_connect(struct hci_conn *conn) +void hci_acl_connect(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; struct inquiry_entry *ie; @@ -63,6 +63,8 @@ static void hci_acl_connect(struct hci_conn *conn) conn->out = 1; conn->link_mode = HCI_LM_MASTER; + conn->attempt++; + memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; @@ -80,7 +82,7 @@ static void hci_acl_connect(struct hci_conn *conn) cp.role_switch = 0x01; else cp.role_switch = 0x00; - + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d43d0c89097..65f09484571 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -414,9 +414,12 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (status) { if (conn && conn->state == BT_CONNECT) { - conn->state = BT_CLOSED; - hci_proto_connect_cfm(conn, status); - hci_conn_del(conn); + if (status != 0x0c || conn->attempt > 2) { + conn->state = BT_CLOSED; + hci_proto_connect_cfm(conn, status); + hci_conn_del(conn); + } else + conn->state = BT_CONNECT2; } } else { if (!conn) { @@ -728,7 +731,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; - struct hci_conn *conn; + struct hci_conn *conn, *pend; BT_DBG("%s", hdev->name); @@ -801,6 +804,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (ev->status) hci_conn_del(conn); + pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); + if (pend) + hci_acl_connect(pend); + hci_dev_unlock(hdev); } -- GitLab From e86070c83e9110e89800274385c013db602b1444 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:31:00 +0200 Subject: [PATCH 1251/1619] [Bluetooth] Disconnect HID interrupt channel first The Bluetooth HID specification demands that the interrupt channel shall be disconnected first. This is needed to pass the qualification tests. Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 03b5dadb495..b2d6da67d88 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -510,11 +510,11 @@ static int hidp_session(void *arg) if (intr_sk->sk_state != BT_CONNECTED) wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ); - fput(session->ctrl_sock->file); + fput(session->intr_sock->file); wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ); - fput(session->intr_sock->file); + fput(session->ctrl_sock->file); __hidp_unlink_session(session); -- GitLab From b2cfcd75df77b80d9cc3fa84190a350dfa79eb93 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:31:05 +0200 Subject: [PATCH 1252/1619] [Bluetooth] Fix reference count when connection lookup fails When the connection lookup for the device structure fails, the reference count for the HCI device needs to be decremented. Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/core.c | 4 +--- net/bluetooth/hidp/core.c | 4 +--- net/bluetooth/rfcomm/tty.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 2312d050eee..4d3424c2421 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -528,12 +528,10 @@ static struct device *bnep_get_device(struct bnep_session *session) return NULL; conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); - if (!conn) - return NULL; hci_dev_put(hdev); - return &conn->dev; + return conn ? &conn->dev : NULL; } int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index b2d6da67d88..9a562cf7406 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -541,12 +541,10 @@ static struct device *hidp_get_device(struct hidp_session *session) return NULL; conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); - if (!conn) - return NULL; hci_dev_put(hdev); - return &conn->dev; + return conn ? &conn->dev : NULL; } static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 1958ad1b854..5833b87c51c 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -172,12 +172,10 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev) return NULL; conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); - if (!conn) - return NULL; hci_dev_put(hdev); - return &conn->dev; + return conn ? &conn->dev : NULL; } static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) -- GitLab From cb19d9ea2ce2bcbe291d3d48e3501dc4f33ba627 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:31:10 +0200 Subject: [PATCH 1253/1619] [Bluetooth] Check if DLC is still attached to the TTY If the DLC device is no longer attached to the TTY device, then it makes no sense to go through with changing the termios settings. Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 5833b87c51c..b8e3a5f1c8a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -765,6 +765,9 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old) BT_DBG("tty %p termios %p", tty, old); + if (!dev) + return; + /* Handle turning off CRTSCTS */ if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS)) BT_DBG("Turning off CRTSCTS unsupported"); -- GitLab From 74da626a1098640ddc40c0e3481c0cd41e8ec1e9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:31:14 +0200 Subject: [PATCH 1254/1619] [Bluetooth] Add locking for bt_proto array manipulation The bt_proto array needs to be protected by some kind of locking to prevent a race condition between bt_sock_create and bt_sock_register. And in addition all calls to sk_alloc need to be made GFP_ATOMIC now. Signed-off-by: Masatake YAMATO Signed-off-by: Frederik Deweerdt Signed-off-by: Marcel Holtmann --- net/bluetooth/af_bluetooth.c | 36 +++++++++++++++++++++++++++++------- net/bluetooth/bnep/sock.c | 2 +- net/bluetooth/cmtp/sock.c | 2 +- net/bluetooth/hci_sock.c | 2 +- net/bluetooth/hidp/sock.c | 2 +- net/bluetooth/l2cap.c | 2 +- net/bluetooth/rfcomm/sock.c | 3 ++- net/bluetooth/sco.c | 3 ++- 8 files changed, 38 insertions(+), 14 deletions(-) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index a91fee4f270..67df99e2e5c 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -53,36 +53,51 @@ /* Bluetooth sockets */ #define BT_MAX_PROTO 8 static struct net_proto_family *bt_proto[BT_MAX_PROTO]; +static DEFINE_RWLOCK(bt_proto_lock); int bt_sock_register(int proto, struct net_proto_family *ops) { + int err = 0; + if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; + write_lock(&bt_proto_lock); + if (bt_proto[proto]) - return -EEXIST; + err = -EEXIST; + else + bt_proto[proto] = ops; - bt_proto[proto] = ops; - return 0; + write_unlock(&bt_proto_lock); + + return err; } EXPORT_SYMBOL(bt_sock_register); int bt_sock_unregister(int proto) { + int err = 0; + if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; + write_lock(&bt_proto_lock); + if (!bt_proto[proto]) - return -ENOENT; + err = -ENOENT; + else + bt_proto[proto] = NULL; - bt_proto[proto] = NULL; - return 0; + write_unlock(&bt_proto_lock); + + return err; } EXPORT_SYMBOL(bt_sock_unregister); static int bt_sock_create(struct socket *sock, int proto) { - int err = 0; + int err; if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; @@ -92,11 +107,18 @@ static int bt_sock_create(struct socket *sock, int proto) request_module("bt-proto-%d", proto); } #endif + err = -EPROTONOSUPPORT; + + read_lock(&bt_proto_lock); + if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { err = bt_proto[proto]->create(sock, proto); module_put(bt_proto[proto]->owner); } + + read_unlock(&bt_proto_lock); + return err; } diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 5d9d6f14b31..5563db1bf52 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -214,7 +214,7 @@ static int bnep_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &bnep_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 0547edd5773..53295d33dc5 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -205,7 +205,7 @@ static int cmtp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1a35d343e08..f26a9eb4994 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -618,7 +618,7 @@ static int hci_sock_create(struct socket *sock, int protocol) sock->ops = &hci_sock_ops; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 6242446aa27..407fba43c1b 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -256,7 +256,7 @@ static int hidp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 66fc621a077..2b3dcb8f90f 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -559,7 +559,7 @@ static int l2cap_sock_create(struct socket *sock, int protocol) sock->ops = &l2cap_sock_ops; - sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL); + sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 530cc41f3a2..544d65b7baa 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -336,7 +336,8 @@ static int rfcomm_sock_create(struct socket *sock, int protocol) sock->ops = &rfcomm_sock_ops; - if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL))) + sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC); + if (!sk) return -ENOMEM; rfcomm_sock_init(sk, NULL); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 14b0f693063..5d13d4f3175 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -452,7 +452,8 @@ static int sco_sock_create(struct socket *sock, int protocol) sock->ops = &sco_sock_ops; - if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL))) + sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC); + if (!sk) return -ENOMEM; sco_sock_init(sk, NULL); -- GitLab From 3f5306927d800306ebba542438cfdf1a1c418376 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 15 Oct 2006 17:31:19 +0200 Subject: [PATCH 1255/1619] [Bluetooth] Use work queue to trigger URB submission The bcm203x firmware loading driver uses a timer to trigger the URB submission. It is better to use a work queue instead. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bcm203x.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 67cdda43f22..516751754aa 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -43,7 +42,7 @@ #define BT_DBG(D...) #endif -#define VERSION "1.0" +#define VERSION "1.1" static int ignore = 0; @@ -72,7 +71,7 @@ struct bcm203x_data { unsigned long state; - struct timer_list timer; + struct work_struct work; struct urb *urb; unsigned char *buffer; @@ -105,7 +104,7 @@ static void bcm203x_complete(struct urb *urb) data->state = BCM203X_SELECT_MEMORY; - mod_timer(&data->timer, jiffies + (HZ / 10)); + schedule_work(&data->work); break; case BCM203X_SELECT_MEMORY: @@ -158,9 +157,9 @@ static void bcm203x_complete(struct urb *urb) } } -static void bcm203x_timer(unsigned long user_data) +static void bcm203x_work(void *user_data) { - struct bcm203x_data *data = (struct bcm203x_data *) user_data; + struct bcm203x_data *data = user_data; if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) BT_ERR("Can't submit URB"); @@ -247,13 +246,11 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id release_firmware(firmware); - init_timer(&data->timer); - data->timer.function = bcm203x_timer; - data->timer.data = (unsigned long) data; + INIT_WORK(&data->work, bcm203x_work, (void *) data); usb_set_intfdata(intf, data); - mod_timer(&data->timer, jiffies + HZ); + schedule_work(&data->work); return 0; } -- GitLab From 43518407d57f1b685f5a9f1a981734ce66a21f76 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 16 Oct 2006 21:28:58 +1000 Subject: [PATCH 1256/1619] [CRYPTO] api: Select cryptomgr where needed Since cryptomgr is the only way to construct algorithm instances for now it makes sense to let the templates depend on it as otherwise it may be left off inadvertently. Signed-off-by: Herbert Xu --- crypto/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 1e2f39c2118..cbae8392ce1 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -27,7 +27,6 @@ config CRYPTO_HASH config CRYPTO_MANAGER tristate "Cryptographic algorithm manager" select CRYPTO_ALGAPI - default m help Create default cryptographic template instantiations such as cbc(aes). @@ -35,6 +34,7 @@ config CRYPTO_MANAGER config CRYPTO_HMAC tristate "HMAC support" select CRYPTO_HASH + select CRYPTO_MANAGER help HMAC: Keyed-Hashing for Message Authentication (RFC2104). This is required for IPSec. @@ -131,6 +131,7 @@ config CRYPTO_TGR192 config CRYPTO_ECB tristate "ECB support" select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER default m help ECB: Electronic CodeBook mode @@ -140,6 +141,7 @@ config CRYPTO_ECB config CRYPTO_CBC tristate "CBC support" select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER default m help CBC: Cipher Block Chaining mode -- GitLab From 9d90dafdb1f0e3c2b69fa8d3fbe99649127c8fa4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:28:44 +0100 Subject: [PATCH 1257/1619] [PATCH] rio: fix array checking Found by an analysis tool and reported to the list. Fix is simple enough Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/char/rio/rioctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index 052e8120a47..7ce77619707 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -662,7 +662,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su p->RIOError.Error = COPYIN_FAILED; return -EFAULT; } - if (portStats.port >= RIO_PORTS) { + if (portStats.port < 0 || portStats.port >= RIO_PORTS) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return -ENXIO; } @@ -702,7 +702,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su p->RIOError.Error = COPYIN_FAILED; return -EFAULT; } - if (portStats.port >= RIO_PORTS) { + if (portStats.port < 0 || portStats.port >= RIO_PORTS) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return -ENXIO; } -- GitLab From 3a42bb223f61fbd755d6e61b9b50b9681d68fcae Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:31:02 +0100 Subject: [PATCH 1258/1619] [PATCH] ide: add sanity checking to ide taskfile ioctl Without this the user can feed in bogus values and get very bogus results. Security impact is minimal as this ioctl isn't available to unpriviledged processes anyway. Reported to the l/k list and found with an auditing tool. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/ide/ide-taskfile.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 1d0470c1f95..30175c7688e 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -524,8 +524,8 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) task_ioreg_t *hobsptr = args.hobRegister; int err = 0; int tasksize = sizeof(struct ide_task_request_s); - int taskin = 0; - int taskout = 0; + unsigned int taskin = 0; + unsigned int taskout = 0; u8 io_32bit = drive->io_32bit; char __user *buf = (char __user *)arg; @@ -538,8 +538,13 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) return -EFAULT; } - taskout = (int) req_task->out_size; - taskin = (int) req_task->in_size; + taskout = req_task->out_size; + taskin = req_task->in_size; + + if (taskin > 65536 || taskout > 65536) { + err = -EINVAL; + goto abort; + } if (taskout) { int outtotal = tasksize; -- GitLab From 8741ca71a3f626a56595b88200ebf952ce77ceef Mon Sep 17 00:00:00 2001 From: Andrey Mirkin Date: Mon, 16 Oct 2006 12:08:43 +0400 Subject: [PATCH 1259/1619] [PATCH] scsi: megaraid_{mm,mbox}: 64-bit DMA capability fix It is known that 2 LSI Logic MegaRAID SATA RAID Controllers (150-4 and 150-6) don't support 64-bit DMA. Unfortunately currently this check is wrong and driver sets 64-bit DMA mode for these devices. Signed-off-by: Andrey Mirkin Acked-by: Vasily Averin Signed-off-by: Linus Torvalds --- drivers/scsi/megaraid/megaraid_mbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c0edb662d86..7bac86dda88 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -884,7 +884,7 @@ megaraid_init_mbox(adapter_t *adapter) if (((magic64 == HBA_SIGNATURE_64_BIT) && ((adapter->pdev->subsystem_device != - PCI_SUBSYS_ID_MEGARAID_SATA_150_6) || + PCI_SUBSYS_ID_MEGARAID_SATA_150_6) && (adapter->pdev->subsystem_device != PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && -- GitLab From 29da7eb0ec69245c6e9b4eb5bdaa04af685f5c4f Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 16 Oct 2006 14:10:49 +0100 Subject: [PATCH 1260/1619] [PATCH] FRV: Use the correct preemption primitives in kmap_atomic() and co Use inc/dec_preempt_count() rather than preempt_enable/disable() and manually add in the compiler barriers that were provided by the latter. This makes FRV consistent with other archs. Furthermore, the compiler barrier effects are now there unconditionally - at least as far as preemption is concerned - because we don't want the compiler moving memory accesses out of the section of code in which the mapping is in force - in effect the kmap_atomic() must imply a LOCK-class barrier and the kunmap_atomic() must imply an UNLOCK-class barrier to the compiler. Signed-off-by: David Howells Acked-by: Peter Zijlstra Signed-off-by: Linus Torvalds --- include/asm-frv/highmem.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h index e2247c22a63..0f390f41f81 100644 --- a/include/asm-frv/highmem.h +++ b/include/asm-frv/highmem.h @@ -82,11 +82,11 @@ extern struct page *kmap_atomic_to_page(void *ptr); dampr = paddr | xAMPRx_L | xAMPRx_M | xAMPRx_S | xAMPRx_SS_16Kb | xAMPRx_V; \ \ if (type != __KM_CACHE) \ - asm volatile("movgs %0,dampr"#ampr :: "r"(dampr)); \ + asm volatile("movgs %0,dampr"#ampr :: "r"(dampr) : "memory"); \ else \ asm volatile("movgs %0,iampr"#ampr"\n" \ "movgs %0,dampr"#ampr"\n" \ - :: "r"(dampr) \ + :: "r"(dampr) : "memory" \ ); \ \ asm("movsg damlr"#ampr",%0" : "=r"(damlr)); \ @@ -104,7 +104,7 @@ extern struct page *kmap_atomic_to_page(void *ptr); asm volatile("movgs %0,tplr \n" \ "movgs %1,tppr \n" \ "tlbpr %0,gr0,#2,#1" \ - : : "r"(damlr), "r"(dampr)); \ + : : "r"(damlr), "r"(dampr) : "memory"); \ \ /*printk("TLB: SECN sl=%d L=%08lx P=%08lx\n", slot, damlr, dampr);*/ \ \ @@ -115,7 +115,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) { unsigned long paddr; - preempt_disable(); + inc_preempt_count(); paddr = page_to_phys(page); switch (type) { @@ -138,16 +138,16 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) } } -#define __kunmap_atomic_primary(type, ampr) \ -do { \ - asm volatile("movgs gr0,dampr"#ampr"\n"); \ - if (type == __KM_CACHE) \ - asm volatile("movgs gr0,iampr"#ampr"\n"); \ +#define __kunmap_atomic_primary(type, ampr) \ +do { \ + asm volatile("movgs gr0,dampr"#ampr"\n" ::: "memory"); \ + if (type == __KM_CACHE) \ + asm volatile("movgs gr0,iampr"#ampr"\n" ::: "memory"); \ } while(0) -#define __kunmap_atomic_secondary(slot, vaddr) \ -do { \ - asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr)); \ +#define __kunmap_atomic_secondary(slot, vaddr) \ +do { \ + asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory"); \ } while(0) static inline void kunmap_atomic(void *kvaddr, enum km_type type) @@ -170,7 +170,8 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) default: BUG(); } - preempt_enable(); + dec_preempt_count(); + preempt_check_resched(); } #endif /* !__ASSEMBLY__ */ -- GitLab From 39af114377bf80d2a88e47be33d578d1fa9b0775 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 16 Oct 2006 09:01:46 -0700 Subject: [PATCH 1261/1619] [PATCH] fix epoll_pwait when EPOLL=n Fixes http://bugzilla.kernel.org/show_bug.cgi?id=7371 sys_epoll_pwait needs to be listed as a conditional (weak) entry point for CONFIG_EPOLL=n. Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- kernel/sys_ni.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 7a3b2e75f04..0e53314b14d 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -49,6 +49,7 @@ cond_syscall(compat_sys_get_robust_list); cond_syscall(sys_epoll_create); cond_syscall(sys_epoll_ctl); cond_syscall(sys_epoll_wait); +cond_syscall(sys_epoll_pwait); cond_syscall(sys_semget); cond_syscall(sys_semop); cond_syscall(sys_semtimedop); -- GitLab From d986a27413aad10574f7211524de6a529870d134 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Tue, 10 Oct 2006 14:26:01 -0700 Subject: [PATCH 1262/1619] RDMA/amso1100: pci_module_init() conversion pci_module_init() convertion in amso1100 driver. Signed-off-by: Henrik Kretzschmar Signed-off-by: Andrew Morton Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index dc1ebeac35c..9e7bd94b958 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -1243,7 +1243,7 @@ static struct pci_driver c2_pci_driver = { static int __init c2_init_module(void) { - return pci_module_init(&c2_pci_driver); + return pci_register_driver(&c2_pci_driver); } static void __exit c2_exit_module(void) -- GitLab From fb7711e71ea7cd0d3e77e969df59162388c8a1f9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 10 Oct 2006 14:26:02 -0700 Subject: [PATCH 1263/1619] RDMA/amso1100: Fix a NULL dereference in error path This patch fixes a NULL dereference spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Acked-by: Steve Wise Acked-by: Tom Tucker Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2_rnic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c index e37c5688c21..30409e17960 100644 --- a/drivers/infiniband/hw/amso1100/c2_rnic.c +++ b/drivers/infiniband/hw/amso1100/c2_rnic.c @@ -150,8 +150,8 @@ static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props) (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) err = -ENOMEM; - - err = c2_errno(reply); + else + err = c2_errno(reply); if (err) goto bail2; -- GitLab From 6ef93dddfe11a72ab98a37ac4ef20ad681b008b0 Mon Sep 17 00:00:00 2001 From: Robert Walsh Date: Tue, 10 Oct 2006 14:55:45 -0700 Subject: [PATCH 1264/1619] IB/ipath: Initialize diagpkt file on device init only Don't attempt to set up the diagpkt device in the module init code. Instead, wait until a piece of hardware is initialized. Fixes a problem when loading the ib_ipath module when no InfiniPath hardware is present: modprobe would go into the D state and stay there. Signed-off-by: Robert Walsh Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_diag.c | 65 +++++++++++++--------- drivers/infiniband/hw/ipath/ipath_driver.c | 10 ---- drivers/infiniband/hw/ipath/ipath_kernel.h | 3 - 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 29958b6e021..28c087b824c 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -67,19 +67,54 @@ static struct file_operations diag_file_ops = { .release = ipath_diag_release }; +static ssize_t ipath_diagpkt_write(struct file *fp, + const char __user *data, + size_t count, loff_t *off); + +static struct file_operations diagpkt_file_ops = { + .owner = THIS_MODULE, + .write = ipath_diagpkt_write, +}; + +static atomic_t diagpkt_count = ATOMIC_INIT(0); +static struct cdev *diagpkt_cdev; +static struct class_device *diagpkt_class_dev; + int ipath_diag_add(struct ipath_devdata *dd) { char name[16]; + int ret = 0; + + if (atomic_inc_return(&diagpkt_count) == 1) { + ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR, + "ipath_diagpkt", &diagpkt_file_ops, + &diagpkt_cdev, &diagpkt_class_dev); + + if (ret) { + ipath_dev_err(dd, "Couldn't create ipath_diagpkt " + "device: %d", ret); + goto done; + } + } snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit); - return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name, - &diag_file_ops, &dd->diag_cdev, - &dd->diag_class_dev); + ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name, + &diag_file_ops, &dd->diag_cdev, + &dd->diag_class_dev); + if (ret) + ipath_dev_err(dd, "Couldn't create %s device: %d", + name, ret); + +done: + return ret; } void ipath_diag_remove(struct ipath_devdata *dd) { + if (atomic_dec_and_test(&diagpkt_count)) + ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev); + ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev); } @@ -275,30 +310,6 @@ bail: return ret; } -static ssize_t ipath_diagpkt_write(struct file *fp, - const char __user *data, - size_t count, loff_t *off); - -static struct file_operations diagpkt_file_ops = { - .owner = THIS_MODULE, - .write = ipath_diagpkt_write, -}; - -static struct cdev *diagpkt_cdev; -static struct class_device *diagpkt_class_dev; - -int __init ipath_diagpkt_add(void) -{ - return ipath_cdev_init(IPATH_DIAGPKT_MINOR, - "ipath_diagpkt", &diagpkt_file_ops, - &diagpkt_cdev, &diagpkt_class_dev); -} - -void __exit ipath_diagpkt_remove(void) -{ - ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev); -} - /** * ipath_diagpkt_write - write an IB packet * @fp: the diag data device file pointer diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 12cefa658f3..b4ffaa7bcbb 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -2005,18 +2005,8 @@ static int __init infinipath_init(void) goto bail_group; } - ret = ipath_diagpkt_add(); - if (ret < 0) { - printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " - "diag data device: error %d\n", -ret); - goto bail_ipathfs; - } - goto bail; -bail_ipathfs: - ipath_exit_ipathfs(); - bail_group: ipath_driver_remove_group(&ipath_driver.driver); diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 7c436697d0e..06d5020a2f6 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -869,9 +869,6 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *); void ipath_device_remove_group(struct device *, struct ipath_devdata *); int ipath_expose_reset(struct device *); -int ipath_diagpkt_add(void); -void ipath_diagpkt_remove(void); - int ipath_init_ipathfs(void); void ipath_exit_ipathfs(void); int ipathfs_add_device(struct ipath_devdata *); -- GitLab From 4d99bfac9d5ce53b383d3c8279b917050be4e06c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 16 Oct 2006 19:59:43 +0200 Subject: [PATCH 1265/1619] [PATCH] CONFIG_TELCLOCK depends on X86 The telecom clock driver for MPBL0010 ATCA SBC depends on X86 Signed-off-by: Geert Uytterhoeven Acked-by: Mark Gross Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 0e6f35fcc2e..39a9f8cc641 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1046,7 +1046,7 @@ source "drivers/char/tpm/Kconfig" config TELCLOCK tristate "Telecom clock driver for MPBL0010 ATCA SBC" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && X86 default n help The telecom clock device is specific to the MPBL0010 ATCA computer and -- GitLab From 0f6f65f607b6d516fa001e8cdf5a2618c81372f5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 16 Oct 2006 21:14:51 +0100 Subject: [PATCH 1266/1619] [ARM] Update mach-types Signed-off-by: Russell King --- arch/arm/tools/mach-types | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index b02af1d740f..579c69ae9ff 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -4,7 +4,7 @@ # # Up to date versions of this file can be obtained from: # -# http://www.arm.linux.org.uk/developer/machines/?action=download +# http://www.arm.linux.org.uk/developer/machines/download.php # # Please do not send patches to this file; it is automatically generated! # To add an entry into this database, please see Documentation/arm/README, @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Sat Sep 23 13:20:43 2006 +# Last update: Mon Oct 16 21:13:36 2006 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -1157,3 +1157,17 @@ adsturboxb MACH_ADSTURBOXB ADSTURBOXB 1143 oti4110 MACH_OTI4110 OTI4110 1144 hme_pxa MACH_HME_PXA HME_PXA 1145 deisterdca MACH_DEISTERDCA DEISTERDCA 1146 +ces_ssem2 MACH_CES_SSEM2 CES_SSEM2 1147 +ces_mtr MACH_CES_MTR CES_MTR 1148 +tds_avng_sbc MACH_TDS_AVNG_SBC TDS_AVNG_SBC 1149 +everest MACH_EVEREST EVEREST 1150 +pnx4010 MACH_PNX4010 PNX4010 1151 +oxnas MACH_OXNAS OXNAS 1152 +fiori MACH_FIORI FIORI 1153 +ml1200 MACH_ML1200 ML1200 1154 +cactus MACH_CACTUS CACTUS 1155 +nb2xxx MACH_NB2XXX NB2XXX 1156 +hw6900 MACH_HW6900 HW6900 1157 +cdcs_quoll MACH_CDCS_QUOLL CDCS_QUOLL 1158 +quicksilver MACH_QUICKSILVER QUICKSILVER 1159 +uplat926 MACH_UPLAT926 UPLAT926 1160 -- GitLab From 1f5c23e2c10d642a23aa3ebb449670a5184b6aab Mon Sep 17 00:00:00 2001 From: Arthur Kepner Date: Mon, 16 Oct 2006 20:22:35 -0700 Subject: [PATCH 1267/1619] IB/mthca: Use mmiowb after doorbell ring We discovered a problem when running IPoIB applications on multiple CPUs on an Altix system. Many messages such as: ib_mthca 0002:01:00.0: SQ 000014 full (19941644 head, 19941707 tail, 64 max, 0 nreq) appear in syslog, and the driver wedges up. Apparently this is because writes to the doorbells from different CPUs reach the device out of order. The following patch adds mmiowb() calls after doorbell rings to ensure the doorbell writes are ordered. Signed-off-by: Arthur Kepner Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cq.c | 7 +++++++ drivers/infiniband/hw/mthca/mthca_qp.c | 19 +++++++++++++++++++ drivers/infiniband/hw/mthca/mthca_srq.c | 8 ++++++++ 3 files changed, 34 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index e393681ba7d..149b3690123 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -39,6 +39,8 @@ #include #include +#include + #include #include "mthca_dev.h" @@ -210,6 +212,11 @@ static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq, mthca_write64(doorbell, dev->kar + MTHCA_CQ_DOORBELL, MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + /* + * Make sure doorbells don't leak out of CQ spinlock + * and reach the HCA out of order: + */ + mmiowb(); } } diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 5e5c58b9920..6a7822e0fc1 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -39,6 +39,8 @@ #include #include +#include + #include #include #include @@ -1732,6 +1734,11 @@ out: mthca_write64(doorbell, dev->kar + MTHCA_SEND_DOORBELL, MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + /* + * Make sure doorbells don't leak out of SQ spinlock + * and reach the HCA out of order: + */ + mmiowb(); } qp->sq.next_ind = ind; @@ -1851,6 +1858,12 @@ out: qp->rq.next_ind = ind; qp->rq.head += nreq; + /* + * Make sure doorbells don't leak out of RQ spinlock and reach + * the HCA out of order: + */ + mmiowb(); + spin_unlock_irqrestore(&qp->rq.lock, flags); return err; } @@ -2112,6 +2125,12 @@ out: MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); } + /* + * Make sure doorbells don't leak out of SQ spinlock and reach + * the HCA out of order: + */ + mmiowb(); + spin_unlock_irqrestore(&qp->sq.lock, flags); return err; } diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 92a72f52152..f5d7677d107 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -35,6 +35,8 @@ #include #include +#include + #include "mthca_dev.h" #include "mthca_cmd.h" #include "mthca_memfree.h" @@ -595,6 +597,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); } + /* + * Make sure doorbells don't leak out of SRQ spinlock and + * reach the HCA out of order: + */ + mmiowb(); + spin_unlock_irqrestore(&srq->lock, flags); return err; } -- GitLab From 107d5a72f2c6a6819b66eebcb0281c7a67b6baaa Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Tue, 17 Oct 2006 00:09:24 -0700 Subject: [PATCH 1268/1619] [PATCH] ioc4: Remove SN2 feature and config dependencies The SGI PCI-RT card, based on the SGI IOC4 chip, will be made available on Altix XE (x86_64) platforms in the near future. As such dependencies on SN2-specific features and config dependencies need to be removed. This patch updates the Kconfig files to remove the config dependency, and updates the IOC4 bus speed detection routine to use universally available time interfaces instead of mmtimer. Signed-off-by: Brent Casavant Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/sn/Kconfig | 13 ++++++------- drivers/sn/ioc4.c | 36 +++++++++++++++++------------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig index a3473162587..34d4fde51a7 100644 --- a/drivers/sn/Kconfig +++ b/drivers/sn/Kconfig @@ -7,16 +7,15 @@ menu "SN Devices" config SGI_IOC4 tristate "SGI IOC4 Base IO support" - depends on MMTIMER default m ---help--- - This option enables basic support for the SGI IOC4-based Base IO - controller card. This option does not enable any specific - functions on such a card, but provides necessary infrastructure - for other drivers to utilize. + This option enables basic support for the IOC4 chip on certain + SGI IO controller cards (IO9, IO10, and PCI-RT). This option + does not enable any specific functions on such a card, but provides + necessary infrastructure for other drivers to utilize. - If you have an SGI Altix with an IOC4-based - I/O controller say Y. Otherwise say N. + If you have an SGI Altix with an IOC4-based card say Y. + Otherwise say N. config SGI_IOC3 tristate "SGI IOC3 Base IO support" diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index 8562821e649..83d2e90c581 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2005-2006 Silicon Graphics, Inc. All Rights Reserved. */ /* This file contains the master driver module for use by SGI IOC4 subdrivers. @@ -29,9 +29,9 @@ #include #include #include -#include -#include +#include #include +#include #include #include #include @@ -43,7 +43,7 @@ /* Tweakable values */ /* PCI bus speed detection/calibration */ -#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */ +#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */ #define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */ #define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */ #define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */ @@ -143,11 +143,11 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) static void ioc4_clock_calibrate(struct ioc4_driver_data *idd) { - extern unsigned long sn_rtc_cycles_per_second; union ioc4_int_out int_out; union ioc4_gpcr gpcr; unsigned int state, last_state = 1; - uint64_t start = 0, end, period; + struct timespec start_ts, end_ts; + uint64_t start, end, period; unsigned int count = 0; /* Enable output */ @@ -175,30 +175,28 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) if (!last_state && state) { count++; if (count == IOC4_CALIBRATE_END) { - end = rtc_time(); + ktime_get_ts(&end_ts); break; } else if (count == IOC4_CALIBRATE_DISCARD) - start = rtc_time(); + ktime_get_ts(&start_ts); } last_state = state; } while (1); /* Calculation rearranged to preserve intermediate precision. * Logically: - * 1. "end - start" gives us number of RTC cycles over all the - * square wave cycles measured. - * 2. Divide by number of square wave cycles to get number of - * RTC cycles per square wave cycle. + * 1. "end - start" gives us the measurement period over all + * the square wave cycles. + * 2. Divide by number of square wave cycles to get the period + * of a square wave cycle. * 3. Divide by 2*(int_out.fields.count+1), which is the formula * by which the IOC4 generates the square wave, to get the - * number of RTC cycles per IOC4 INT_OUT count. - * 4. Divide by sn_rtc_cycles_per_second to get seconds per - * count. - * 5. Multiply by 1E9 to get nanoseconds per count. + * period of an IOC4 INT_OUT count. */ - period = ((end - start) * 1000000000) / - (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1) - * sn_rtc_cycles_per_second); + end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec; + start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec; + period = (end - start) / + (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)); /* Bounds check the result. */ if (period > IOC4_CALIBRATE_LOW_LIMIT || -- GitLab From 59f148005cfd3d41537a4b872c266213d5fe4dc6 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Tue, 17 Oct 2006 00:09:25 -0700 Subject: [PATCH 1269/1619] [PATCH] ioc4: Enable build on non-SN2 The SGI PCI-RT card, based on the SGI IOC4 chip, will be made available on Altix XE (x86_64) platforms in the near future. As such it is now a misnomer for the IOC4 base device driver to live under drivers/sn, and would complicate builds for non-SN2. This patch moves the IOC4 base driver code from drivers/sn to drivers/misc, and updates the associated Makefiles and Kconfig files to allow building on non-SN2 configs. Due to the resulting change in link order, it is now necessary to use late_initcall() for IOC4 subdriver initialization. [akpm@osdl.org: __udivdi3 fix] [akpm@osdl.org: fix default in Kconfig] Acked-by: Pat Gefre Acked-by: Jeremy Higdon Signed-off-by: Brent Casavant Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/Kconfig | 6 ++++-- drivers/ide/pci/sgiioc4.c | 2 +- drivers/misc/Kconfig | 11 +++++++++++ drivers/misc/Makefile | 1 + drivers/{sn => misc}/ioc4.c | 11 +++++------ drivers/serial/ioc4_serial.c | 2 +- drivers/sn/Kconfig | 12 ------------ drivers/sn/Makefile | 1 - 8 files changed, 23 insertions(+), 23 deletions(-) rename drivers/{sn => misc}/ioc4.c (98%) diff --git a/drivers/Kconfig b/drivers/Kconfig index 263e86ddc1a..f3946341890 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -14,6 +14,10 @@ source "drivers/pnp/Kconfig" source "drivers/block/Kconfig" +# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4 + +source "drivers/misc/Kconfig" + source "drivers/ide/Kconfig" source "drivers/scsi/Kconfig" @@ -52,8 +56,6 @@ source "drivers/w1/Kconfig" source "drivers/hwmon/Kconfig" -source "drivers/misc/Kconfig" - source "drivers/mfd/Kconfig" source "drivers/media/Kconfig" diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index f3fe287fbd8..244f7eb7006 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -774,7 +774,7 @@ ioc4_ide_exit(void) ioc4_unregister_submodule(&ioc4_ide_submodule); } -module_init(ioc4_ide_init); +late_initcall(ioc4_ide_init); /* Call only after IDE init is done */ module_exit(ioc4_ide_exit); MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon"); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index fa7acc2c5c6..b6c045dc97b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -28,6 +28,17 @@ config IBM_ASM If unsure, say N. +config SGI_IOC4 + tristate "SGI IOC4 Base IO support" + ---help--- + This option enables basic support for the IOC4 chip on certain + SGI IO controller cards (IO9, IO10, and PCI-RT). This option + does not enable any specific functions on such a card, but provides + necessary infrastructure for other drivers to utilize. + + If you have an SGI Altix with an IOC4-based card say Y. + Otherwise say N. + config TIFM_CORE tristate "TI Flash Media interface support (EXPERIMENTAL)" depends on EXPERIMENTAL diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 9a91c1ee849..c9e98ab021c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o +obj-$(CONFIG_SGI_IOC4) += ioc4.o diff --git a/drivers/sn/ioc4.c b/drivers/misc/ioc4.c similarity index 98% rename from drivers/sn/ioc4.c rename to drivers/misc/ioc4.c index 83d2e90c581..1c3c14a3839 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/misc/ioc4.c @@ -32,9 +32,6 @@ #include #include #include -#include -#include -#include /*************** * Definitions * @@ -208,10 +205,12 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR); period = IOC4_CALIBRATE_DEFAULT; } else { + u64 ns = period; + + do_div(ns, IOC4_EXTINT_COUNT_DIVISOR); printk(KERN_DEBUG - "IOC4 %s: PCI clock is %ld ns.\n", - pci_name(idd->idd_pdev), - period / IOC4_EXTINT_COUNT_DIVISOR); + "IOC4 %s: PCI clock is %lld ns.\n", + pci_name(idd->idd_pdev), ns); } /* Remember results. We store the extint clock period rather diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 98ce88d8020..ff4fa25f9fd 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -2935,7 +2935,7 @@ static void __devexit ioc4_serial_exit(void) uart_unregister_driver(&ioc4_uart_rs422); } -module_init(ioc4_serial_init); +late_initcall(ioc4_serial_init); /* Call only after tty init is done */ module_exit(ioc4_serial_exit); MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig index 34d4fde51a7..c66ba9ad833 100644 --- a/drivers/sn/Kconfig +++ b/drivers/sn/Kconfig @@ -5,18 +5,6 @@ menu "SN Devices" depends on SGI_SN -config SGI_IOC4 - tristate "SGI IOC4 Base IO support" - default m - ---help--- - This option enables basic support for the IOC4 chip on certain - SGI IO controller cards (IO9, IO10, and PCI-RT). This option - does not enable any specific functions on such a card, but provides - necessary infrastructure for other drivers to utilize. - - If you have an SGI Altix with an IOC4-based card say Y. - Otherwise say N. - config SGI_IOC3 tristate "SGI IOC3 Base IO support" default m diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile index 2cda011597c..693db8bb8d9 100644 --- a/drivers/sn/Makefile +++ b/drivers/sn/Makefile @@ -3,5 +3,4 @@ # # -obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SGI_IOC3) += ioc3.o -- GitLab From 623a43952abfad2d48f287d1fab07b2089d07554 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Tue, 17 Oct 2006 00:09:27 -0700 Subject: [PATCH 1270/1619] [PATCH] synclink: remove PAGE_SIZE reference Remove reference to PAGE_SIZE that causes errors if PAGE_SIZE != 4096 Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index f2864cc6424..06784adcc35 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -133,8 +133,8 @@ static MGSL_PARAMS default_params = { }; #define SHARED_MEM_ADDRESS_SIZE 0x40000 -#define BUFFERLISTSIZE (PAGE_SIZE) -#define DMABUFFERSIZE (PAGE_SIZE) +#define BUFFERLISTSIZE 4096 +#define DMABUFFERSIZE 4096 #define MAXRXFRAMES 7 typedef struct _DMABUFFERENTRY -- GitLab From ca268c691de95612981b93e58899c1d73fdb6b47 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 17 Oct 2006 00:09:28 -0700 Subject: [PATCH 1271/1619] [PATCH] lockdep: increase max allowed recursion depth In general, lockdep warnings are intended to be non-fatal, so I have put in various practical limits on internal data structure failure modes. We haven't had a /single/ lockdep-internal crash ever since lockdep went upstream [the unwinder crashes are outside of lockdep], and that's largely due to the good internal checks it does. Recursion within the dependency graph is currently limited to 20, that's probably not enough on some many-CPU boxes - this patch doubles it to 40. I have written the lockdep functions to have as small stackframes as possible, so 40 should be OK too. (The practical recursion limit should be somewhere between 100 and 200 entries. If we hit that then I'll change the algorithm to be iteration-based. Graph walking logic is so easy to program via recursion, so i'd like to keep recursion as long as possible.) Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/lockdep.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 805a322a565..d1a3b2cfe4a 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -575,6 +575,8 @@ static noinline int print_circular_bug_tail(void) return 0; } +#define RECURSION_LIMIT 40 + static int noinline print_infinite_recursion_bug(void) { __raw_spin_unlock(&hash_lock); @@ -595,7 +597,7 @@ check_noncircular(struct lock_class *source, unsigned int depth) debug_atomic_inc(&nr_cyclic_check_recursions); if (depth > max_recursion_depth) max_recursion_depth = depth; - if (depth >= 20) + if (depth >= RECURSION_LIMIT) return print_infinite_recursion_bug(); /* * Check this lock's dependency list: @@ -645,7 +647,7 @@ find_usage_forwards(struct lock_class *source, unsigned int depth) if (depth > max_recursion_depth) max_recursion_depth = depth; - if (depth >= 20) + if (depth >= RECURSION_LIMIT) return print_infinite_recursion_bug(); debug_atomic_inc(&nr_find_usage_forwards_checks); @@ -684,7 +686,7 @@ find_usage_backwards(struct lock_class *source, unsigned int depth) if (depth > max_recursion_depth) max_recursion_depth = depth; - if (depth >= 20) + if (depth >= RECURSION_LIMIT) return print_infinite_recursion_bug(); debug_atomic_inc(&nr_find_usage_backwards_checks); -- GitLab From b9f5d8040b470e4f74e3266ece2969ef06d0f8aa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 17 Oct 2006 00:09:30 -0700 Subject: [PATCH 1272/1619] [PATCH] New MMC maintainer I will be taking over after Russell King as the new maintainer of the MMC layer. Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 208da3c320c..5305dd69095 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2012,8 +2012,11 @@ L: linux-kernel@vger.kernel.org W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html S: Maintained -MULTIMEDIA CARD (MMC) SUBSYSTEM -S: Orphan +MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM +P: Pierre Ossman +M: drzeus-mmc@drzeus.cx +L: linux-kernel@vger.kernel.org +S: Maintained MULTISOUND SOUND DRIVER P: Andrew Veliath -- GitLab From 3f4a0b917ce72ef47e438d354c433eb645218e87 Mon Sep 17 00:00:00 2001 From: john stultz Date: Tue, 17 Oct 2006 00:09:32 -0700 Subject: [PATCH 1273/1619] [PATCH] i386 Time: Avoid PIT SMP lockups Avoid possible PIT livelock issues seen on SMP systems (and reported by Andi), by not allowing it as a clocksource on SMP boxes. However, since the PIT may no longer be present, we have to properly handle the cases where SMP systems have TSC skew and fall back from the TSC. Since the PIT isn't there, it would "fall back" to the TSC again. So this changes the jiffies rating to 1, and the TSC-bad rating value to 0. Thus you will get the following behavior priority on i386 systems: tsc [if present & stable] hpet [if present] cyclone [if present] acpi_pm [if present] pit [if UP] jiffies Rather then the current more complicated: tsc [if present & stable] hpet [if present] cyclone [if present] acpi_pm [if present] pit [if cpus < 4] tsc [if present & unstable] jiffies Signed-off-by: John Stultz Cc: Andi Kleen Cc: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/i8253.c | 2 +- arch/i386/kernel/tsc.c | 6 +++--- kernel/time/jiffies.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c index 477b24daff5..9a0060b92e3 100644 --- a/arch/i386/kernel/i8253.c +++ b/arch/i386/kernel/i8253.c @@ -109,7 +109,7 @@ static struct clocksource clocksource_pit = { static int __init init_pit_clocksource(void) { - if (num_possible_cpus() > 4) /* PIT does not scale! */ + if (num_possible_cpus() > 1) /* PIT does not scale! */ return 0; clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index b8fa0a8b2e4..fbc95828cd7 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -349,8 +349,8 @@ static int tsc_update_callback(void) int change = 0; /* check to see if we should switch to the safe clocksource: */ - if (clocksource_tsc.rating != 50 && check_tsc_unstable()) { - clocksource_tsc.rating = 50; + if (clocksource_tsc.rating != 0 && check_tsc_unstable()) { + clocksource_tsc.rating = 0; clocksource_reselect(); change = 1; } @@ -461,7 +461,7 @@ static int __init init_tsc_clocksource(void) clocksource_tsc.shift); /* lower the rating if we already know its unstable: */ if (check_tsc_unstable()) - clocksource_tsc.rating = 50; + clocksource_tsc.rating = 0; init_timer(&verify_tsc_freq_timer); verify_tsc_freq_timer.function = verify_tsc_freq; diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index 126bb30c4af..a99b2a6e6a0 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -57,7 +57,7 @@ static cycle_t jiffies_read(void) struct clocksource clocksource_jiffies = { .name = "jiffies", - .rating = 0, /* lowest rating*/ + .rating = 1, /* lowest valid rating*/ .read = jiffies_read, .mask = 0xffffffff, /*32bits*/ .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */ -- GitLab From 5eb30790d4ccd3409240a80eaf9ab76b4fb75fd8 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Tue, 17 Oct 2006 00:09:35 -0700 Subject: [PATCH 1274/1619] [PATCH] null dereference in fs/jbd2/journal.c This is Eric Sesterhenn's jbd patch applied to jbd2. Commit: 41716c7c21b15e7ecf14f0caf1eef3980707fb74 His words: Since commit d1807793e1e7e502e3dc047115e9dbc3b50e4534 we dereference a NULL pointer. Coverity id #1432. We set journal to NULL, and use it directly afterwards. Signed-off-by: Dave Kleikamp Cc: Eric Sesterhenn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/journal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 10db92ced01..c60f378b0f7 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -725,6 +725,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, __FUNCTION__); kfree(journal); journal = NULL; + goto out; } journal->j_dev = bdev; journal->j_fs_dev = fs_dev; @@ -735,7 +736,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; - +out: return journal; } -- GitLab From a649fd9271773dd0f78e2b9f347bcceecb8827f9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 17 Oct 2006 00:09:36 -0700 Subject: [PATCH 1275/1619] [PATCH] invalidate: remove_mapping() fix If remove_mapping() failed to remove the page from its mapping, don't go and mark it not uptodate! Makes kernel go dead. (Actually, I don't think the ClearPageUptodate is needed there at all). Says Nick Piggin: "Right, it isn't needed because at this point the page is guaranteed by remove_mapping to have no references (except us) and cannot pick up any new ones because it is removed from pagecache. We can delete it." Signed-off-by: Andrew Morton Acked-by: Nick Piggin Signed-off-by: Linus Torvalds --- mm/truncate.c | 1 - mm/vmscan.c | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mm/truncate.c b/mm/truncate.c index 11ca480701d..e07b1e682c3 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -96,7 +96,6 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) return 0; ret = remove_mapping(mapping, page); - ClearPageUptodate(page); return ret; } diff --git a/mm/vmscan.c b/mm/vmscan.c index eca70310adb..af73c14f9d8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -378,6 +378,12 @@ static pageout_t pageout(struct page *page, struct address_space *mapping) return PAGE_CLEAN; } +/* + * Attempt to detach a locked page from its ->mapping. If it is dirty or if + * someone else has a ref on the page, abort and return 0. If it was + * successfully detached, return 1. Assumes the caller has a single ref on + * this page. + */ int remove_mapping(struct address_space *mapping, struct page *page) { BUG_ON(!PageLocked(page)); -- GitLab From e24650c2e744f99541125a5b023f0d02cad19d14 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 17 Oct 2006 00:09:38 -0700 Subject: [PATCH 1276/1619] [PATCH] md: fix /proc/mdstat refcounting I have seen mdadm oops after successfully unloading md module. This patch privents from unloading md module while mdadm is polling /proc/mdstat. Cc: Neil Brown Signed-off-by: Akinbou Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 57fa64f93e5..f7f19088f3b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4912,6 +4912,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait) } static struct file_operations md_seq_fops = { + .owner = THIS_MODULE, .open = md_seq_open, .read = seq_read, .llseek = seq_lseek, -- GitLab From ac08c26492a0ad4d94a25bd47d5630cd38337069 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 17 Oct 2006 00:09:39 -0700 Subject: [PATCH 1277/1619] [PATCH] posix-cpu-timers: prevent signal delivery starvation The integer divisions in the timer accounting code can round the result down to 0. Adding 0 is without effect and the signal delivery stops. Clamp the division result to minimum 1 to avoid this. Problem was reported by Seongbae Park , who provided also an inital patch. Roland sayeth: I have had some more time to think about the problem, and to reproduce it using Toyo's test case. For the record, if my understanding of the problem is correct, this happens only in one very particular case. First, the expiry time has to be so soon that in cputime_t units (usually 1s/HZ ticks) it's < nthreads so the division yields zero. Second, it only affects each thread that is so new that its CPU time accumulation is zero so now+0 is still zero and ->it_*_expires winds up staying zero. For the VIRT and PROF clocks when cputime_t is tick granularity (or the SCHED clock on configurations where sched_clock's value only advances on clock ticks), this is not hard to arrange with new threads starting up and blocking before they accumulate a whole tick of CPU time. That's what happens in Toyo's test case. Note that in general it is fine for that division to round down to zero, and set each thread's expiry time to its "now" time. The problem only arises with thread's whose "now" value is still zero, so that now+0 winds up 0 and is interpreted as "not set" instead of ">= now". So it would be a sufficient and more precise fix to just use max(ticks, 1) inside the loop when setting each it_*_expires value. But, it does no harm to round the division up to one and always advance every thread's expiry time. If the thread didn't already fire timers for the expiry time of "now", there is no expectation that it will do so before the next tick anyway. So I followed Thomas's patch in lifting the max out of the loops. This patch also covers the reload cases, which are harder to write a test for (and I didn't try). I've tested it with Toyo's case and it fixes that. [toyoa@mvista.com: fix: min_t -> max_t] Signed-off-by: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Roland McGrath Cc: Daniel Walker Cc: Toyo Abe Cc: john stultz Cc: Roman Zippel Cc: Seongbae Park Cc: Peter Mattis Cc: Rohit Seth Cc: Martin Bligh Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/posix-cpu-timers.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 479b16b44f7..7c3e1e6dfb5 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -87,6 +87,19 @@ static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock, return a; } +/* + * Divide and limit the result to res >= 1 + * + * This is necessary to prevent signal delivery starvation, when the result of + * the division would be rounded down to 0. + */ +static inline cputime_t cputime_div_non_zero(cputime_t time, unsigned long div) +{ + cputime_t res = cputime_div(time, div); + + return max_t(cputime_t, res, 1); +} + /* * Update expiry time from increment, and increase overrun count, * given the current clock sample. @@ -483,8 +496,8 @@ static void process_timer_rebalance(struct task_struct *p, BUG(); break; case CPUCLOCK_PROF: - left = cputime_div(cputime_sub(expires.cpu, val.cpu), - nthreads); + left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu), + nthreads); do { if (likely(!(t->flags & PF_EXITING))) { ticks = cputime_add(prof_ticks(t), left); @@ -498,8 +511,8 @@ static void process_timer_rebalance(struct task_struct *p, } while (t != p); break; case CPUCLOCK_VIRT: - left = cputime_div(cputime_sub(expires.cpu, val.cpu), - nthreads); + left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu), + nthreads); do { if (likely(!(t->flags & PF_EXITING))) { ticks = cputime_add(virt_ticks(t), left); @@ -515,6 +528,7 @@ static void process_timer_rebalance(struct task_struct *p, case CPUCLOCK_SCHED: nsleft = expires.sched - val.sched; do_div(nsleft, nthreads); + nsleft = max_t(unsigned long long, nsleft, 1); do { if (likely(!(t->flags & PF_EXITING))) { ns = t->sched_time + nsleft; @@ -1159,12 +1173,13 @@ static void check_process_timers(struct task_struct *tsk, prof_left = cputime_sub(prof_expires, utime); prof_left = cputime_sub(prof_left, stime); - prof_left = cputime_div(prof_left, nthreads); + prof_left = cputime_div_non_zero(prof_left, nthreads); virt_left = cputime_sub(virt_expires, utime); - virt_left = cputime_div(virt_left, nthreads); + virt_left = cputime_div_non_zero(virt_left, nthreads); if (sched_expires) { sched_left = sched_expires - sched_time; do_div(sched_left, nthreads); + sched_left = max_t(unsigned long long, sched_left, 1); } else { sched_left = 0; } -- GitLab From 0187f879ee8d4b914e74ffa3cc5df268311fc2d2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 17 Oct 2006 00:09:41 -0700 Subject: [PATCH 1278/1619] [PATCH] PROC_NUMBUF is wrong Actually, the decimal representation of a 32-bit signed number can take 12 bytes, including the \0. And then some code adds a \n as well, so let's give it 13 bytes. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 82da55b5cff..26a8f8416b7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -86,7 +86,7 @@ /* Worst case buffer size needed for holding an integer. */ -#define PROC_NUMBUF 10 +#define PROC_NUMBUF 13 struct pid_entry { int len; -- GitLab From aaa248f6c9c81b2683db7dbb0689cd5ed1c86d88 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 00:09:42 -0700 Subject: [PATCH 1279/1619] [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 diff --git a/include/linux/net.h b/include/linux/net.h index c257f716e00..15c733b816f 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 5d6456bcdeb..0248b30e306 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 59070dbfbeb..4b8052f6a7b 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 00000000000..4a15ce51cea --- /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 4d891beab13..81c426adcd1 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 94c5d761c83..d93fe64f669 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. -- GitLab From 5c496374a72320279ddb86291ef709e090a5d531 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 17 Oct 2006 00:09:44 -0700 Subject: [PATCH 1280/1619] [PATCH] remove carta_random32 This library function should be in obj-y and not in lib-y. But when we do that it clashes unpleasantly with the assembly-language implementation in the ia64 architecture. Instead of trying to fix it all up, just remove the generic carta_random32 in the expectation that the recently-made-generic random32() will suffice. If/when perfmon is migrated to random32, ia64's private carta_random32 implementation can also be removed. Cc: Stephane Eranian Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/Makefile | 2 +- lib/carta_random32.c | 41 ----------------------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 lib/carta_random32.c diff --git a/lib/Makefile b/lib/Makefile index 4b8052f6a7b..cf98fabaa54 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 carta_random32.o + sha1.o irq_regs.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o diff --git a/lib/carta_random32.c b/lib/carta_random32.c deleted file mode 100644 index ca82df70eee..00000000000 --- a/lib/carta_random32.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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); -- GitLab From 91828a405ae454a9503c41a7744f6ff877a80714 Mon Sep 17 00:00:00 2001 From: "David M. Grimes" Date: Tue, 17 Oct 2006 00:09:45 -0700 Subject: [PATCH 1281/1619] [PATCH] knfsd: add nfs-export support to tmpfs We need to encode a decode the 'file' part of a handle. We simply use the inode number and generation number to construct the filehandle. The generation number is the time when the file was created. As inode numbers cycle through the full 32 bits before being reused, there is no real chance of the same inum being allocated to different files in the same second so this is suitably unique. Using time-of-day rather than e.g. jiffies makes it less likely that the same filehandle can be created after a reboot. In order to be able to decode a filehandle we need to be able to lookup by inum, which means that the inode needs to be added to the inode hash table (tmpfs doesn't currently hash inodes as there is never a need to lookup by inum). To avoid overhead when not exporting, we only hash an inode when it is first exported. This requires a lock to ensure it isn't hashed twice. This code is separate from the patch posted in June06 from Atal Shargorodsky which provided the same functionality, but does borrow slightly from it. Locking comment: Most filesystems that hash their inodes do so at the point where the 'struct inode' is initialised, and that has suitable locking (I_NEW). Here in shmem, we are hashing the inode later, the first time we need an NFS file handle for it. We no longer have I_NEW to ensure only one thread tries to add it to the hash table. Cc: Atal Shargorodsky Cc: Gilad Ben-Yossef Signed-off-by: David M. Grimes Signed-off-by: Neil Brown Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/shmem.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/mm/shmem.c b/mm/shmem.c index bb8ca7ef709..b378f66cf2f 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1362,6 +1362,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) inode->i_mapping->a_ops = &shmem_aops; inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_generation = get_seconds(); info = SHMEM_I(inode); memset(info, 0, (char *)inode - (char *)info); spin_lock_init(&info->lock); @@ -1956,6 +1957,85 @@ static struct xattr_handler *shmem_xattr_handlers[] = { }; #endif +static struct dentry *shmem_get_parent(struct dentry *child) +{ + return ERR_PTR(-ESTALE); +} + +static int shmem_match(struct inode *ino, void *vfh) +{ + __u32 *fh = vfh; + __u64 inum = fh[2]; + inum = (inum << 32) | fh[1]; + return ino->i_ino == inum && fh[0] == ino->i_generation; +} + +static struct dentry *shmem_get_dentry(struct super_block *sb, void *vfh) +{ + struct dentry *de = NULL; + struct inode *inode; + __u32 *fh = vfh; + __u64 inum = fh[2]; + inum = (inum << 32) | fh[1]; + + inode = ilookup5(sb, (unsigned long)(inum+fh[0]), shmem_match, vfh); + if (inode) { + de = d_find_alias(inode); + iput(inode); + } + + return de? de: ERR_PTR(-ESTALE); +} + +static struct dentry *shmem_decode_fh(struct super_block *sb, __u32 *fh, + int len, int type, + int (*acceptable)(void *context, struct dentry *de), + void *context) +{ + if (len < 3) + return ERR_PTR(-ESTALE); + + return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, + context); +} + +static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len, + int connectable) +{ + struct inode *inode = dentry->d_inode; + + if (*len < 3) + return 255; + + if (hlist_unhashed(&inode->i_hash)) { + /* Unfortunately insert_inode_hash is not idempotent, + * so as we hash inodes here rather than at creation + * time, we need a lock to ensure we only try + * to do it once + */ + static DEFINE_SPINLOCK(lock); + spin_lock(&lock); + if (hlist_unhashed(&inode->i_hash)) + __insert_inode_hash(inode, + inode->i_ino + inode->i_generation); + spin_unlock(&lock); + } + + fh[0] = inode->i_generation; + fh[1] = inode->i_ino; + fh[2] = ((__u64)inode->i_ino) >> 32; + + *len = 3; + return 1; +} + +static struct export_operations shmem_export_ops = { + .get_parent = shmem_get_parent, + .get_dentry = shmem_get_dentry, + .encode_fh = shmem_encode_fh, + .decode_fh = shmem_decode_fh, +}; + 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) @@ -2128,6 +2208,7 @@ static int shmem_fill_super(struct super_block *sb, &inodes, &policy, &policy_nodes)) return -EINVAL; } + sb->s_export_op = &shmem_export_ops; #else sb->s_flags |= MS_NOUSER; #endif -- GitLab From f9b2e97bea228739b74b541033b1119c5707200b Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Tue, 17 Oct 2006 00:09:47 -0700 Subject: [PATCH 1282/1619] [PATCH] w1 kconfig fix Remove dependency of w1 subsytem from connector, only w1_con must depend on it. With attached patch applied to vanilla 2.6.19-git things works fine. Signed-off-by: Evgeniy Polyakov Cc: Cc: Greg KH Cc: Roman Zippel Cc: "Randy.Dunlap" Cc: Adrian Bunk Acked-by: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/w1/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 27c9d05d03e..c287a9ae4fd 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -2,7 +2,6 @@ menu "Dallas's 1-wire bus" config W1 tristate "Dallas's 1-wire support" - depends on CONNECTOR ---help--- Dallas' 1-wire bus is useful to connect slow 1-pin devices such as iButtons and thermal sensors. -- GitLab From c430169e0c9f42f2cd27e0a6161e7ff4dc7e608d Mon Sep 17 00:00:00 2001 From: Francisco Larramendi Date: Tue, 17 Oct 2006 00:09:53 -0700 Subject: [PATCH 1283/1619] [PATCH] rtc-max6902: month conversion fix Fix October-only BCD-to-binary conversion bug: 0x08 -> 7 0x09 -> 8 0x10 -> 15 (!) 0x11 -> 19 Fixes http://bugzilla.kernel.org/show_bug.cgi?id=7361 Cc: Raphael Assenat Cc: Alessandro Zummo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-max6902.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 0b20dfacbf5..d9417072807 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -136,7 +136,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) dt->tm_min = BCD2BIN(chip->buf[2]); dt->tm_hour = BCD2BIN(chip->buf[3]); dt->tm_mday = BCD2BIN(chip->buf[4]); - dt->tm_mon = BCD2BIN(chip->buf[5] - 1); + dt->tm_mon = BCD2BIN(chip->buf[5]) - 1; dt->tm_wday = BCD2BIN(chip->buf[6]); dt->tm_year = BCD2BIN(chip->buf[7]); -- GitLab From 286e1ea3ac1ca4f503ebbb3020bdb0cbe6adffac Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 17 Oct 2006 00:09:57 -0700 Subject: [PATCH 1284/1619] [PATCH] vmalloc(): don't pass __GFP_ZERO to slab A recent change to the vmalloc() code accidentally resulted in us passing __GFP_ZERO into the slab allocator. But we only wanted __GFP_ZERO for the actual pages whcih are being vmalloc()ed, and passing __GFP_ZERO into slab is not a rational thing to ask for. Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmalloc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 750ab6ed13f..1133dd3aafc 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -428,8 +428,11 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, if (array_size > PAGE_SIZE) { pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node); area->flags |= VM_VPAGES; - } else - pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node); + } else { + pages = kmalloc_node(array_size, + (gfp_mask & ~(__GFP_HIGHMEM | __GFP_ZERO)), + node); + } area->pages = pages; if (!area->pages) { remove_vm_area(area->addr); -- GitLab From 1fec74a9cda95772887c82ede5c0ac60f5be857e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 17 Oct 2006 00:09:58 -0700 Subject: [PATCH 1285/1619] [PATCH] acpi_processor_latency_notifier(): UP warning fix drivers/acpi/processor_idle.c:1112: warning: 'smp_callback' defined but not used Cc: Len Brown Cc: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/processor_idle.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 526387dc379..e67144cf3c8 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1108,6 +1108,7 @@ static const struct file_operations acpi_processor_power_fops = { .release = single_release, }; +#ifdef CONFIG_SMP static void smp_callback(void *v) { /* we already woke the CPU up, nothing more to do */ @@ -1129,6 +1130,7 @@ static int acpi_processor_latency_notify(struct notifier_block *b, static struct notifier_block acpi_processor_latency_notifier = { .notifier_call = acpi_processor_latency_notify, }; +#endif int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) @@ -1146,7 +1148,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, "ACPI: processor limited to max C-state %d\n", max_cstate); first_run++; +#ifdef CONFIG_SMP register_latency_notifier(&acpi_processor_latency_notifier); +#endif } if (!pr) @@ -1218,7 +1222,9 @@ int acpi_processor_power_exit(struct acpi_processor *pr, * copies of pm_idle before proceeding. */ cpu_idle_wait(); +#ifdef CONFIG_SMP unregister_latency_notifier(&acpi_processor_latency_notifier); +#endif } return 0; -- GitLab From c60099bfe3a5e6fa22a930627689b3769c52153f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 17 Oct 2006 00:09:59 -0700 Subject: [PATCH 1286/1619] [PATCH] swsusp: fix memory leaks My fancy new swsusp IO code had a big memory leak. It's somewhat invisible because the whole mem_map[] gets overwritten after resume, but it can cause us to get low on memory during the actual suspend process. Cc: "Rafael J. Wysocki" Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/power/swap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 9b2ee5344de..1a3b0dd2c3f 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -425,7 +425,8 @@ static int submit(int rw, pgoff_t page_off, struct page *page, bio_set_pages_dirty(bio); bio_put(bio); } else { - get_page(page); + if (rw == READ) + get_page(page); /* These pages are freed later */ bio->bi_private = *bio_chain; *bio_chain = bio; submit_bio(rw | (1 << BIO_RW_SYNC), bio); -- GitLab From a4bb2cf1c3d30e7498e5561b22246b5bcbfe2e15 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 17 Oct 2006 00:10:00 -0700 Subject: [PATCH 1287/1619] [PATCH] drivers/char/specialix.c: fix the baud conversion Correct the following bugs introduced by commit 67cc0161ecc9ebee6eba4af6cbfdba028090b1b9: - remove one remaining and now incorrect baud_table[] usage - "baud +=" is no longer correct The former bug was spotted by the Coverity checker. Rolf Eike Beer spotted a bug in the initial version of my patch. Signed-off-by: Adrian Bunk Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/specialix.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index d0b88d0e87f..7e1bd9562c2 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -183,11 +183,6 @@ static int sx_poll = HZ; static struct tty_driver *specialix_driver; -static unsigned long baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0, -}; - static struct specialix_board sx_board[SX_NBOARD] = { { 0, SX_IOBASE1, 9, }, { 0, SX_IOBASE2, 11, }, @@ -1090,9 +1085,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p if (baud == 38400) { if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baud ++; + baud = 57600; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baud += 2; + baud = 115200; } if (!baud) { @@ -1150,11 +1145,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p sx_out(bp, CD186x_RBPRL, tmp & 0xff); sx_out(bp, CD186x_TBPRL, tmp & 0xff); spin_unlock_irqrestore(&bp->lock, flags); - if (port->custom_divisor) { + if (port->custom_divisor) baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor; - baud = ( baud + 5 ) / 10; - } else - baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */ + baud = (baud + 5) / 10; /* Estimated CPS */ /* Two timer ticks seems enough to wakeup something like SLIP driver */ tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO; -- GitLab From 308ba5fcf89b6e328f9290067181c1e4d772fdc9 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 17 Oct 2006 00:10:02 -0700 Subject: [PATCH 1288/1619] [PATCH] fix `make headers_install' Fix this: make[3]: *** No rule to make target `/mnt/md0/devel/linux-git/include/linux/version.h', needed by `/mnt/md0/devel/linux-git-obj/usr/include/linux/version.h'. Stop. make[2]: *** [linux] Error 2 make[1]: *** [headers_install] Error 2 Signed-off-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/Makefile.headersinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst index 6a026f69b56..4241e0dfeea 100644 --- a/scripts/Makefile.headersinst +++ b/scripts/Makefile.headersinst @@ -168,7 +168,7 @@ $(objhdr-y) $(header-y) $(unifdef-y): $(KBUILDFILES) $(call cmd,gen) else -$(objhdr-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(srctree)/$(obj)/%.h $(KBUILDFILES) +$(objhdr-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(objtree)/$(obj)/%.h $(KBUILDFILES) $(call cmd,o_hdr_install) $(header-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(srctree)/$(obj)/%.h $(KBUILDFILES) -- GitLab From a460e745e8f9c75a0525ff94154a0629f9d3e05d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 17 Oct 2006 00:10:03 -0700 Subject: [PATCH 1289/1619] [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(-) diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d53eafb6daa..62996cd1708 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 0612a33bb89..c4ef801b765 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 c64f3cc7e87..775f5a7da49 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 11c99697acf..2d0dc3efe81 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); } -- GitLab From 48d1a7ea6373337985f27dc1c707649469df5827 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 17 Oct 2006 00:10:05 -0700 Subject: [PATCH 1290/1619] [PATCH] sx: fix user-visible typo (devic) Signed-off-by: Alexey Dobriyan Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 5fec626598c..cc10af08cb0 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2602,7 +2602,7 @@ static void __exit sx_exit (void) } } if (misc_deregister(&sx_fw_device) < 0) { - printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n"); + printk (KERN_INFO "sx: couldn't deregister firmware loader device\n"); } sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized); if (sx_initialized) -- GitLab From 9ffbb9162312fd8113037cb3d94f787f06bbfa9a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:06 -0700 Subject: [PATCH 1291/1619] [PATCH] fuse: fix hang on SMP Fuse didn't always call i_size_write() with i_mutex held which caused rare hangs on SMP/32bit. This bug has been present since fuse-2.2, well before being merged into mainline. The simplest solution is to protect i_size_write() with the per-connection spinlock. Using i_mutex for this purpose would require some restructuring of the code and I'm not even sure it's always safe to acquire i_mutex in all places i_size needs to be set. Since most of vmtruncate is already duplicated for other reasons, duplicate the remaining part as well, making all i_size_write() calls internal to fuse. Using i_size_write() was unnecessary in fuse_init_inode(), since this function is only called on a newly created locked inode. Reported by a few people over the years, but special thanks to Dana Henriksen who was persistent enough in helping me debug it. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/dir.c | 30 +++++++++++++++++++++--------- fs/fuse/file.c | 12 +++++++++--- fs/fuse/inode.c | 5 ++++- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8605155db17..a8f65c11aa2 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -935,14 +935,30 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) } } +static void fuse_vmtruncate(struct inode *inode, loff_t offset) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + int need_trunc; + + spin_lock(&fc->lock); + need_trunc = inode->i_size > offset; + i_size_write(inode, offset); + spin_unlock(&fc->lock); + + if (need_trunc) { + struct address_space *mapping = inode->i_mapping; + unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); + truncate_inode_pages(mapping, offset); + } +} + /* * Set attributes, and at the same time refresh them. * * Truncation is slightly complicated, because the 'truncate' request * may fail, in which case we don't want to touch the mapping. - * vmtruncate() doesn't allow for this case. So do the rlimit - * checking by hand and call vmtruncate() only after the file has - * actually been truncated. + * vmtruncate() doesn't allow for this case, so do the rlimit checking + * and the actual truncation by hand. */ static int fuse_setattr(struct dentry *entry, struct iattr *attr) { @@ -993,12 +1009,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) make_bad_inode(inode); err = -EIO; } else { - if (is_truncate) { - loff_t origsize = i_size_read(inode); - i_size_write(inode, outarg.attr.size); - if (origsize > outarg.attr.size) - vmtruncate(inode, outarg.attr.size); - } + if (is_truncate) + fuse_vmtruncate(inode, outarg.attr.size); fuse_change_attributes(inode, &outarg.attr); fi->i_time = time_to_jiffies(outarg.attr_valid, outarg.attr_valid_nsec); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 183626868ee..2bb5ace3882 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -481,8 +481,10 @@ static int fuse_commit_write(struct file *file, struct page *page, err = -EIO; if (!err) { pos += count; - if (pos > i_size_read(inode)) + spin_lock(&fc->lock); + if (pos > inode->i_size) i_size_write(inode, pos); + spin_unlock(&fc->lock); if (offset == 0 && to == PAGE_CACHE_SIZE) { clear_page_dirty(page); @@ -586,8 +588,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, } fuse_put_request(fc, req); if (res > 0) { - if (write && pos > i_size_read(inode)) - i_size_write(inode, pos); + if (write) { + spin_lock(&fc->lock); + if (pos > inode->i_size) + i_size_write(inode, pos); + spin_unlock(&fc->lock); + } *ppos = pos; } fuse_invalidate_attr(inode); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7d0a9aee01f..8e106163aae 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -109,6 +109,7 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) { + struct fuse_conn *fc = get_fuse_conn(inode); if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) invalidate_inode_pages(inode->i_mapping); @@ -117,7 +118,9 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) inode->i_nlink = attr->nlink; inode->i_uid = attr->uid; inode->i_gid = attr->gid; + spin_lock(&fc->lock); i_size_write(inode, attr->size); + spin_unlock(&fc->lock); inode->i_blocks = attr->blocks; inode->i_atime.tv_sec = attr->atime; inode->i_atime.tv_nsec = attr->atimensec; @@ -130,7 +133,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) { inode->i_mode = attr->mode & S_IFMT; - i_size_write(inode, attr->size); + inode->i_size = attr->size; if (S_ISREG(inode->i_mode)) { fuse_init_common(inode); fuse_init_file_inode(inode); -- GitLab From 7762f5a0b709b415fda132258ad37b9f2a1db994 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:07 -0700 Subject: [PATCH 1292/1619] [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(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 34406ed467c..661c7c57214 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) -- GitLab From 8da5ff23ce0a84d9845b01e6fe5047e17836bf5a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:08 -0700 Subject: [PATCH 1293/1619] [PATCH] fuse: locking fix for nlookup An inode could be returned by independent parallel lookups, in this case an update of the lookup counter could be lost resulting in a memory leak in userspace. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/dir.c | 2 ++ fs/fuse/inode.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index a8f65c11aa2..7ecfe95795c 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -163,7 +163,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) fuse_send_forget(fc, req, outarg.nodeid, 1); return 0; } + spin_lock(&fc->lock); fi->nlookup ++; + spin_unlock(&fc->lock); } fuse_put_request(fc, req); if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 8e106163aae..e9114237f31 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -195,7 +195,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, } fi = get_fuse_inode(inode); + spin_lock(&fc->lock); fi->nlookup ++; + spin_unlock(&fc->lock); fuse_change_attributes(inode, attr); return inode; } -- GitLab From 265126ba9e1f8e217e61d1017c6609f76828aa7a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:09 -0700 Subject: [PATCH 1294/1619] [PATCH] fuse: fix spurious BUG Fix a spurious BUG in an unlikely race, where at least three parallel lookups return the same inode, but with different file type. This has not yet been observed in real life. Allowing unlimited retries could delay fuse_iget() indefinitely, but this is really for the broken userspace filesystem to worry about. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/inode.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e9114237f31..4ee8f72e638 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -172,7 +172,6 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, struct inode *inode; struct fuse_inode *fi; struct fuse_conn *fc = get_fuse_conn_super(sb); - int retried = 0; retry: inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); @@ -186,11 +185,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, fuse_init_inode(inode, attr); unlock_new_inode(inode); } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { - BUG_ON(retried); /* Inode has changed type, any I/O on the old should fail */ make_bad_inode(inode); iput(inode); - retried = 1; goto retry; } -- GitLab From d2a85164aaa8d514ef5efbf5d05746e85dd13ddd Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:11 -0700 Subject: [PATCH 1295/1619] [PATCH] fuse: fix handling of moved directory Fuse considered it an error (EIO) if lookup returned a directory inode, to which a dentry already refered. This is because directory aliases are not allowed. But in a network filesystem this could happen legitimately, if a directory is moved on a remote client. This patch attempts to relax the restriction by trying to first evict the offending alias from the cache. If this fails, it still returns an error (EBUSY). A rarer situation is if an mkdir races with an indenpendent lookup, which finds the newly created directory already moved. In this situation the mkdir should return success, but that would be incorrect, since the dentry cannot be instantiated, so return EBUSY. Previously checking for a directory alias and instantiation of the dentry weren't done atomically in lookup/mkdir, hence two such calls racing with each other could create aliased directories. To prevent this introduce a new per-connection mutex: fuse_conn->inst_mutex, which is taken for instantiations with a directory inode. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/dir.c | 70 ++++++++++++++++++++++++++++++------------------ fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 5 +++- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 7ecfe95795c..9d0ef5e1874 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -177,22 +177,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) return 1; } -/* - * Check if there's already a hashed alias of this directory inode. - * If yes, then lookup and mkdir must not create a new alias. - */ -static int dir_alias(struct inode *inode) -{ - if (S_ISDIR(inode->i_mode)) { - struct dentry *alias = d_find_alias(inode); - if (alias) { - dput(alias); - return 1; - } - } - return 0; -} - static int invalid_nodeid(u64 nodeid) { return !nodeid || nodeid == FUSE_ROOT_ID; @@ -208,6 +192,24 @@ static int valid_mode(int m) S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); } +/* + * Add a directory inode to a dentry, ensuring that no other dentry + * refers to this inode. Called with fc->inst_mutex. + */ +static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) +{ + struct dentry *alias = d_find_alias(inode); + if (alias) { + /* This tries to shrink the subtree below alias */ + fuse_invalidate_entry(alias); + dput(alias); + if (!list_empty(&inode->i_dentry)) + return -EBUSY; + } + d_add(entry, inode); + return 0; +} + static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { @@ -243,11 +245,17 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, if (err && err != -ENOENT) return ERR_PTR(err); - if (inode && dir_alias(inode)) { - iput(inode); - return ERR_PTR(-EIO); - } - d_add(entry, inode); + if (inode && S_ISDIR(inode->i_mode)) { + mutex_lock(&fc->inst_mutex); + err = fuse_d_add_directory(entry, inode); + mutex_unlock(&fc->inst_mutex); + if (err) { + iput(inode); + return ERR_PTR(err); + } + } else + d_add(entry, inode); + entry->d_op = &fuse_dentry_operations; if (!err) fuse_change_timeout(entry, &outarg); @@ -403,12 +411,22 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, } fuse_put_request(fc, req); - if (dir_alias(inode)) { - iput(inode); - return -EIO; - } + if (S_ISDIR(inode->i_mode)) { + struct dentry *alias; + mutex_lock(&fc->inst_mutex); + alias = d_find_alias(inode); + if (alias) { + /* New directory must have moved since mkdir */ + mutex_unlock(&fc->inst_mutex); + dput(alias); + iput(inode); + return -EBUSY; + } + d_instantiate(entry, inode); + mutex_unlock(&fc->inst_mutex); + } else + d_instantiate(entry, inode); - d_instantiate(entry, inode); fuse_change_timeout(entry, &outarg); fuse_invalidate_attr(dir); return 0; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 69c7750d55b..91edb8932d9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -239,6 +239,9 @@ struct fuse_conn { /** Lock protecting accessess to members of this structure */ spinlock_t lock; + /** Mutex protecting against directory alias creation */ + struct mutex inst_mutex; + /** Refcount */ atomic_t count; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 4ee8f72e638..fc420357037 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -379,6 +379,7 @@ static struct fuse_conn *new_conn(void) fc = kzalloc(sizeof(*fc), GFP_KERNEL); if (fc) { spin_lock_init(&fc->lock); + mutex_init(&fc->inst_mutex); atomic_set(&fc->count, 1); init_waitqueue_head(&fc->waitq); init_waitqueue_head(&fc->blocked_waitq); @@ -398,8 +399,10 @@ static struct fuse_conn *new_conn(void) void fuse_conn_put(struct fuse_conn *fc) { - if (atomic_dec_and_test(&fc->count)) + if (atomic_dec_and_test(&fc->count)) { + mutex_destroy(&fc->inst_mutex); kfree(fc); + } } struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) -- GitLab From e956edd0523b6b48ed367c63b0c82d8f4c447a58 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:12 -0700 Subject: [PATCH 1296/1619] [PATCH] fuse: fix dereferencing dentry parent There's no locking for ->d_revalidate, so fuse_dentry_revalidate() should use dget_parent() instead of simply dereferencing ->d_parent. Due to topology changes in the directory tree the parent could become negative or be destroyed while being used. There hasn't been any reports about this yet. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/dir.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 9d0ef5e1874..cfc8f81e60d 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -138,6 +138,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) struct fuse_entry_out outarg; struct fuse_conn *fc; struct fuse_req *req; + struct dentry *parent; /* Doesn't hurt to "reset" the validity timeout */ fuse_invalidate_entry_cache(entry); @@ -151,8 +152,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) if (IS_ERR(req)) return 0; - fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); + parent = dget_parent(entry); + fuse_lookup_init(req, parent->d_inode, entry, &outarg); request_send(fc, req); + dput(parent); err = req->out.h.error; /* Zero nodeid is same as -ENOENT */ if (!err && !outarg.nodeid) -- GitLab From dc730e173785e29b297aa605786c94adaffe2544 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 17 Oct 2006 00:10:13 -0700 Subject: [PATCH 1297/1619] [PATCH] knfsd: nfsd4: fix owner-override on open If a client creates a file using an open which sets the mode to 000, or if a chmod changes permissions after a file is opened, then situations may arise where an NFS client knows that some IO is permitted (because a process holds the file open), but the NFS server does not (because it doesn't know about the open, and only sees that the IO conflicts with the current mode of the file). As a hack to solve this problem, NFS servers normally allow the owner to override permissions on IO. The client can still enforce correct permissions-checking on open by performing an explicit access check. In NFSv4 the client can rely on the explicit on-the-wire open instead of an access check. Therefore we should not be allowing the owner to override permissions on an over-the-wire open! However, we should still allow the owner to override permissions in the case where the client is claiming an open that it already made either before a reboot, or while it was holding a delegation. Thanks to Jim Rees for reporting the bug. 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 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 8333db12cac..a05d3376cc4 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -68,20 +68,18 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src) } static int -do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) +do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) { - int accmode, status; + int status; if (open->op_truncate && !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) return nfserr_inval; - accmode = MAY_NOP; if (open->op_share_access & NFS4_SHARE_ACCESS_READ) - accmode = MAY_READ; + accmode |= MAY_READ; if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE) accmode |= (MAY_WRITE | MAY_TRUNC); - accmode |= MAY_OWNER_OVERRIDE; status = fh_verify(rqstp, current_fh, S_IFREG, accmode); @@ -124,7 +122,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); - status = do_open_permission(rqstp, current_fh, open); + status = do_open_permission(rqstp, current_fh, open, MAY_NOP); } fh_put(&resfh); @@ -155,7 +153,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && (open->op_iattr.ia_size == 0); - status = do_open_permission(rqstp, current_fh, open); + status = do_open_permission(rqstp, current_fh, open, MAY_OWNER_OVERRIDE); return status; } -- GitLab From 9801d8a39cfe6c34f39f9552a246a6bd002e735e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 17 Oct 2006 00:10:14 -0700 Subject: [PATCH 1298/1619] [PATCH] knfsd: nfsd4: fix open permission checking We weren't actually checking for SHARE_ACCESS_WRITE, with the result that the owner could open a non-writeable file for write! Continue to allow DENY_WRITE only with write access. Thanks to Jim Rees for reporting the bug. 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 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index a05d3376cc4..d1fac6872c4 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -78,8 +78,10 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs if (open->op_share_access & NFS4_SHARE_ACCESS_READ) accmode |= MAY_READ; - if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE) + if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) accmode |= (MAY_WRITE | MAY_TRUNC); + if (open->op_share_deny & NFS4_SHARE_DENY_WRITE) + accmode |= MAY_WRITE; status = fh_verify(rqstp, current_fh, S_IFREG, accmode); -- GitLab From 0942176f4353ffebcd6e3f95abce9fd8e24f2cb1 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 17 Oct 2006 00:10:16 -0700 Subject: [PATCH 1299/1619] [PATCH] knfsd: nfsd4: Fix error handling in nfsd's callback client Coverity noticed that the error handling code in the NFSv4 callback client sets cb->cb_client to NULL, then calls rpc_shutdown_client with the NULL pointer. Coverity: #cid 1397 Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4callback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index f6ca9fb3fc6..324a278f280 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -421,7 +421,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) /* Create RPC client */ cb->cb_client = rpc_create(&args); - if (!cb->cb_client) { + if (IS_ERR(cb->cb_client)) { dprintk("NFSD: couldn't create callback client\n"); goto out_err; } @@ -448,10 +448,10 @@ nfsd4_probe_callback(struct nfs4_client *clp) out_rpciod: atomic_dec(&clp->cl_count); rpciod_down(); - cb->cb_client = NULL; out_clnt: rpc_shutdown_client(cb->cb_client); out_err: + cb->cb_client = NULL; dprintk("NFSD: warning: no callback path to client %.*s\n", (int)clp->cl_name.len, clp->cl_name.data); } -- GitLab From 4481d1038f4116f3f5c307d919e6dc815a3acbb9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 17 Oct 2006 00:10:17 -0700 Subject: [PATCH 1300/1619] [PATCH] knfsd: Fix bug in recent lockd patches that can cause reclaim to fail When an nfs server shuts down, lockd needs to release all the locks even though the client still holds them. It should therefore not 'unmonitor' the clients, so that the files in nfs/sm will still be there when the nfs server restarts, so that those clients will be told to reclaim their locks. However the hosts are fully unmonitored, so statd may well remove the files. lockd has a test for 'sm_sticky' and avoid the unmonitor call if it is set, but it is currently not set. So set it when tearing down lockd. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svcsubs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 514f5f20701..c5f9113cdc7 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -324,7 +324,16 @@ nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) static int nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) { - return host->h_server; + if (host->h_server) { + /* we are destroying locks even though the client + * hasn't asked us too, so don't unmonitor the + * client + */ + if (host->h_nsmhandle) + host->h_nsmhandle->sm_sticky = 1; + return 1; + } else + return 0; } /* -- GitLab From d343fce148a4eee24a907a05c4101d3268045aae Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 17 Oct 2006 00:10:18 -0700 Subject: [PATCH 1301/1619] [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(-) diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index fa370f6eb07..399ad11b97b 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 75b2c81bcb9..6a931f4ab75 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 c5f9113cdc7..7dac96e6c82 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 7b889ff15ae..9b9e7e127c0 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 81e3a185f95..aa50d89eacd 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 bb0a0f1caa9..66fdae3b490 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 1e65f2dd80e..606cb216523 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 953723b09bc..ac69e551160 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 2807fa0eab4..eb44ec929ca 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"); -- GitLab From 58ff407bee5a55f9c1188a3f9d70ffc79485183c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 17 Oct 2006 00:10:19 -0700 Subject: [PATCH 1302/1619] [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(-) diff --git a/fs/buffer.c b/fs/buffer.c index f65ef8821c7..35527dca1db 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 131ffd37e71..5d9fb0e9415 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 */ }; -- GitLab From 12fda16814bba05a84a49a1da25a069d6c249758 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 17 Oct 2006 00:10:20 -0700 Subject: [PATCH 1303/1619] [PATCH] drivers/led: handle sysfs errors Signed-off-by: Jeff Garzik Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/led-class.c | 26 +++++++++++++++++++++----- drivers/leds/ledtrig-timer.c | 16 ++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index aecbbe2e89a..3c1711210e3 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -91,6 +91,8 @@ EXPORT_SYMBOL_GPL(led_classdev_resume); */ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) { + int rc; + led_cdev->class_dev = class_device_create(leds_class, NULL, 0, parent, "%s", led_cdev->name); if (unlikely(IS_ERR(led_cdev->class_dev))) @@ -99,8 +101,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) class_set_devdata(led_cdev->class_dev, led_cdev); /* register the attributes */ - class_device_create_file(led_cdev->class_dev, - &class_device_attr_brightness); + rc = class_device_create_file(led_cdev->class_dev, + &class_device_attr_brightness); + if (rc) + goto err_out; /* add to the list of leds */ write_lock(&leds_list_lock); @@ -110,16 +114,28 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) #ifdef CONFIG_LEDS_TRIGGERS rwlock_init(&led_cdev->trigger_lock); - led_trigger_set_default(led_cdev); + rc = class_device_create_file(led_cdev->class_dev, + &class_device_attr_trigger); + if (rc) + goto err_out_led_list; - class_device_create_file(led_cdev->class_dev, - &class_device_attr_trigger); + led_trigger_set_default(led_cdev); #endif printk(KERN_INFO "Registered led device: %s\n", led_cdev->class_dev->class_id); return 0; + +#ifdef CONFIG_LEDS_TRIGGERS +err_out_led_list: + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_brightness); + list_del(&led_cdev->node); +#endif +err_out: + class_device_unregister(led_cdev->class_dev); + return rc; } EXPORT_SYMBOL_GPL(led_classdev_register); diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index 179c2876b54..29a8818a32e 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -123,6 +123,7 @@ static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show, static void timer_trig_activate(struct led_classdev *led_cdev) { struct timer_trig_data *timer_data; + int rc; timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); if (!timer_data) @@ -134,10 +135,21 @@ static void timer_trig_activate(struct led_classdev *led_cdev) timer_data->timer.function = led_timer_function; timer_data->timer.data = (unsigned long) led_cdev; - class_device_create_file(led_cdev->class_dev, + rc = class_device_create_file(led_cdev->class_dev, &class_device_attr_delay_on); - class_device_create_file(led_cdev->class_dev, + if (rc) goto err_out; + rc = class_device_create_file(led_cdev->class_dev, &class_device_attr_delay_off); + if (rc) goto err_out_delayon; + + return; + +err_out_delayon: + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_delay_on); +err_out: + led_cdev->trigger_data = NULL; + kfree(timer_data); } static void timer_trig_deactivate(struct led_classdev *led_cdev) -- GitLab From 6b5f29675c6a1041aefc147271508bd56cf2b761 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 17 Oct 2006 00:10:22 -0700 Subject: [PATCH 1304/1619] [PATCH] I2O: handle a few sysfs errors Signed-off-by: Jeff Garzik Cc: Markus Lidel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/message/i2o/bus-osm.c | 12 ++++++++++-- drivers/message/i2o/exec-osm.c | 17 ++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c index ac06f10c54e..d96c687aee9 100644 --- a/drivers/message/i2o/bus-osm.c +++ b/drivers/message/i2o/bus-osm.c @@ -80,18 +80,26 @@ static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan); * @dev: device to verify if it is a I2O Bus Adapter device * * Because we want all Bus Adapters always return 0. + * Except when we fail. Then we are sad. * - * Returns 0. + * Returns 0, except when we fail to excel. */ static int i2o_bus_probe(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(get_device(dev)); + int rc; - device_create_file(dev, &dev_attr_scan); + rc = device_create_file(dev, &dev_attr_scan); + if (rc) + goto err_out; osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid); return 0; + +err_out: + put_device(dev); + return rc; }; /** diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 7bd4d85d0b4..91f95d172ca 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -325,13 +325,24 @@ static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL); static int i2o_exec_probe(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(dev); + int rc; - i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + if (rc) goto err_out; - device_create_file(dev, &dev_attr_vendor_id); - device_create_file(dev, &dev_attr_product_id); + rc = device_create_file(dev, &dev_attr_vendor_id); + if (rc) goto err_evtreg; + rc = device_create_file(dev, &dev_attr_product_id); + if (rc) goto err_vid; return 0; + +err_vid: + device_remove_file(dev, &dev_attr_vendor_id); +err_evtreg: + i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); +err_out: + return rc; }; /** -- GitLab From eee44cca665aa1a5663e6a00c2bdfc275739dac5 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 17 Oct 2006 00:10:23 -0700 Subject: [PATCH 1305/1619] [PATCH] fs/partitions/check: add sysfs error handling Handle errors thrown in disk_sysfs_symlinks(), and propagate back to caller. The callers and associated functions don't do a real good job of handling kobject errors anyway (add_partition, register_disk, rescan_partitions), so this should do until something better comes along. Signed-off-by: Jeff Garzik Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/partitions/check.c | 50 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 51c6a748df4..6fb4b6150d7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -376,18 +376,48 @@ static char *make_block_name(struct gendisk *disk) return name; } -static void disk_sysfs_symlinks(struct gendisk *disk) +static int disk_sysfs_symlinks(struct gendisk *disk) { struct device *target = get_device(disk->driverfs_dev); + int err; + char *disk_name = NULL; + if (target) { - char *disk_name = make_block_name(disk); - sysfs_create_link(&disk->kobj,&target->kobj,"device"); - if (disk_name) { - sysfs_create_link(&target->kobj,&disk->kobj,disk_name); - kfree(disk_name); + disk_name = make_block_name(disk); + if (!disk_name) { + err = -ENOMEM; + goto err_out; } + + err = sysfs_create_link(&disk->kobj, &target->kobj, "device"); + if (err) + goto err_out_disk_name; + + err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name); + if (err) + goto err_out_dev_link; } - sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, "subsystem"); + + err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, + "subsystem"); + if (err) + goto err_out_disk_name_lnk; + + kfree(disk_name); + + return 0; + +err_out_disk_name_lnk: + if (target) { + sysfs_remove_link(&target->kobj, disk_name); +err_out_dev_link: + sysfs_remove_link(&disk->kobj, "device"); +err_out_disk_name: + kfree(disk_name); +err_out: + put_device(target); + } + return err; } /* Not exported, helper to add_disk(). */ @@ -406,7 +436,11 @@ void register_disk(struct gendisk *disk) *s = '!'; if ((err = kobject_add(&disk->kobj))) return; - disk_sysfs_symlinks(disk); + err = disk_sysfs_symlinks(disk); + if (err) { + kobject_del(&disk->kobj); + return; + } disk_sysfs_add_subdirs(disk); /* No minors to use for partitions */ -- GitLab From 6a15f46c1272afd3010259067451bf0df04f6511 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 17 Oct 2006 00:10:25 -0700 Subject: [PATCH 1306/1619] [PATCH] rtc: fix printk of 64-bit res on 32-bit platform With 64-bit resources on 32-bit platforms, the resource address might be larger than a void*. Fix printk to work regardless of resource size. Signed-off-by: Jeff Garzik Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-v3020.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 09b714f1cdc..3b58d3d5d38 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -195,9 +195,9 @@ static int rtc_probe(struct platform_device *pdev) * are all disabled */ v3020_set_reg(chip, V3020_STATUS_0, 0x0); - dev_info(&pdev->dev, "Chip available at physical address 0x%p," + dev_info(&pdev->dev, "Chip available at physical address 0x%llx," "data connected to D%d\n", - (void*)pdev->resource[0].start, + (unsigned long long)pdev->resource[0].start, chip->leftshift); platform_set_drvdata(pdev, chip); -- GitLab From 3864c4894a7f4c03d69a90082a5bb0ab10e437ab Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 17 Oct 2006 00:10:26 -0700 Subject: [PATCH 1307/1619] [PATCH] lockdep: annotate i386 apm Lockdep doesn't like to enable interrupts when they are enabled already. BUG: warning at kernel/lockdep.c:1814/trace_hardirqs_on() (Not tainted) [] show_trace_log_lvl+0x58/0x16a [] show_trace+0xd/0x10 [] dump_stack+0x19/0x1b [] trace_hardirqs_on+0xa2/0x11e [] apm_bios_call_simple+0xcd/0xfd [] apm+0x92/0x5b1 [] 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 [] trace_hardirqs_on+0xa2/0x11e [] apm_bios_call_simple+0xcd/0xfd [] apm+0x92/0x5b1 [] kernel_thread_helper+0x5/0xb Signed-off-by: Peter Zijlstra Cc: Stephen Rothwell Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/apm.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index b42f2d914af..2af65858d32 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -540,11 +540,30 @@ static inline void apm_restore_cpus(cpumask_t mask) * Also, we KNOW that for the non error case of apm_bios_call, there * is no useful data returned in the low order 8 bits of eax. */ -#define APM_DO_CLI \ - if (apm_info.allow_ints) \ - local_irq_enable(); \ - else \ + +static inline unsigned long __apm_irq_save(void) +{ + unsigned long flags; + local_save_flags(flags); + if (apm_info.allow_ints) { + if (irqs_disabled_flags(flags)) + local_irq_enable(); + } else + local_irq_disable(); + + return flags; +} + +#define apm_irq_save(flags) \ + do { flags = __apm_irq_save(); } while (0) + +static inline void apm_irq_restore(unsigned long flags) +{ + if (irqs_disabled_flags(flags)) local_irq_disable(); + else if (irqs_disabled()) + local_irq_enable(); +} #ifdef APM_ZERO_SEGS # define APM_DECL_SEGS \ @@ -596,12 +615,11 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, save_desc_40 = gdt[0x40 / 8]; gdt[0x40 / 8] = bad_bios_desc; - local_save_flags(flags); - APM_DO_CLI; + apm_irq_save(flags); APM_DO_SAVE_SEGS; apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; - local_irq_restore(flags); + apm_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); @@ -640,12 +658,11 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) save_desc_40 = gdt[0x40 / 8]; gdt[0x40 / 8] = bad_bios_desc; - local_save_flags(flags); - APM_DO_CLI; + apm_irq_save(flags); APM_DO_SAVE_SEGS; error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; - local_irq_restore(flags); + apm_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); -- GitLab From ea6f94dfe9db4d19a39e774cfafa5c9428a9fdbc Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 17 Oct 2006 00:10:27 -0700 Subject: [PATCH 1308/1619] [PATCH] rd: memory leak on rd_init() failure If RAM disk driver initialization fails due to blk_alloc_queue() faulure, the gendisk structs stored in rd_disks[] will not be freed completely. This patch resolves that memory leak case by doing alloc_disk() and blk_alloc_queue() at the same time. Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/rd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/block/rd.c b/drivers/block/rd.c index a3f64bfe6b5..485aa87e9bc 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -432,6 +432,12 @@ static int __init rd_init(void) rd_disks[i] = alloc_disk(1); if (!rd_disks[i]) goto out; + + rd_queue[i] = blk_alloc_queue(GFP_KERNEL); + if (!rd_queue[i]) { + put_disk(rd_disks[i]); + goto out; + } } if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) { @@ -442,10 +448,6 @@ static int __init rd_init(void) for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) { struct gendisk *disk = rd_disks[i]; - rd_queue[i] = blk_alloc_queue(GFP_KERNEL); - if (!rd_queue[i]) - goto out_queue; - blk_queue_make_request(rd_queue[i], &rd_make_request); blk_queue_hardsect_size(rd_queue[i], rd_blocksize); @@ -466,8 +468,6 @@ static int __init rd_init(void) CONFIG_BLK_DEV_RAM_COUNT, rd_size, rd_blocksize); return 0; -out_queue: - unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); out: while (i--) { put_disk(rd_disks[i]); -- GitLab From dabad0568a5935e9f4903f5fd1d8f22b1c7c88c7 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 17 Oct 2006 00:10:28 -0700 Subject: [PATCH 1309/1619] [PATCH] epca: prevent panic on tty_register_driver() failure Make epca fail on initialization failure instead of panic. Cc: "Digi International, Inc" Signed-off-by: Akinobu Mita Acked-by: Alan Cox Acked-by: Scott Kilau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/epca.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/char/epca.c b/drivers/char/epca.c index c3f95583a12..706733c0b36 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1157,6 +1157,7 @@ static int __init pc_init(void) int crd; struct board_info *bd; unsigned char board_id = 0; + int err = -ENOMEM; int pci_boards_found, pci_count; @@ -1164,13 +1165,11 @@ static int __init pc_init(void) pc_driver = alloc_tty_driver(MAX_ALLOC); if (!pc_driver) - return -ENOMEM; + goto out1; pc_info = alloc_tty_driver(MAX_ALLOC); - if (!pc_info) { - put_tty_driver(pc_driver); - return -ENOMEM; - } + if (!pc_info) + goto out2; /* ----------------------------------------------------------------------- If epca_setup has not been ran by LILO set num_cards to defaults; copy @@ -1370,11 +1369,17 @@ static int __init pc_init(void) } /* End for each card */ - if (tty_register_driver(pc_driver)) - panic("Couldn't register Digi PC/ driver"); + err = tty_register_driver(pc_driver); + if (err) { + printk(KERN_ERR "Couldn't register Digi PC/ driver"); + goto out3; + } - if (tty_register_driver(pc_info)) - panic("Couldn't register Digi PC/ info "); + err = tty_register_driver(pc_info); + if (err) { + printk(KERN_ERR "Couldn't register Digi PC/ info "); + goto out4; + } /* ------------------------------------------------------------------- Start up the poller to check for events on all enabled boards @@ -1385,6 +1390,15 @@ static int __init pc_init(void) mod_timer(&epca_timer, jiffies + HZ/25); return 0; +out4: + tty_unregister_driver(pc_driver); +out3: + put_tty_driver(pc_info); +out2: + put_tty_driver(pc_driver); +out1: + return err; + } /* End pc_init */ /* ------------------ Begin post_fep_init ---------------------- */ -- GitLab From 3f3fd3c055853d11295a1ec6cdc81e37e2182d16 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Tue, 17 Oct 2006 00:10:30 -0700 Subject: [PATCH 1310/1619] [PATCH] kbuild: allow multi-word $M in Makefile.modpost Some people want to do crazy things like pass multiple directories as the value of $(SUBDIRS) or $M. Mostly this kinda works, except that Makefile.modpost constructs a modpost commandline which fails modpost's argument parsing. This patch fixes that little wrinkle. Signed-off-by: Greg Banks Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/Makefile.modpost | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 6c5469b1473..65e0a79c36c 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -44,7 +44,7 @@ include scripts/Kbuild.include include scripts/Makefile.lib kernelsymfile := $(objtree)/Module.symvers -modulesymfile := $(KBUILD_EXTMOD)/Module.symvers +modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers # Step 1), find all modules listed in $(MODVERDIR)/ __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) -- GitLab From 91b943ee4afa2037678dc1db30b89baef0e17090 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 17 Oct 2006 00:10:32 -0700 Subject: [PATCH 1311/1619] [PATCH] Add entry.S labels to tag file Add functions defined using ENTRY macro to the tags file. Signed-off-by: Aneesh Kumar K.V Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 703d40a65e7..62a1343cf32 100644 --- a/Makefile +++ b/Makefile @@ -1319,7 +1319,8 @@ define xtags $(all-sources) | xargs $1 -a \ -I __initdata,__exitdata,__acquires,__releases \ -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ - --extra=+f --c-kinds=+px; \ + --extra=+f --c-kinds=+px \ + --regex-asm='/ENTRY\(([^)]*)\).*/\1/'; \ $(all-kconfigs) | xargs $1 -a \ --langdef=kconfig \ --language-force=kconfig \ -- GitLab From bea493a031fe3337f4fe5479e8e865513828ea76 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 17 Oct 2006 00:10:33 -0700 Subject: [PATCH 1312/1619] [PATCH] rt-mutex: fixup rt-mutex debug code BUG: warning at kernel/rtmutex-debug.c:125/rt_mutex_debug_task_free() (Not tainted) [] show_trace_log_lvl+0x58/0x16a [] show_trace+0xd/0x10 [] dump_stack+0x19/0x1b [] rt_mutex_debug_task_free+0x35/0x6a [] free_task+0x15/0x24 [] copy_process+0x12bd/0x1324 [] do_fork+0x42/0x113 [] sys_fork+0x19/0x1b [] syscall_call+0x7/0xb In copy_process(), dup_task_struct() also duplicates the ->pi_lock, ->pi_waiters and ->pi_blocked_on members. rt_mutex_debug_task_free() called from free_task() validates these members. However free_task() can be invoked before these members are reset for the new task. Move the initialization code before the first bail that can hit free_task(). Signed-off-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/fork.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index 7dc6140baac..29ebb30850e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -984,6 +984,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (!p) goto fork_out; + rt_mutex_init_task(p); + #ifdef CONFIG_TRACE_IRQFLAGS DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); @@ -1088,8 +1090,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->lockdep_recursion = 0; #endif - rt_mutex_init_task(p); - #ifdef CONFIG_DEBUG_MUTEXES p->blocked_on = NULL; /* not blocked yet */ #endif -- GitLab From bd5349cfd2b9bbb10a3dbcd3fe5cbaabe0b2ab9e Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 17 Oct 2006 00:10:35 -0700 Subject: [PATCH 1313/1619] [PATCH] Convert cpu hotplug notifiers to use raw_notifier instead of blocking_notifier The use of blocking notifier by _cpu_up and _cpu_down in cpu.c has two problem. 1/ An interaction with the workqueue notifier causes lockdep to spit a warning. 2/ A notifier could conceivable be added or removed while _cpu_up or _cpu_down are in process. As each notifier is called twice (prepare then commit/abort) this could be unhealthy. To fix to we simply take cpu_add_remove_lock while adding or removing notifiers to/from the list. This makes the 'blocking' usage unnecessary as all accesses to cpu_chain are now protected by cpu_add_remove_lock. So change "blocking" to "raw" in all relevant places. This fixes 1. Credit: Andrew Morton Cc: Rusty Russell Cc: Michal Piotrowski (reporter) Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpu.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/kernel/cpu.c b/kernel/cpu.c index 32c96628463..27dd3ee4709 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -19,7 +19,7 @@ static DEFINE_MUTEX(cpu_add_remove_lock); static DEFINE_MUTEX(cpu_bitmask_lock); -static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain); +static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. * Should always be manipulated under cpu_add_remove_lock @@ -68,7 +68,11 @@ EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); /* Need to know about CPUs going up/down? */ int __cpuinit register_cpu_notifier(struct notifier_block *nb) { - return blocking_notifier_chain_register(&cpu_chain, nb); + int ret; + mutex_lock(&cpu_add_remove_lock); + ret = raw_notifier_chain_register(&cpu_chain, nb); + mutex_unlock(&cpu_add_remove_lock); + return ret; } #ifdef CONFIG_HOTPLUG_CPU @@ -77,7 +81,9 @@ EXPORT_SYMBOL(register_cpu_notifier); void unregister_cpu_notifier(struct notifier_block *nb) { - blocking_notifier_chain_unregister(&cpu_chain, nb); + mutex_lock(&cpu_add_remove_lock); + raw_notifier_chain_unregister(&cpu_chain, nb); + mutex_unlock(&cpu_add_remove_lock); } EXPORT_SYMBOL(unregister_cpu_notifier); @@ -126,7 +132,7 @@ static int _cpu_down(unsigned int cpu) if (!cpu_online(cpu)) return -EINVAL; - err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, + err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, (void *)(long)cpu); if (err == NOTIFY_BAD) { printk("%s: attempt to take down CPU %u failed\n", @@ -146,7 +152,7 @@ static int _cpu_down(unsigned int cpu) if (IS_ERR(p)) { /* CPU didn't die: tell everyone. Can't complain. */ - if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, + if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, (void *)(long)cpu) == NOTIFY_BAD) BUG(); @@ -169,7 +175,7 @@ static int _cpu_down(unsigned int cpu) put_cpu(); /* CPU is completely dead: tell everyone. Too late to complain. */ - if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, + if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) == NOTIFY_BAD) BUG(); @@ -206,7 +212,7 @@ static int __devinit _cpu_up(unsigned int cpu) if (cpu_online(cpu) || !cpu_present(cpu)) return -EINVAL; - ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); + ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); if (ret == NOTIFY_BAD) { printk("%s: attempt to bring up CPU %u failed\n", __FUNCTION__, cpu); @@ -223,11 +229,11 @@ static int __devinit _cpu_up(unsigned int cpu) BUG_ON(!cpu_online(cpu)); /* Now call notifier in preparation. */ - blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); + raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); out_notify: if (ret != 0) - blocking_notifier_call_chain(&cpu_chain, + raw_notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); return ret; -- GitLab From 0d9ba869e103d91d471146378ad85bf1fb8e74b4 Mon Sep 17 00:00:00 2001 From: Amol Lad Date: Tue, 17 Oct 2006 00:10:36 -0700 Subject: [PATCH 1314/1619] [PATCH] drivers/isdn/hysdn: save_flags()/cli(), restore_flags() replaced appropriately With Karsten Keil save_flags()/cli() pair is replaced with spin_lock_irqsave() and restore_flags() replaced with spin_unlock_irqrestore() Tested compile only using allmodconfig Signed-off-by: Amol Lad Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hysdn/boardergo.c | 32 +++++++++++++----------------- drivers/isdn/hysdn/hysdn_defs.h | 2 ++ drivers/isdn/hysdn/hysdn_proclog.c | 17 +++++++--------- drivers/isdn/hysdn/hysdn_sched.c | 9 ++++----- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 160f22fa594..8bbe33ae06d 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -45,11 +45,10 @@ ergo_interrupt(int intno, void *dev_id) if (!card->irq_enabled) return IRQ_NONE; /* other device interrupting or irq switched off */ - save_flags(flags); - cli(); /* no further irqs allowed */ + spin_lock_irqsave(&card->hysdn_lock, flags); /* no further irqs allowed */ if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) { - restore_flags(flags); /* restore old state */ + spin_unlock_irqrestore(&card->hysdn_lock, flags); /* restore old state */ return IRQ_NONE; /* no interrupt requested by E1 */ } /* clear any pending ints on the board */ @@ -61,7 +60,7 @@ ergo_interrupt(int intno, void *dev_id) /* start kernel task immediately after leaving all interrupts */ if (!card->hw_lock) schedule_work(&card->irq_queue); - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); return IRQ_HANDLED; } /* ergo_interrupt */ @@ -83,10 +82,9 @@ ergo_irq_bh(hysdn_card * card) dpr = card->dpram; /* point to DPRAM */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); if (card->hw_lock) { - restore_flags(flags); /* hardware currently unavailable */ + spin_unlock_irqrestore(&card->hysdn_lock, flags); /* hardware currently unavailable */ return; } card->hw_lock = 1; /* we now lock the hardware */ @@ -120,7 +118,7 @@ ergo_irq_bh(hysdn_card * card) card->hw_lock = 0; /* free hardware again */ } while (again); /* until nothing more to do */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); } /* ergo_irq_bh */ @@ -137,8 +135,7 @@ ergo_stopcard(hysdn_card * card) #ifdef CONFIG_HYSDN_CAPI hycapi_capi_stop(card); #endif /* CONFIG_HYSDN_CAPI */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */ byteout(card->iobase + PCI9050_INTR_REG, val); @@ -147,7 +144,7 @@ ergo_stopcard(hysdn_card * card) card->state = CARD_STATE_UNUSED; card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); } /* ergo_stopcard */ /**************************************************************************/ @@ -162,12 +159,11 @@ ergo_set_errlog_state(hysdn_card * card, int on) card->err_log_state = ERRLOG_STATE_OFF; /* must be off */ return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) || ((card->err_log_state == ERRLOG_STATE_ON) && on)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); return; /* nothing to do */ } if (on) @@ -175,7 +171,7 @@ ergo_set_errlog_state(hysdn_card * card, int on) else card->err_log_state = ERRLOG_STATE_STOP; /* request stop */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); schedule_work(&card->irq_queue); } /* ergo_set_errlog_state */ @@ -356,8 +352,7 @@ ergo_waitpofready(struct HYSDN_CARD *card) if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "ERGO: pof boot success"); - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); card->state = CARD_STATE_RUN; /* now card is running */ /* enable the cards interrupt */ @@ -370,7 +365,7 @@ ergo_waitpofready(struct HYSDN_CARD *card) dpr->ToHyInt = 1; dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); if ((hynet_enable & (1 << card->myid)) && (i = hysdn_net_create(card))) { @@ -448,6 +443,7 @@ ergo_inithardware(hysdn_card * card) card->waitpofready = ergo_waitpofready; card->set_errlog_state = ergo_set_errlog_state; INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card); + card->hysdn_lock = SPIN_LOCK_UNLOCKED; return (0); } /* ergo_inithardware */ diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index 461e831592d..729df408938 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -188,6 +188,8 @@ typedef struct HYSDN_CARD { /* init and deinit stopcard for booting, too */ void (*stopcard) (struct HYSDN_CARD *); void (*releasehardware) (struct HYSDN_CARD *); + + spinlock_t hysdn_lock; #ifdef CONFIG_HYSDN_CAPI struct hycapictrl_info { char cardname[32]; diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index c4301e8338e..fcd49920b22 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -116,8 +116,7 @@ put_log_buffer(hysdn_card * card, char *cp) strcpy(ib->log_start, cp); /* set output string */ ib->next = NULL; ib->proc_ctrl = pd; /* point to own control structure */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); ib->usage_cnt = pd->if_used; if (!pd->log_head) pd->log_head = ib; /* new head */ @@ -125,7 +124,7 @@ put_log_buffer(hysdn_card * card, char *cp) pd->log_tail->next = ib; /* follows existing messages */ pd->log_tail = ib; /* new tail */ i = pd->del_lock++; /* get lock state */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); /* delete old entrys */ if (!i) @@ -270,14 +269,13 @@ hysdn_log_open(struct inode *ino, struct file *filep) } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { /* read access -> log/debug read */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); pd->if_used++; if (pd->log_head) filep->private_data = &pd->log_tail->next; else filep->private_data = &pd->log_head; - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); } else { /* simultaneous read/write access forbidden ! */ unlock_kernel(); return (-EPERM); /* no permission this time */ @@ -301,7 +299,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) hysdn_card *card; int retval = 0; unsigned long flags; - + spinlock_t hysdn_lock = SPIN_LOCK_UNLOCKED; lock_kernel(); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { @@ -311,8 +309,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) /* read access -> log/debug read, mark one further file as closed */ pd = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&hysdn_lock, flags); inf = *((struct log_data **) filep->private_data); /* get first log entry */ if (inf) pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ @@ -335,7 +332,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) inf->usage_cnt--; /* decrement usage count for buffers */ inf = inf->next; } - restore_flags(flags); + spin_unlock_irqrestore(&hysdn_lock, flags); if (pd) if (pd->if_used <= 0) /* delete buffers if last file closed */ diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index 1c0d54ac12a..1fadf0133e9 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -155,8 +155,7 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); - save_flags(flags); - cli(); + spin_lock_irqsave(&card->hysdn_lock, flags); while (card->async_busy) { sti(); @@ -165,7 +164,7 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) msleep_interruptible(20); /* Timeout 20ms */ if (!--cnt) { - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); return (-ERR_ASYNC_TIME); /* timed out */ } cli(); @@ -194,13 +193,13 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) msleep_interruptible(20); /* Timeout 20ms */ if (!--cnt) { - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); return (-ERR_ASYNC_TIME); /* timed out */ } cli(); } /* wait for buffer to become free again */ - restore_flags(flags); + spin_unlock_irqrestore(&card->hysdn_lock, flags); if (card->debug_flags & LOG_SCHED_ASYN) hysdn_addlog(card, "async tx-cfg data send"); -- GitLab From 078d396598401dbaa88d5f95ec45579f9d3dce0e Mon Sep 17 00:00:00 2001 From: Amol Lad Date: Tue, 17 Oct 2006 00:10:37 -0700 Subject: [PATCH 1315/1619] [PATCH] drivers/isdn/isdnloop: save_flags()/cli(), restore_flags() replaced appropriately Signed-off-by: Amol Lad Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/isdnloop/isdnloop.c | 70 ++++++++++++++------------------ drivers/isdn/isdnloop/isdnloop.h | 1 + 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index fabbd461603..23afba46433 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -100,12 +100,11 @@ isdnloop_pollbchan(unsigned long data) isdnloop_bchan_send(card, 1); if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) { /* schedule b-channel polling again */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; add_timer(&card->rb_timer); card->flags |= ISDNLOOP_FLAGS_RBTIMER; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } else card->flags &= ~ISDNLOOP_FLAGS_RBTIMER; } @@ -281,8 +280,7 @@ isdnloop_putmsg(isdnloop_card * card, unsigned char c) { ulong flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; if (card->msg_buf_write == card->msg_buf_read) { if (++card->msg_buf_read > card->msg_buf_end) @@ -290,7 +288,7 @@ isdnloop_putmsg(isdnloop_card * card, unsigned char c) } if (card->msg_buf_write > card->msg_buf_end) card->msg_buf_write = card->msg_buf; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -372,21 +370,19 @@ isdnloop_polldchan(unsigned long data) if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) { /* schedule b-channel polling */ card->flags |= ISDNLOOP_FLAGS_RBTIMER; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); del_timer(&card->rb_timer); card->rb_timer.function = isdnloop_pollbchan; card->rb_timer.data = (unsigned long) card; card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; add_timer(&card->rb_timer); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* schedule again */ - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; add_timer(&card->st_timer); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -416,8 +412,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card) return 0; if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); nskb = dev_alloc_skb(skb->len); if (nskb) { memcpy(skb_put(nskb, len), skb->data, len); @@ -426,7 +421,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card) } else len = 0; card->sndcount[channel] += len; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } return len; } @@ -576,8 +571,7 @@ isdnloop_atimeout(isdnloop_card * card, int ch) unsigned long flags; char buf[60]; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); if (card->rcard) { isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1); card->rcard[ch]->rcard[card->rch[ch]] = NULL; @@ -587,7 +581,7 @@ isdnloop_atimeout(isdnloop_card * card, int ch) /* No user responding */ sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3)); isdnloop_fake(card, buf, ch + 1); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -622,8 +616,7 @@ isdnloop_start_ctimer(isdnloop_card * card, int ch) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); init_timer(&card->c_timer[ch]); card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT; if (ch) @@ -632,7 +625,7 @@ isdnloop_start_ctimer(isdnloop_card * card, int ch) card->c_timer[ch].function = isdnloop_atimeout0; card->c_timer[ch].data = (unsigned long) card; add_timer(&card->c_timer[ch]); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -647,10 +640,9 @@ isdnloop_kill_ctimer(isdnloop_card * card, int ch) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); del_timer(&card->c_timer[ch]); - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } static u_char si2bit[] = @@ -706,13 +698,12 @@ isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd) } } if (num_match) { - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); /* channel idle? */ if (!(cc->rcard[ch])) { /* Check SI */ if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return 3; } /* ch is idle, si and number matches */ @@ -720,10 +711,10 @@ isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd) cc->rch[ch] = lch; card->rcard[lch] = cc; card->rch[lch] = ch; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return 0; } else { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); /* num matches, but busy */ if (ch == 1) return 1; @@ -1027,8 +1018,7 @@ isdnloop_stopcard(isdnloop_card * card) unsigned long flags; isdn_ctrl cmd; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); if (card->flags & ISDNLOOP_FLAGS_RUNNING) { card->flags &= ~ISDNLOOP_FLAGS_RUNNING; del_timer(&card->st_timer); @@ -1039,7 +1029,7 @@ isdnloop_stopcard(isdnloop_card * card) cmd.driver = card->myid; card->interface.statcallb(&cmd); } - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); } /* @@ -1078,18 +1068,17 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) return -EBUSY; if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef))) return -EFAULT; - save_flags(flags); - cli(); + spin_lock_irqsave(&card->isdnloop_lock, flags); switch (sdef.ptype) { case ISDN_PTYPE_EURO: if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96", -1)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } card->sil[0] = card->sil[1] = 4; if (isdnloop_fake(card, "TEI OK", 0)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } for (i = 0; i < 3; i++) @@ -1098,12 +1087,12 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) case ISDN_PTYPE_1TR6: if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95", -1)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } card->sil[0] = card->sil[1] = 4; if (isdnloop_fake(card, "TEI OK", 0)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return -ENOMEM; } strcpy(card->s0num[0], sdef.num[0]); @@ -1111,7 +1100,7 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) card->s0num[2][0] = '\0'; break; default: - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n", sdef.ptype); return -EINVAL; @@ -1122,7 +1111,7 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp) card->st_timer.data = (unsigned long) card; add_timer(&card->st_timer); card->flags |= ISDNLOOP_FLAGS_RUNNING; - restore_flags(flags); + spin_unlock_irqrestore(&card->isdnloop_lock, flags); return 0; } @@ -1472,6 +1461,7 @@ isdnloop_initcard(char *id) skb_queue_head_init(&card->bqueue[i]); } skb_queue_head_init(&card->dqueue); + card->isdnloop_lock = SPIN_LOCK_UNLOCKED; card->next = cards; cards = card; if (!register_isdn(&card->interface)) { diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h index d699fe53e1c..0d458a86f52 100644 --- a/drivers/isdn/isdnloop/isdnloop.h +++ b/drivers/isdn/isdnloop/isdnloop.h @@ -94,6 +94,7 @@ typedef struct isdnloop_card { struct sk_buff_head bqueue[ISDNLOOP_BCH]; /* B-Channel queues */ struct sk_buff_head dqueue; /* D-Channel queue */ + spinlock_t isdnloop_lock; } isdnloop_card; /* -- GitLab From 04518bfe8eac2e82b476fb2b0093527adc2bc791 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 17 Oct 2006 00:10:39 -0700 Subject: [PATCH 1316/1619] [PATCH] ISDN: fix drivers, by handling errors thrown by ->readstat() This is a particularly ugly on-failure bug, possibly security, since the lack of error handling here is covering up another class of bug: failure to handle copy_to_user() return values. The I4L API function ->readstat() returns an integer, and by looking at several existing driver implementations, it is clear that a negative return value was meant to indicate an error. Given that several drivers already return a negative value indicating an errno-style error, the current code would blindly accept that [negative] value as a valid amount of bytes read. Obvious damage ensues. Correcting ->readstat() handling to properly notice errors fixes the existing code to work correctly on error, and enables future patches to more easily indicate errors during operation. Signed-off-by: Jeff Garzik Cc: Karsten Keil Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/i4l/isdn_common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index c3d79eef9e3..69aee2602aa 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1134,9 +1134,12 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off) if (dev->drv[drvidx]->interface->readstat) { if (count > dev->drv[drvidx]->stavail) count = dev->drv[drvidx]->stavail; - len = dev->drv[drvidx]->interface-> - readstat(buf, count, drvidx, - isdn_minor2chan(minor)); + len = dev->drv[drvidx]->interface->readstat(buf, count, + drvidx, isdn_minor2chan(minor)); + if (len < 0) { + retval = len; + goto out; + } } else { len = 0; } -- GitLab From 7786ce192fc4917fb9b789dd823476ff8fd6cf66 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 17 Oct 2006 00:10:40 -0700 Subject: [PATCH 1317/1619] [PATCH] ISDN: check for userspace copy faults Most of the ISDN ->readstat() implementations needed to check copy_to_user() and put_user() return values. Signed-off-by: Jeff Garzik Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/capi/capidrv.c | 3 ++- drivers/isdn/hisax/config.c | 6 ++++-- drivers/isdn/icn/icn.c | 3 ++- drivers/isdn/isdnloop/isdnloop.c | 3 ++- drivers/isdn/pcbit/drv.c | 16 ++++++++++------ 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index d10c8b82e6a..b6f9476c050 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -1907,7 +1907,8 @@ static int if_readstat(u8 __user *buf, int len, int id, int channel) } for (p=buf, count=0; count < len; p++, count++) { - put_user(*card->q931_read++, p); + if (put_user(*card->q931_read++, p)) + return -EFAULT; if (card->q931_read > card->q931_end) card->q931_read = card->q931_buf; } diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index e4823ab2b12..785b08554fc 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -631,7 +631,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) count = cs->status_end - cs->status_read + 1; if (count >= len) count = len; - copy_to_user(p, cs->status_read, count); + if (copy_to_user(p, cs->status_read, count)) + return -EFAULT; cs->status_read += count; if (cs->status_read > cs->status_end) cs->status_read = cs->status_buf; @@ -642,7 +643,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) cnt = HISAX_STATUS_BUFSIZE; else cnt = count; - copy_to_user(p, cs->status_read, cnt); + if (copy_to_user(p, cs->status_read, cnt)) + return -EFAULT; p += cnt; cs->status_read += cnt % HISAX_STATUS_BUFSIZE; count -= cnt; diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 6649f8bc995..730bbd07ebc 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1010,7 +1010,8 @@ icn_readstatus(u_char __user *buf, int len, icn_card * card) for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - put_user(*card->msg_buf_read++, p); + if (put_user(*card->msg_buf_read++, p)) + return -EFAULT; if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 23afba46433..c3ae2edaf6f 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -446,7 +446,8 @@ isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card * card) for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - put_user(*card->msg_buf_read++, p); + if (put_user(*card->msg_buf_read++, p)) + return -EFAULT; if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 94f21486bb2..6ead5e1508b 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -725,23 +725,27 @@ static int pcbit_stat(u_char __user *buf, int len, int driver, int channel) if (stat_st < stat_end) { - copy_to_user(buf, statbuf + stat_st, len); + if (copy_to_user(buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; } else { if (len > STATBUF_LEN - stat_st) { - copy_to_user(buf, statbuf + stat_st, - STATBUF_LEN - stat_st); - copy_to_user(buf, statbuf, - len - (STATBUF_LEN - stat_st)); + if (copy_to_user(buf, statbuf + stat_st, + STATBUF_LEN - stat_st)) + return -EFAULT; + if (copy_to_user(buf, statbuf, + len - (STATBUF_LEN - stat_st))) + return -EFAULT; stat_st = len - (STATBUF_LEN - stat_st); } else { - copy_to_user(buf, statbuf + stat_st, len); + if (copy_to_user(buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; -- GitLab From 7281c248f797723f66244b7ecef204620f664648 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:49:50 +0100 Subject: [PATCH 1318/1619] [ARM] switch to new pci_get_bus_and_slot API Signed-off-by: Alan Cox Signed-off-by: Russell King --- arch/arm/mach-ixp2000/ixdp2400.c | 6 ++++-- arch/arm/mach-ixp2000/ixdp2800.c | 6 ++++-- arch/arm/mach-ixp2000/ixdp2x00.c | 7 +++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c index a6f14801872..9ee63834e60 100644 --- a/arch/arm/mach-ixp2000/ixdp2400.c +++ b/arch/arm/mach-ixp2000/ixdp2400.c @@ -133,11 +133,13 @@ static void ixdp2400_pci_postinit(void) struct pci_dev *dev; if (ixdp2x00_master_npu()) { - dev = pci_find_slot(1, IXDP2400_SLAVE_ENET_DEVFN); + dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN); pci_remove_bus_device(dev); + pci_dev_put(dev) } else { - dev = pci_find_slot(1, IXDP2400_MASTER_ENET_DEVFN); + dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN); pci_remove_bus_device(dev); + pci_dev_put(dev) ixdp2x00_slave_pci_postinit(); } diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c index 91d36d91dac..70d247f09a7 100644 --- a/arch/arm/mach-ixp2000/ixdp2800.c +++ b/arch/arm/mach-ixp2000/ixdp2800.c @@ -261,14 +261,16 @@ int __init ixdp2800_pci_init(void) pci_common_init(&ixdp2800_pci); if (ixdp2x00_master_npu()) { - dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN); + dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN); pci_remove_bus_device(dev); + pci_dev_put(dev); ixdp2800_master_enable_slave(); ixdp2800_master_wait_for_slave_bus_scan(); } else { - dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN); + dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN); pci_remove_bus_device(dev); + pci_dev_put(dev); } } diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index af48cb52dfc..aa2655092d2 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -241,11 +241,14 @@ void ixdp2x00_slave_pci_postinit(void) /* * Remove PMC device is there is one */ - if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN))) + if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) { pci_remove_bus_device(dev); + pci_dev_put(dev); + } - dev = pci_find_slot(0, IXDP2X00_21555_DEVFN); + dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN); pci_remove_bus_device(dev); + pci_dev_put(dev); } /************************************************************************** -- GitLab From 2bffc23a01a489ad46ba7d61a1a657cecec87cc8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:17:18 -0700 Subject: [PATCH 1319/1619] sky2: MSI test is only a warning Some motherboards don't implement MSI correctly. The driver handles this but the warning is too verbose and overly cautious. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c10e7f5faa5..9e31efeea7c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3326,9 +3326,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) if (!hw->msi_detected) { /* MSI test failed, go back to INTx mode */ - printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, " - "switching to INTx mode. Please report this failure to " - "the PCI maintainer and include system chipset information.\n", + printk(KERN_INFO PFX "%s: No interrupt generated using MSI, " + "switching to INTx mode.\n", pci_name(pdev)); err = -EOPNOTSUPP; @@ -3336,6 +3335,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) } sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); free_irq(pdev->irq, hw); -- GitLab From e561a83be5c9cada5fa3733efdff67a2098a0c8e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:20:51 -0700 Subject: [PATCH 1320/1619] sky2: turn of workaround timer The workaround timer is not needed in most systems with proper IRQ routing and by perodically waking up it adds to laptop power consumption. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 9e31efeea7c..bd5ccae5387 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -96,9 +96,9 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); -static int idle_timeout = 100; +static int idle_timeout = 0; module_param(idle_timeout, int, 0); -MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)"); +MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)"); static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, -- GitLab From ebc646f681a6ad5a81989a6906832e82155df283 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:23:56 -0700 Subject: [PATCH 1321/1619] sky2: phy irq on shutdown When PHY is turned off on shutdown, it causes the IRQ to get stuck on. Make sure and disable the IRQ first, and if IRQ occurs when device is not running, don't access PHY because that will hang. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bd5ccae5387..2747e2f74dc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1499,6 +1499,11 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); + /* Disable port IRQ */ + imask = sky2_read32(hw, B0_IMSK); + imask &= ~portirq_msk[port]; + sky2_write32(hw, B0_IMSK, imask); + sky2_gmac_reset(hw, port); /* Stop transmitter */ @@ -1549,11 +1554,6 @@ static int sky2_down(struct net_device *dev) sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); - /* Disable port IRQ */ - imask = sky2_read32(hw, B0_IMSK); - imask &= ~portirq_msk[port]; - sky2_write32(hw, B0_IMSK, imask); - sky2_phy_power(hw, port, 0); /* turn off LED's */ @@ -1750,13 +1750,13 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(dev); u16 istatus, phystat; + if (!netif_running(dev)) + return; + spin_lock(&sky2->phy_lock); istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); - if (!netif_running(dev)) - goto out; - if (netif_msg_intr(sky2)) printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", sky2->netdev->name, istatus, phystat); -- GitLab From 709c6e7bb07411176ef9ef660242b1e59fc87a6f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:04 -0700 Subject: [PATCH 1322/1619] sky2: fiber pause bits The advertisement bits for flow control are located in different location on fiber (1000baseX) Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2747e2f74dc..88b12e85664 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -384,20 +384,31 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) adv |= PHY_M_AN_10_FD; if (sky2->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; + + /* desired flow control */ + if (sky2->tx_pause && sky2->rx_pause) /* both */ + adv |= PHY_M_AN_PC | PHY_M_AN_ASP; + else if (sky2->tx_pause) + adv |= PHY_M_AN_ASP; + else if (sky2->rx_pause) + adv |= PHY_M_AN_PC; + + } else { /* special defines for FIBER (88E1040S only) */ if (sky2->advertising & ADVERTISED_1000baseT_Full) adv |= PHY_M_AN_1000X_AFD; if (sky2->advertising & ADVERTISED_1000baseT_Half) adv |= PHY_M_AN_1000X_AHD; - } - /* Set Flow-control capabilities */ - if (sky2->tx_pause && sky2->rx_pause) - adv |= PHY_AN_PAUSE_CAP; /* symmetric */ - else if (sky2->rx_pause && !sky2->tx_pause) - adv |= PHY_AN_PAUSE_ASYM | PHY_AN_PAUSE_CAP; - else if (!sky2->rx_pause && sky2->tx_pause) - adv |= PHY_AN_PAUSE_ASYM; /* local */ + if (sky2->tx_pause && sky2->rx_pause) /* both */ + adv |= PHY_M_P_BOTH_MD_X; + else if (sky2->tx_pause) + adv |= PHY_M_P_ASYM_MD_X; + else if (sky2->rx_pause) + adv |= PHY_M_P_SYM_MD_X; + else + adv |= PHY_M_P_NO_PAUSE_X; + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; -- GitLab From 0edea0f54e1e28bdc1ce6b02d5ca3c4c878cf959 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:07 -0700 Subject: [PATCH 1323/1619] sky2: advertising register 16 bits The advertising bits (from ethtool.h) fit in 16 bits. --- drivers/net/sky2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 43d2accf60e..0a8d8210679 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1860,7 +1860,7 @@ struct sky2_port { dma_addr_t rx_le_map; dma_addr_t tx_le_map; - u32 advertising; /* ADVERTISED_ bits */ + u16 advertising; /* ADVERTISED_ bits */ u16 speed; /* SPEED_1000, SPEED_100, ... */ u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ -- GitLab From 7c74ac1c236457e454804774e832046c1a7cc0bf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:08 -0700 Subject: [PATCH 1324/1619] sky2: use duplex result bits The result of duplex negotiation is avaliable in the phy status register, so use that to simplify code and avoid rereading the PHY. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 88b12e85664..6a594b001f5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1714,26 +1714,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) } sky2->speed = sky2_phy_speed(hw, aux); - if (sky2->speed == SPEED_1000) { - u16 ctl2 = gm_phy_read(hw, port, PHY_MARV_1000T_CTRL); - u16 lpa2 = gm_phy_read(hw, port, PHY_MARV_1000T_STAT); - if (lpa2 & PHY_B_1000S_MSF) { - printk(KERN_ERR PFX "%s: master/slave fault", - sky2->netdev->name); - return -1; - } - - if ((ctl2 & PHY_M_1000C_AFD) && (lpa2 & PHY_B_1000S_LP_FD)) - sky2->duplex = DUPLEX_FULL; - else - sky2->duplex = DUPLEX_HALF; - } else { - u16 adv = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); - if ((aux & adv) & PHY_AN_FULL) - sky2->duplex = DUPLEX_FULL; - else - sky2->duplex = DUPLEX_HALF; - } + sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; /* Pause bits are offset (9..8) */ if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) -- GitLab From 7800fddcd05a7dc89276389b96664af4f7890ea7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:10 -0700 Subject: [PATCH 1325/1619] sky2: don't reset PHY twice Don't need to reset PHY twice on startup. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 6a594b001f5..20a8c34e6d5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -356,16 +356,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } - ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); - if (sky2->autoneg == AUTONEG_DISABLE) - ctrl &= ~PHY_CT_ANE; - else - ctrl |= PHY_CT_ANE; - - ctrl |= PHY_CT_RESET; - gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); - - ctrl = 0; + ctrl = PHY_CT_RESET; ct1000 = 0; adv = PHY_AN_CSMA; reg = 0; @@ -450,8 +441,6 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); - - ctrl |= PHY_CT_RESET; } gma_write16(hw, port, GM_GP_CTRL, reg); -- GitLab From 16ad91e1c686734aaa5664cd08af0b5e9bf3af61 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:13 -0700 Subject: [PATCH 1326/1619] sky2: flow control setting fixes The result of flow control negotiation should not limit the next negotiatition. If board is plugged into an old half duplex 10Mbit port, without pause, then replugged into a gigabit port, it should negotiate what is desired, not inherit that last negotiation. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 115 ++++++++++++++++++++++++++++----------------- drivers/net/sky2.h | 11 ++++- 2 files changed, 81 insertions(+), 45 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 20a8c34e6d5..b8f202169a7 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -284,6 +284,31 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) gma_write16(hw, port, GM_RX_CTRL, reg); } +/* flow control to advertise bits */ +static const u16 copper_fc_adv[] = { + [FC_NONE] = 0, + [FC_TX] = PHY_M_AN_ASP, + [FC_RX] = PHY_M_AN_PC, + [FC_BOTH] = PHY_M_AN_PC | PHY_M_AN_ASP, +}; + +/* flow control to advertise bits when using 1000BaseX */ +static const u16 fiber_fc_adv[] = { + [FC_BOTH] = PHY_M_P_BOTH_MD_X, + [FC_TX] = PHY_M_P_ASYM_MD_X, + [FC_RX] = PHY_M_P_SYM_MD_X, + [FC_NONE] = PHY_M_P_NO_PAUSE_X, +}; + +/* flow control to GMA disable bits */ +static const u16 gm_fc_disable[] = { + [FC_NONE] = GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS, + [FC_TX] = GM_GPCR_FC_RX_DIS, + [FC_RX] = GM_GPCR_FC_TX_DIS, + [FC_BOTH] = 0, +}; + + static void sky2_phy_init(struct sky2_hw *hw, unsigned port) { struct sky2_port *sky2 = netdev_priv(hw->dev[port]); @@ -376,29 +401,14 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - /* desired flow control */ - if (sky2->tx_pause && sky2->rx_pause) /* both */ - adv |= PHY_M_AN_PC | PHY_M_AN_ASP; - else if (sky2->tx_pause) - adv |= PHY_M_AN_ASP; - else if (sky2->rx_pause) - adv |= PHY_M_AN_PC; - - + adv |= copper_fc_adv[sky2->flow_mode]; } else { /* special defines for FIBER (88E1040S only) */ if (sky2->advertising & ADVERTISED_1000baseT_Full) adv |= PHY_M_AN_1000X_AFD; if (sky2->advertising & ADVERTISED_1000baseT_Half) adv |= PHY_M_AN_1000X_AHD; - if (sky2->tx_pause && sky2->rx_pause) /* both */ - adv |= PHY_M_P_BOTH_MD_X; - else if (sky2->tx_pause) - adv |= PHY_M_P_ASYM_MD_X; - else if (sky2->rx_pause) - adv |= PHY_M_P_SYM_MD_X; - else - adv |= PHY_M_P_NO_PAUSE_X; + adv |= fiber_fc_adv[sky2->flow_mode]; } /* Restart Auto-negotiation */ @@ -424,20 +434,14 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->duplex == DUPLEX_FULL) { reg |= GM_GPCR_DUP_FULL; ctrl |= PHY_CT_DUP_MD; - } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) { - /* Turn off flow control for 10/100mbps */ - sky2->rx_pause = 0; - sky2->tx_pause = 0; - } + } else if (sky2->speed < SPEED_1000) + sky2->flow_mode = FC_NONE; - if (!sky2->rx_pause) - reg |= GM_GPCR_FC_RX_DIS; - if (!sky2->tx_pause) - reg |= GM_GPCR_FC_TX_DIS; + reg |= gm_fc_disable[sky2->flow_mode]; /* Forward pause packets to GMAC? */ - if (sky2->tx_pause || sky2->rx_pause) + if (sky2->flow_mode & FC_RX) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -1605,6 +1609,12 @@ static void sky2_link_up(struct sky2_port *sky2) struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u16 reg; + static const char *fc_name[] = { + [FC_NONE] = "none", + [FC_TX] = "tx", + [FC_RX] = "rx", + [FC_BOTH] = "both", + }; /* enable Rx/Tx */ reg = gma_read16(hw, port, GM_GP_CTRL); @@ -1648,8 +1658,7 @@ static void sky2_link_up(struct sky2_port *sky2) "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", sky2->netdev->name, sky2->speed, sky2->duplex == DUPLEX_FULL ? "full" : "half", - (sky2->tx_pause && sky2->rx_pause) ? "both" : - sky2->tx_pause ? "tx" : sky2->rx_pause ? "rx" : "none"); + fc_name[sky2->flow_status]); } static void sky2_link_down(struct sky2_port *sky2) @@ -1664,7 +1673,7 @@ static void sky2_link_down(struct sky2_port *sky2) reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, reg); - if (sky2->rx_pause && !sky2->tx_pause) { + if (sky2->flow_status == FC_RX) { /* restore Asymmetric Pause bit */ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) @@ -1683,6 +1692,14 @@ static void sky2_link_down(struct sky2_port *sky2) sky2_phy_init(hw, port); } +static enum flow_control sky2_flow(int rx, int tx) +{ + if (rx) + return tx ? FC_BOTH : FC_RX; + else + return tx ? FC_TX : FC_NONE; +} + static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) { struct sky2_hw *hw = sky2->hw; @@ -1709,14 +1726,14 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) aux >>= 6; - sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0; - sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0; + sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, + aux & PHY_M_PS_TX_P_EN); - if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000 + if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) - sky2->rx_pause = sky2->tx_pause = 0; + sky2->flow_status = FC_NONE; - if (sky2->rx_pause || sky2->tx_pause) + if (aux & PHY_M_PS_RX_P_EN) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -2729,7 +2746,7 @@ static int sky2_nway_reset(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - if (sky2->autoneg != AUTONEG_ENABLE) + if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE) return -EINVAL; sky2_phy_reinit(sky2); @@ -2971,8 +2988,20 @@ static void sky2_get_pauseparam(struct net_device *dev, { struct sky2_port *sky2 = netdev_priv(dev); - ecmd->tx_pause = sky2->tx_pause; - ecmd->rx_pause = sky2->rx_pause; + switch (sky2->flow_mode) { + case FC_NONE: + ecmd->tx_pause = ecmd->rx_pause = 0; + break; + case FC_TX: + ecmd->tx_pause = 1, ecmd->rx_pause = 0; + break; + case FC_RX: + ecmd->tx_pause = 0, ecmd->rx_pause = 1; + break; + case FC_BOTH: + ecmd->tx_pause = ecmd->rx_pause = 1; + } + ecmd->autoneg = sky2->autoneg; } @@ -2982,10 +3011,10 @@ static int sky2_set_pauseparam(struct net_device *dev, struct sky2_port *sky2 = netdev_priv(dev); sky2->autoneg = ecmd->autoneg; - sky2->tx_pause = ecmd->tx_pause != 0; - sky2->rx_pause = ecmd->rx_pause != 0; + sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause); - sky2_phy_reinit(sky2); + if (netif_running(dev)) + sky2_phy_reinit(sky2); return 0; } @@ -3215,8 +3244,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, /* Auto speed and flow control */ sky2->autoneg = AUTONEG_ENABLE; - sky2->tx_pause = 1; - sky2->rx_pause = 1; + sky2->flow_mode = FC_BOTH; + sky2->duplex = -1; sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 0a8d8210679..3f05492da70 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1828,6 +1828,13 @@ struct rx_ring_info { dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT]; }; +enum flow_control { + FC_NONE = 0, + FC_TX = 1, + FC_RX = 2, + FC_BOTH = 3, +}; + struct sky2_port { struct sky2_hw *hw; struct net_device *netdev; @@ -1864,9 +1871,9 @@ struct sky2_port { u16 speed; /* SPEED_1000, SPEED_100, ... */ u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ - u8 rx_pause; - u8 tx_pause; u8 rx_csum; + enum flow_control flow_mode; + enum flow_control flow_status; struct net_device_stats net_stats; -- GitLab From b6d7773462df13c105c19ab89706687ded839844 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:16 -0700 Subject: [PATCH 1327/1619] sky2: no message on rx fifo overflow Under high load it is possible to make the receiver FIFO get overloaded. The driver/hardware recover properly, so there is no reason to fill the log with lots of extra messages, just update counter. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b8f202169a7..6eddd0f36bc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2014,6 +2014,10 @@ oversize: error: ++sky2->net_stats.rx_errors; + if (status & GMR_FS_RX_FF_OV) { + sky2->net_stats.rx_fifo_errors++; + goto resubmit; + } if (netif_msg_rx_err(sky2) && net_ratelimit()) printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n", @@ -2025,8 +2029,6 @@ error: sky2->net_stats.rx_frame_errors++; if (status & GMR_FS_CRC_ERR) sky2->net_stats.rx_crc_errors++; - if (status & GMR_FS_RX_FF_OV) - sky2->net_stats.rx_fifo_errors++; goto resubmit; } -- GitLab From 52c89cac6781dea0ee2426821cd3effae1a925d3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:18 -0700 Subject: [PATCH 1328/1619] sky2: version 1.9 Mark version, this has been a lot of patches. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 6eddd0f36bc..c1933835178 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.9" +#define DRV_VERSION "1.10" #define PFX DRV_NAME " " /* -- GitLab From a052b52f4b6b77503af2647dc0c7415939d8232a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:23 -0700 Subject: [PATCH 1329/1619] sky2: accept multicast pause frames When using flow control, the PHY needs to accept multicast pause frames. Without this fix, these frames were getting discarded by the PHY before doing any flow control. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c1933835178..67ecd66f26d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2850,6 +2850,14 @@ static int sky2_set_mac_address(struct net_device *dev, void *p) return 0; } +static void inline sky2_add_filter(u8 filter[8], const u8 *addr) +{ + u32 bit; + + bit = ether_crc(ETH_ALEN, addr) & 63; + filter[bit >> 3] |= 1 << (bit & 7); +} + static void sky2_set_multicast(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); @@ -2858,7 +2866,10 @@ static void sky2_set_multicast(struct net_device *dev) struct dev_mc_list *list = dev->mc_list; u16 reg; u8 filter[8]; + int rx_pause; + static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; + rx_pause = (sky2->flow_status == FC_RX || sky2->flow_status == FC_BOTH); memset(filter, 0, sizeof(filter)); reg = gma_read16(hw, port, GM_RX_CTRL); @@ -2866,18 +2877,19 @@ static void sky2_set_multicast(struct net_device *dev) if (dev->flags & IFF_PROMISC) /* promiscuous */ reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16) /* all multicast */ + else if (dev->flags & IFF_ALLMULTI) memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0) /* no multicast */ + else if (dev->mc_count == 0 && !rx_pause) reg &= ~GM_RXCR_MCF_ENA; else { int i; reg |= GM_RXCR_MCF_ENA; - for (i = 0; list && i < dev->mc_count; i++, list = list->next) { - u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; - filter[bit / 8] |= 1 << (bit % 8); - } + if (rx_pause) + sky2_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < dev->mc_count; i++, list = list->next) + sky2_add_filter(filter, list->dmi_addr); } gma_write16(hw, port, GM_MC_ADDR_H1, -- GitLab From 4e4bc305e16440ab38060d61fbcb7d774881d2f1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 10:24:25 -0700 Subject: [PATCH 1330/1619] sky2: GMAC pause frame This reverts earlier change that attempted to fix flow control. Device needs to discard pause frames, otherwise it hangs after a while. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 3f05492da70..6d2a23f66c9 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1576,7 +1576,7 @@ enum { GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR | GMR_FS_FRAGMENT | GMR_FS_LONG_ERR | - GMR_FS_MII_ERR | GMR_FS_BAD_FC | + GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; -- GitLab From 64f89798da35f43c6ef6afda0541e25034513458 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Oct 2006 13:57:18 -0700 Subject: [PATCH 1331/1619] USB: revert EHCI VIA workaround patch This reverts 26f953fd884ea4879585287917f855c63c6b2666 which caused resume problems on the mac mini. Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 4 ++- drivers/usb/host/ehci-hcd.c | 70 +++++++++++-------------------------- drivers/usb/host/ehci-hub.c | 2 +- drivers/usb/host/ehci-pci.c | 2 +- drivers/usb/host/ehci-q.c | 6 ++-- drivers/usb/host/ehci.h | 22 ++++-------- 6 files changed, 37 insertions(+), 69 deletions(-) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 23b95b2bfe1..34b7a31cd85 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf) } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim); + temp = scnprintf (next, size, "reclaim qh %p%s\n", + ehci->reclaim, + ehci->reclaim_ready ? " ready" : ""); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index aac6ec5dd7c..9030994aba9 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_MSECS 10 /* arbitrary */ +#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -254,7 +254,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ -static void end_unlink_async (struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" @@ -264,37 +263,25 @@ static void ehci_work(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ -static void ehci_iaa_watchdog (unsigned long param) +static void ehci_watchdog (unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; - u32 status; spin_lock_irqsave (&ehci->lock, flags); - WARN_ON(!ehci->reclaim); - /* lost IAA irqs wedge things badly; seen first with a vt8235 */ + /* lost IAA irqs wedge things badly; seen with a vt8235 */ if (ehci->reclaim) { - status = readl (&ehci->regs->status); + u32 status = readl (&ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); writel (STS_IAA, &ehci->regs->status); - end_unlink_async (ehci); + ehci->reclaim_ready = 1; } } - spin_unlock_irqrestore (&ehci->lock, flags); -} - -static void ehci_watchdog (unsigned long param) -{ - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - unsigned long flags; - - spin_lock_irqsave (&ehci->lock, flags); - - /* stop async processing after it's idled a bit */ + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) start_unlink_async (ehci, ehci->async); @@ -345,6 +332,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); + if (ehci->reclaim_ready) + end_unlink_async (ehci); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -379,7 +368,6 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); - del_timer_sync (&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -426,10 +414,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; - init_timer(&ehci->iaa_watchdog); - ehci->iaa_watchdog.function = ehci_iaa_watchdog; - ehci->iaa_watchdog.data = (unsigned long) ehci; - /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -446,6 +430,7 @@ static int ehci_init(struct usb_hcd *hcd) ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; + ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -619,7 +604,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - end_unlink_async (ehci); + ehci->reclaim_ready = 1; bh = 1; } @@ -723,14 +708,10 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - // BUG_ON(qh->qh_state != QH_STATE_LINKED); - - /* failfast */ - if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - end_unlink_async (ehci); - - /* defer till later if busy */ - else if (ehci->reclaim) { + /* if we need to use IAA and it's busy, defer */ + if (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -740,8 +721,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* start IAA cycle */ - } else + /* bypass IAA if the hc can't care */ + } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) + end_unlink_async (ehci); + + /* something else might have unlinked the qh by now */ + if (qh->qh_state == QH_STATE_LINKED) start_unlink_async (ehci, qh); } @@ -763,19 +748,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - unlink_async (ehci, qh); - break; - case QH_STATE_UNLINK: - case QH_STATE_UNLINK_WAIT: - /* already started */ - break; - case QH_STATE_IDLE: - WARN_ON(1); - break; - } + unlink_async (ehci, qh); break; case PIPE_INTERRUPT: @@ -867,7 +840,6 @@ rescan: unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ - case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2012213c0a2..1b20722c102 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = readl (&ehci->regs->command); if (ehci->reclaim) - end_unlink_async (ehci); + ehci->reclaim_ready = 1; ehci_work(ehci); /* suspend any active/unsuspended ports, maybe allow wakeup */ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 35e3fab6fc4..e51c1ed81ac 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -303,7 +303,7 @@ restart: /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - end_unlink_async (ehci); + ehci->reclaim_ready = 1; ehci_work(ehci); spin_unlock_irq(&ehci->lock); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 46327272f61..62e46dc60e8 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - iaa_watchdog_done (ehci); + timer_action_done (ehci, TIMER_IAA_WATCHDOG); // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; + ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh); @@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } + ehci->reclaim_ready = 0; cmd |= CMD_IAAD; writel (cmd, &ehci->regs->command); (void) readl (&ehci->regs->command); - iaa_watchdog_start (ehci); + timer_action (ehci, TIMER_IAA_WATCHDOG); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 6aac39f50e0..bbc3082a73d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -58,6 +58,7 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; + unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -80,7 +81,6 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ - struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -114,21 +114,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) } -static inline void -iaa_watchdog_start (struct ehci_hcd *ehci) -{ - WARN_ON(timer_pending(&ehci->iaa_watchdog)); - mod_timer (&ehci->iaa_watchdog, - jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); -} - -static inline void iaa_watchdog_done (struct ehci_hcd *ehci) -{ - del_timer (&ehci->iaa_watchdog); -} - enum ehci_timer_action { TIMER_IO_WATCHDOG, + TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -146,6 +134,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) unsigned long t; switch (action) { + case TIMER_IAA_WATCHDOG: + t = EHCI_IAA_JIFFIES; + break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -162,7 +153,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (time_before_eq(t, ehci->watchdog.expires) + if (action != TIMER_IAA_WATCHDOG + && t > ehci->watchdog.expires && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); -- GitLab From 3bbe486b361b317ac7103378ed3d1aab4779715e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 17 Oct 2006 14:28:16 -0700 Subject: [PATCH 1332/1619] [IA64] perfmon fix for global IRQ fix Missed one piece of ia64 fallout from the global IRQ patch 7d12e780e003f93433d49ce78cfedf4b4c52adc5 Perfmon interrupt handler needs to use get_irq_regs() too. Acked-by: stephane eranian Signed-off-by: Tony Luck --- arch/ia64/kernel/perfmon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 281004ff7b0..3aaede0d698 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -5558,12 +5558,13 @@ report_spurious2: } static irqreturn_t -pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +pfm_interrupt_handler(int irq, void *arg) { unsigned long start_cycles, total_cycles; unsigned long min, max; int this_cpu; int ret; + struct pt_regs *regs = get_irq_regs(); this_cpu = get_cpu(); if (likely(!pfm_alt_intr_handler)) { -- GitLab From 8d32e3ae5972641ee9eb813e7a5c44a2b85d3694 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 26 Sep 2006 13:34:47 -0700 Subject: [PATCH 1333/1619] USB: Wacom driver updates This fixes some issues with the current wacom driver due to the split of the driver into different pieces and adds support for the Intuos3 4x6 Signed-off-by: Ping Cheng Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Makefile | 2 +- drivers/usb/input/wacom.h | 2 + drivers/usb/input/wacom_sys.c | 15 +++-- drivers/usb/input/wacom_wac.c | 121 ++++++++++++++++++---------------- drivers/usb/input/wacom_wac.h | 2 +- 5 files changed, 80 insertions(+), 62 deletions(-) diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 295f459d107..71437db7e9b 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -3,7 +3,7 @@ # # Multipart objects. -wacom-objs := wacom_sys.o wacom_wac.o +wacom-objs := wacom_wac.o wacom_sys.o usbhid-objs := hid-core.o # Optional parts of multipart objects. diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h index 7b3840e378a..1cf08f02c50 100644 --- a/drivers/usb/input/wacom.h +++ b/drivers/usb/input/wacom.h @@ -63,6 +63,7 @@ * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, * - where wacom_sys.c deals with system specific code, * - and wacom_wac.c deals with Wacom specific code + * - Support Intuos3 4x6 */ /* @@ -118,6 +119,7 @@ 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); extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(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 d233c37bd53..3c27f9b0aaa 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -110,7 +110,7 @@ __u16 wacom_be16_to_cpu(unsigned char *data) __u16 wacom_le16_to_cpu(unsigned char *data) { __u16 value; - value = be16_to_cpu(*(__be16 *) data); + value = le16_to_cpu(*(__le16 *) data); return value; } @@ -143,7 +143,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_dev->evbit[0] |= BIT(EV_MSC); input_dev->mscbit[0] |= BIT(MSC_SERIAL); input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4); } void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -155,11 +155,16 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); } -void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); +} + +void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); } @@ -244,7 +249,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom_wac->data, wacom_wac->features->pktlen, - wacom_wac->features->irq, wacom, endpoint->bInterval); + wacom_sys_irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index aa31d22d4f0..92726fe8937 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -191,9 +191,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); if (wacom->features->type == WACOM_G4) - wacom_report_abs(wcombo, ABS_DISTANCE, data[6]); + wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); else - wacom_report_abs(wcombo, ABS_DISTANCE, data[7]); + wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); break; } } @@ -303,8 +303,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom->tool[idx] = BTN_TOOL_PEN; } /* only large I3 support Lens Cursor */ - if(!((wacom->tool[idx] == BTN_TOOL_LENS) && - (wacom->features->type == INTUOS3))) { + if(!((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S)))) { wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ wacom_report_key(wcombo, wacom->tool[idx], 1); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); @@ -315,10 +316,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { - wacom_report_key(wcombo, wacom->tool[idx], 0); - wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - return 2; + if(!((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S)))) { + wacom_report_key(wcombo, wacom->tool[idx], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + return 2; + } } return 0; } @@ -382,7 +387,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); - if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2]) + if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | + data[2] | (data[3] & 0x1f) | data[4]) wacom_report_key(wcombo, wacom->tool[1], 1); else wacom_report_key(wcombo, wacom->tool[1], 0); @@ -432,7 +438,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) ((t - 1) / 2) : -t / 2); } - } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) { + } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) { /* 4D mouse packet */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -452,12 +458,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) - ((data[8] & 0x02) >> 1)); /* I3 2D mouse side buttons */ - if (wacom->features->type == INTUOS3) { + if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); } - } else if (wacom->features->type < INTUOS3) { + } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) { /* Lens cursor packets */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -490,6 +496,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) return (wacom_ptu_irq(wacom_wac, wcombo)); break; case INTUOS: + case INTUOS3S: case INTUOS3: case INTUOS3L: case CINTIQ: @@ -515,6 +522,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w case CINTIQ: input_dev_i3(input_dev, wacom_wac); /* fall through */ + case INTUOS3S: + input_dev_i3s(input_dev, wacom_wac); case INTUOS: input_dev_i(input_dev, wacom_wac); break; @@ -530,49 +539,50 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w } static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_sys_irq }, - { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_sys_irq }, - { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_sys_irq }, - { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq}, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq}, - { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_sys_irq }, - { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PTU, wacom_sys_irq }, - { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, - { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, - { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_sys_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, + { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER }, + { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE }, + { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE }, + { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, + { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, + { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, + { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE }, + { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE }, + { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE }, + { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom PL400", 8, 5408, 4056, 255, 0, PL }, + { "Wacom PL500", 8, 6144, 4608, 255, 0, PL }, + { "Wacom PL600", 8, 6126, 4604, 255, 0, PL }, + { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL }, + { "Wacom PL550", 8, 6144, 4608, 511, 0, PL }, + { "Wacom PL800", 8, 7220, 5780, 511, 0, PL }, + { "Wacom PL700", 8, 6758, 5406, 511, 0, PL }, + { "Wacom PL510", 8, 6282, 4762, 511, 0, PL }, + { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL }, + { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL }, + { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL }, + { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S }, + { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S }, + { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { } }; @@ -618,6 +628,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h index ceae7bf59d9..a1d9ce00797 100644 --- a/drivers/usb/input/wacom_wac.h +++ b/drivers/usb/input/wacom_wac.h @@ -20,6 +20,7 @@ enum { PTU, PL, INTUOS, + INTUOS3S, INTUOS3, INTUOS3L, CINTIQ, @@ -34,7 +35,6 @@ struct wacom_features { int pressure_max; int distance_max; int type; - usb_complete_t irq; }; struct wacom_wac { -- GitLab From 2920349d438ec08d2b1f6761c8b78b8d13fd1dee Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn <[mailto:snakebyte@gmx.de]> Date: Tue, 17 Oct 2006 14:46:30 -0700 Subject: [PATCH 1334/1619] USB: BUG_ON conversion for wacom.c this patch converts two if () BUG(); construct to BUG_ON(); which occupies less space, uses unlikely and is safer when BUG() is disabled. Signed-off-by: Eric Sesterhenn Acked-by: "Ping Cheng" Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/wacom_sys.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index 3c27f9b0aaa..31379b89c33 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -223,8 +223,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom_wac->features = get_wacom_feature(id); - if (wacom_wac->features->pktlen > 10) - BUG(); + BUG_ON(wacom_wac->features->pktlen > 10); input_dev->name = wacom_wac->features->name; wacom->wacom_wac = wacom_wac; -- GitLab From 2daa48729dfafd349c2a52520734de2edb9dc805 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Wed, 4 Oct 2006 09:56:44 -0700 Subject: [PATCH 1335/1619] USB: fix use after free in wacom_sys.c the following commit added a use after free http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3D3bea733ab21247290bd552dd6a2cd3049af9adef Found by coverity (cid #1441) Signed-off-by: Eric Sesterhenn Signed-off-by: "Ping Cheng" Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/wacom_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index 31379b89c33..3498b893b53 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -282,8 +282,8 @@ static void wacom_disconnect(struct usb_interface *intf) input_unregister_device(wacom->dev); usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma); - kfree(wacom); kfree(wacom->wacom_wac); + kfree(wacom); } } -- GitLab From 931b0411ac296591643662b7a790d15d6e23d57e Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Tue, 3 Oct 2006 10:31:36 -0300 Subject: [PATCH 1336/1619] airprime: New device ID. Adds support for the verizon wireless Broadband Access, National Access V640 ExpressCard34 Qualcomm 3G CDMA. Reported by Maciej A. __enczykowski Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 2c19f19b255..392a5129af6 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -24,6 +24,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); -- GitLab From 91a9c9214e34c364bf15406aadb922787ae7129b Mon Sep 17 00:00:00 2001 From: Chris Malley Date: Tue, 3 Oct 2006 10:08:28 +0100 Subject: [PATCH 1337/1619] USB: Support for BT On-Air USB modem in cdc-acm.c The patch below is a necessary workaround to support the BT On-Air USB modem, which fails to initialise properly during normal probing thus: Sep 30 17:34:57 sled kernel: drivers/usb/class/cdc-acm.c: Zero length descriptor references Sep 30 17:34:57 sled kernel: cdc_acm: probe of 1-1.2:1.0 failed with error -22 Adding the patch below causes the probing section to be skipped, and the modem then initialises correctly. Signed-off-by: Chris Malley Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ec4d1d75672..daecdf0bff0 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ .driver_info = SINGLE_RX_URB, /* firmware bug */ }, -- GitLab From fbe2bafcb00b25265c2c869ba4615d6a5324b7f1 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 28 Sep 2006 23:36:04 +0200 Subject: [PATCH 1338/1619] USB: remove private debug macros from kaweth this kills the private debug macros from the kaweth driver. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/kaweth.c | 122 ++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 66 deletions(-) diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 957d4ad316f..9ef9075a168 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -65,16 +65,6 @@ #undef DEBUG -#ifdef DEBUG -#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) -#else -#define kaweth_dbg(format, arg...) do {} while (0) -#endif -#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg) -#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg) -#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg) - - #include "kawethfw.h" #define KAWETH_MTU 1514 @@ -265,17 +255,17 @@ static int kaweth_control(struct kaweth_device *kaweth, { struct usb_ctrlrequest *dr; - kaweth_dbg("kaweth_control()"); + dbg("kaweth_control()"); if(in_interrupt()) { - kaweth_dbg("in_interrupt()"); + dbg("in_interrupt()"); return -EBUSY; } dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); if (!dr) { - kaweth_dbg("kmalloc() failed"); + dbg("kmalloc() failed"); return -ENOMEM; } @@ -300,7 +290,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth) { int retval; - kaweth_dbg("Reading kaweth configuration"); + dbg("Reading kaweth configuration"); retval = kaweth_control(kaweth, usb_rcvctrlpipe(kaweth->dev, 0), @@ -322,7 +312,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) { int retval; - kaweth_dbg("Setting URB size to %d", (unsigned)urb_size); + dbg("Setting URB size to %d", (unsigned)urb_size); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -344,7 +334,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) { int retval; - kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait); + dbg("Set SOFS wait to %d", (unsigned)sofs_wait); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -367,7 +357,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth, { int retval; - kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter); + dbg("Set receive filter to %d", (unsigned)receive_filter); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -392,7 +382,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, __u8 type) { if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { - kaweth_err("Firmware too big: %d", data_len); + err("Firmware too big: %d", data_len); return -ENOSPC; } @@ -403,13 +393,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, kaweth->firmware_buf[4] = type; kaweth->firmware_buf[5] = interrupt; - kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3], + dbg("High: %i, Low:%i", kaweth->firmware_buf[3], kaweth->firmware_buf[2]); - kaweth_dbg("Downloading firmware at %p to kaweth device at %p", + dbg("Downloading firmware at %p to kaweth device at %p", data, kaweth); - kaweth_dbg("Firmware length: %d", data_len); + dbg("Firmware length: %d", data_len); return kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -437,7 +427,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth, kaweth->firmware_buf[6] = 0x00; kaweth->firmware_buf[7] = 0x00; - kaweth_dbg("Triggering firmware"); + dbg("Triggering firmware"); return kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -457,7 +447,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) { int result; - kaweth_dbg("kaweth_reset(%p)", kaweth); + dbg("kaweth_reset(%p)", kaweth); result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), USB_REQ_SET_CONFIGURATION, @@ -470,7 +460,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) mdelay(10); - kaweth_dbg("kaweth_reset() returns %d.",result); + dbg("kaweth_reset() returns %d.",result); return result; } @@ -568,7 +558,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, kaweth->suspend_lowmem_rx = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } - kaweth_err("resubmitting rx_urb %d failed", result); + err("resubmitting rx_urb %d failed", result); } else { kaweth->suspend_lowmem_rx = 0; } @@ -605,7 +595,7 @@ static void kaweth_usb_receive(struct urb *urb) return; if(urb->status && urb->status != -EREMOTEIO && count != 1) { - kaweth_err("%s RX status: %d count: %d packet_len: %d", + err("%s RX status: %d count: %d packet_len: %d", net->name, urb->status, count, @@ -616,9 +606,9 @@ static void kaweth_usb_receive(struct urb *urb) if(kaweth->net && (count > 2)) { if(pkt_len > (count - 2)) { - kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); - kaweth_err("Packet len & 2047: %x", pkt_len & 2047); - kaweth_err("Count 2: %x", count2); + err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); + err("Packet len & 2047: %x", pkt_len & 2047); + err("Count 2: %x", count2); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } @@ -655,7 +645,7 @@ static int kaweth_open(struct net_device *net) struct kaweth_device *kaweth = netdev_priv(net); int res; - kaweth_dbg("Opening network device."); + dbg("Opening network device."); res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) @@ -732,7 +722,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb) if (unlikely(urb->status != 0)) if (urb->status != -ENOENT) - kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); + dbg("%s: TX status %d.", kaweth->net->name, urb->status); netif_wake_queue(kaweth->net); dev_kfree_skb_irq(skb); @@ -783,7 +773,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { - kaweth_warn("kaweth failed tx_urb %d", res); + warn("kaweth failed tx_urb %d", res); kaweth->stats.tx_errors++; netif_start_queue(net); @@ -812,7 +802,7 @@ static void kaweth_set_rx_mode(struct net_device *net) KAWETH_PACKET_FILTER_BROADCAST | KAWETH_PACKET_FILTER_MULTICAST; - kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap); + dbg("Setting Rx mode to %d", packet_filter_bitmap); netif_stop_queue(net); @@ -850,10 +840,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) KAWETH_CONTROL_TIMEOUT); if(result < 0) { - kaweth_err("Failed to set Rx mode: %d", result); + err("Failed to set Rx mode: %d", result); } else { - kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap); + dbg("Set Rx mode to %d", packet_filter_bitmap); } } } @@ -874,7 +864,7 @@ static void kaweth_tx_timeout(struct net_device *net) { struct kaweth_device *kaweth = netdev_priv(net); - kaweth_warn("%s: Tx timed out. Resetting.", net->name); + warn("%s: Tx timed out. Resetting.", net->name); kaweth->stats.tx_errors++; net->trans_start = jiffies; @@ -895,15 +885,15 @@ static int kaweth_probe( const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; int result = 0; - kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", + dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", dev->devnum, le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct), le16_to_cpu(dev->descriptor.bcdDevice)); - kaweth_dbg("Device at %p", dev); + dbg("Device at %p", dev); - kaweth_dbg("Descriptor length: %x type: %x", + dbg("Descriptor length: %x type: %x", (int)dev->descriptor.bLength, (int)dev->descriptor.bDescriptorType); @@ -918,7 +908,7 @@ static int kaweth_probe( spin_lock_init(&kaweth->device_lock); init_waitqueue_head(&kaweth->term_wait); - kaweth_dbg("Resetting."); + dbg("Resetting."); kaweth_reset(kaweth); @@ -928,17 +918,17 @@ static int kaweth_probe( */ if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { - kaweth_info("Firmware present in device."); + info("Firmware present in device."); } else { /* Download the firmware */ - kaweth_info("Downloading firmware..."); + info("Downloading firmware..."); kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); if ((result = kaweth_download_firmware(kaweth, kaweth_new_code, len_kaweth_new_code, 100, 2)) < 0) { - kaweth_err("Error downloading firmware (%d)", result); + err("Error downloading firmware (%d)", result); goto err_fw; } @@ -947,7 +937,7 @@ static int kaweth_probe( len_kaweth_new_code_fix, 100, 3)) < 0) { - kaweth_err("Error downloading firmware fix (%d)", result); + err("Error downloading firmware fix (%d)", result); goto err_fw; } @@ -956,7 +946,7 @@ static int kaweth_probe( len_kaweth_trigger_code, 126, 2)) < 0) { - kaweth_err("Error downloading trigger code (%d)", result); + err("Error downloading trigger code (%d)", result); goto err_fw; } @@ -966,18 +956,18 @@ static int kaweth_probe( len_kaweth_trigger_code_fix, 126, 3)) < 0) { - kaweth_err("Error downloading trigger code fix (%d)", result); + err("Error downloading trigger code fix (%d)", result); goto err_fw; } if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { - kaweth_err("Error triggering firmware (%d)", result); + err("Error triggering firmware (%d)", result); goto err_fw; } /* Device will now disappear for a moment... */ - kaweth_info("Firmware loaded. I'll be back..."); + info("Firmware loaded. I'll be back..."); err_fw: free_page((unsigned long)kaweth->firmware_buf); free_netdev(netdev); @@ -987,14 +977,14 @@ err_fw: result = kaweth_read_configuration(kaweth); if(result < 0) { - kaweth_err("Error reading configuration (%d), no net device created", result); + err("Error reading configuration (%d), no net device created", result); goto err_free_netdev; } - kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask); - kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); - kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); - kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + info("Statistics collection: %x", kaweth->configuration.statistics_mask); + info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); + info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); + info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", (int)kaweth->configuration.hw_addr[0], (int)kaweth->configuration.hw_addr[1], (int)kaweth->configuration.hw_addr[2], @@ -1005,17 +995,17 @@ err_fw: if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr))) { - kaweth_err("Firmware not functioning properly, no net device created"); + err("Firmware not functioning properly, no net device created"); goto err_free_netdev; } if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { - kaweth_dbg("Error setting URB size"); + dbg("Error setting URB size"); goto err_free_netdev; } if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { - kaweth_err("Error setting SOFS wait"); + err("Error setting SOFS wait"); goto err_free_netdev; } @@ -1025,11 +1015,11 @@ err_fw: KAWETH_PACKET_FILTER_MULTICAST); if(result < 0) { - kaweth_err("Error setting receive filter"); + err("Error setting receive filter"); goto err_free_netdev; } - kaweth_dbg("Initializing net device."); + dbg("Initializing net device."); kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kaweth->tx_urb) @@ -1086,13 +1076,13 @@ err_fw: SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - kaweth_err("Error registering netdev."); + err("Error registering netdev."); goto err_intfdata; } - kaweth_info("kaweth interface created at %s", kaweth->net->name); + info("kaweth interface created at %s", kaweth->net->name); - kaweth_dbg("Kaweth probe returning."); + dbg("Kaweth probe returning."); return 0; @@ -1121,16 +1111,16 @@ static void kaweth_disconnect(struct usb_interface *intf) struct kaweth_device *kaweth = usb_get_intfdata(intf); struct net_device *netdev; - kaweth_info("Unregistering"); + info("Unregistering"); usb_set_intfdata(intf, NULL); if (!kaweth) { - kaweth_warn("unregistering non-existant device"); + warn("unregistering non-existant device"); return; } netdev = kaweth->net; - kaweth_dbg("Unregistering net device"); + dbg("Unregistering net device"); unregister_netdev(netdev); usb_free_urb(kaweth->rx_urb); @@ -1185,7 +1175,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { // timeout - kaweth_warn("usb_control/bulk_msg: timeout"); + warn("usb_control/bulk_msg: timeout"); usb_kill_urb(urb); // remove urb safely status = -ETIMEDOUT; } @@ -1234,7 +1224,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, ****************************************************************/ static int __init kaweth_init(void) { - kaweth_dbg("Driver loading"); + dbg("Driver loading"); return usb_register(&kaweth_driver); } -- GitLab From 1a2ea1dfc4ee078841cd6406ebf6bf0c5a3d25e9 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 3 Oct 2006 10:30:52 +0200 Subject: [PATCH 1339/1619] USB: suspend/resume support for kaweth this adds support for suspend and resume to the kaweth driver. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/kaweth.c | 82 +++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 9ef9075a168..7c906a43e49 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -76,6 +76,9 @@ #define KAWETH_STATUS_BROKEN 0x0000001 #define KAWETH_STATUS_CLOSING 0x0000002 +#define KAWETH_STATUS_SUSPENDING 0x0000004 + +#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 @@ -102,6 +105,8 @@ #define STATE_MASK 0x40 #define STATE_SHIFT 5 +#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) + MODULE_AUTHOR("Michael Zappe , Stephane Alnet , Brad Hards and Oliver Neukum "); MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); @@ -118,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout); +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); +static int kaweth_resume(struct usb_interface *intf); /**************************************************************** * usb_device_id @@ -169,6 +176,8 @@ static struct usb_driver kaweth_driver = { .name = driver_name, .probe = kaweth_probe, .disconnect = kaweth_disconnect, + .suspend = kaweth_suspend, + .resume = kaweth_resume, .id_table = usb_klsi_table, }; @@ -212,6 +221,7 @@ struct kaweth_device int suspend_lowmem_rx; int suspend_lowmem_ctrl; int linkstate; + int opened; struct work_struct lowmem_work; struct usb_device *dev; @@ -524,7 +534,7 @@ static void kaweth_resubmit_tl(void *d) { struct kaweth_device *kaweth = (struct kaweth_device *)d; - if (kaweth->status | KAWETH_STATUS_CLOSING) + if (IS_BLOCKED(kaweth->status)) return; if (kaweth->suspend_lowmem_rx) @@ -591,8 +601,12 @@ static void kaweth_usb_receive(struct urb *urb) return; } - if (kaweth->status & KAWETH_STATUS_CLOSING) + spin_lock(&kaweth->device_lock); + if (IS_BLOCKED(kaweth->status)) { + spin_unlock(&kaweth->device_lock); return; + } + spin_unlock(&kaweth->device_lock); if(urb->status && urb->status != -EREMOTEIO && count != 1) { err("%s RX status: %d count: %d packet_len: %d", @@ -668,6 +682,7 @@ static int kaweth_open(struct net_device *net) usb_kill_urb(kaweth->rx_urb); return -EIO; } + kaweth->opened = 1; netif_start_queue(net); @@ -678,14 +693,8 @@ static int kaweth_open(struct net_device *net) /**************************************************************** * kaweth_close ****************************************************************/ -static int kaweth_close(struct net_device *net) +static void kaweth_kill_urbs(struct kaweth_device *kaweth) { - struct kaweth_device *kaweth = netdev_priv(net); - - netif_stop_queue(net); - - kaweth->status |= KAWETH_STATUS_CLOSING; - usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); @@ -696,6 +705,21 @@ static int kaweth_close(struct net_device *net) we hit them again */ usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); +} + +/**************************************************************** + * kaweth_close + ****************************************************************/ +static int kaweth_close(struct net_device *net) +{ + struct kaweth_device *kaweth = netdev_priv(net); + + netif_stop_queue(net); + kaweth->opened = 0; + + kaweth->status |= KAWETH_STATUS_CLOSING; + + kaweth_kill_urbs(kaweth); kaweth->status &= ~KAWETH_STATUS_CLOSING; @@ -742,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth_async_set_rx_mode(kaweth); netif_stop_queue(net); + if (IS_BLOCKED(kaweth->status)) { + goto skip; + } /* We now decide whether we can put our special header into the sk_buff */ if (skb_cloned(skb) || skb_headroom(skb) < 2) { @@ -774,6 +801,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { warn("kaweth failed tx_urb %d", res); +skip: kaweth->stats.tx_errors++; netif_start_queue(net); @@ -871,6 +899,42 @@ static void kaweth_tx_timeout(struct net_device *net) usb_unlink_urb(kaweth->tx_urb); } +/**************************************************************** + * kaweth_suspend + ****************************************************************/ +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct kaweth_device *kaweth = usb_get_intfdata(intf); + unsigned long flags; + + spin_lock_irqsave(&kaweth->device_lock, flags); + kaweth->status |= KAWETH_STATUS_SUSPENDING; + spin_unlock_irqrestore(&kaweth->device_lock, flags); + + kaweth_kill_urbs(kaweth); + return 0; +} + +/**************************************************************** + * kaweth_resume + ****************************************************************/ +static int kaweth_resume(struct usb_interface *intf) +{ + struct kaweth_device *kaweth = usb_get_intfdata(intf); + unsigned long flags; + + spin_lock_irqsave(&kaweth->device_lock, flags); + kaweth->status &= ~KAWETH_STATUS_SUSPENDING; + spin_unlock_irqrestore(&kaweth->device_lock, flags); + + if (!kaweth->opened) + return 0; + kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); + kaweth_resubmit_int_urb(kaweth, GFP_NOIO); + + return 0; +} + /**************************************************************** * kaweth_probe ****************************************************************/ -- GitLab From 8442ae00d47dad690ac1105b426274433dc672f8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 2 Oct 2006 07:20:10 -0700 Subject: [PATCH 1340/1619] USB: ohci-pnx4008 build fixes The OHCI bus glue for the Philips PNX chips is missing a few calls. - Bus suspend/resume were wrongly omitted in the original submission. - Two new calls were added since that glue was submitted: * Root hub irq enable call * Shutdown hook for usbcore Plus usb_bus.hcpriv has now been removed from usbcore. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-pnx4008.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 82cb22f002e..2dbb7741490 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -262,6 +262,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .start = ohci_pnx4008_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -280,7 +281,11 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif .start_port_reset = ohci_start_port_reset, }; @@ -410,8 +415,6 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev) goto out4; } - hcd->self.hcpriv = (void *)hcd; - pnx4008_start_hc(); platform_set_drvdata(pdev, hcd); ohci = hcd_to_ohci(hcd); -- GitLab From 9ca5346483ea2c2e8932268246d1d8746fe3bcaa Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Tue, 3 Oct 2006 21:46:33 +0200 Subject: [PATCH 1341/1619] UEAGLE : be suspend friendly this patch avoid that the kernel thread block the suspend process. Some work is still need to recover after a resume. Signed-off-by: Matthieu Castet Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f5434b1cbb1..68b5d0dd4f9 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1173,6 +1173,9 @@ static int uea_kthread(void *data) ret = uea_stat(sc); if (ret != -EAGAIN) msleep(1000); + if (try_to_freeze()) + uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " + "please unplug/replug your modem\n"); } uea_leaves(INS_TO_USBDEV(sc)); return ret; -- GitLab From 531a39bbab213209a9914e68809bcf8b60a54f47 Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Tue, 3 Oct 2006 21:49:29 +0200 Subject: [PATCH 1342/1619] UEAGLE : use interruptible sleep this patch use wait_event_interruptible_timeout and msleep_interruptible beacause uninterruptible sleep (task state 'D') is counted as 1 towards load average, like running processes. Signed-off-by: Matthieu Castet Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 68b5d0dd4f9..88585da262d 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_timeout(sc->cmv_ack_wait, + int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, sc->cmv_ack, ACK_TIMEOUT); sc->cmv_ack = 0; @@ -1172,7 +1172,7 @@ static int uea_kthread(void *data) if (!ret) ret = uea_stat(sc); if (ret != -EAGAIN) - msleep(1000); + msleep_interruptible(1000); if (try_to_freeze()) uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " "please unplug/replug your modem\n"); @@ -1600,7 +1600,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf) { struct uea_softc *sc = usbatm->driver_data; - wait_event(sc->sync_q, IS_OPERATIONAL(sc)); + wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc)); return 0; -- GitLab From a7a0c9cd1f45c2cae38ebe0951246bf94399818a Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Tue, 3 Oct 2006 21:44:11 +0200 Subject: [PATCH 1343/1619] UEAGLE : comestic changes Hi, this patch does some cosmetic changes : - dump firwmare version as soon as possible and export it on sysfs - hint about wrong cmv/dsp - Display a message to warn user when the modem is ready : it can help people to detect problems on the line without debug trace - Fix wrong indent - display modem type (pots/isdn) - increase version number Signed-off-by: Matthieu Castet Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 42 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 88585da262d..57052984223 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -68,7 +68,7 @@ #include "usbatm.h" -#define EAGLEUSBVERSION "ueagle 1.3" +#define EAGLEUSBVERSION "ueagle 1.4" /* @@ -80,14 +80,14 @@ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm dbg] %s: " format, \ __FUNCTION__, ##args); \ - } while (0) + } while (0) #define uea_vdbg(usb_dev, format, args...) \ do { \ if (debug >= 2) \ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm vdbg] " format, ##args); \ - } while (0) + } while (0) #define uea_enters(usb_dev) \ uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__) @@ -218,8 +218,8 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(sc) \ - (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(usb_dev) \ + (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) #define INS_TO_USBDEV(ins) ins->usb_dev @@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc) char *dsp_name; if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc)) + if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc)) + if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc) break; case 3: /* fail ... */ - uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n"); + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc) release_firmware(sc->dsp_firm); sc->dsp_firm = NULL; } - - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); } /* always update it as atm layer could not be init when we switch to @@ -1033,9 +1028,9 @@ static int request_cmvs(struct uea_softc *sc, if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin"; + file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; else - file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin"; + file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; } else file = cmv_file[sc->modem_index]; @@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_softc *sc) if (ret < 0) return ret; + /* Dump firmware version */ + ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + /* get options */ ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); if (ret < 0) @@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_softc *sc) /* Enter in R-ACT-REQ */ ret = uea_write_cmv(sc, SA_CNTL, 0, 2); uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "Modem started, " + "waiting synchronization\n"); out: release_firmware(cmvs_fw); sc->reset = 0; @@ -1569,6 +1573,7 @@ UEA_ATTR(uscorr, 0); UEA_ATTR(dscorr, 0); UEA_ATTR(usunc, 0); UEA_ATTR(dsunc, 0); +UEA_ATTR(firmid, 0); /* Retrieve the device End System Identifier (MAC) */ @@ -1642,6 +1647,7 @@ static struct attribute *attrs[] = { &dev_attr_stat_dscorr.attr, &dev_attr_stat_usunc.attr, &dev_attr_stat_dsunc.attr, + &dev_attr_stat_firmid.attr, }; static struct attribute_group attr_grp = { .attrs = attrs, @@ -1756,10 +1762,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n", + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", le16_to_cpu(usb->descriptor.idVendor), le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)]); + chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); usb_reset_device(usb); -- GitLab From 762f007b05446f5c63268fb2c28646f28959ee4b Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Fri, 6 Oct 2006 07:23:11 +0200 Subject: [PATCH 1344/1619] USB: fix cdc-acm problems with hard irq? (inconsistent lock state) Signed-off-by: Jarek Poplawski Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index daecdf0bff0..9a9012fd284 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm) struct acm_rb *buf; struct tty_struct *tty = acm->tty; struct acm_ru *rcv; - //unsigned long flags; + unsigned long flags; int i = 0; dbg("Entering acm_rx_tasklet"); @@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm) return; next_buffer: - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->filled_read_bufs)) { - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); goto urbs; } buf = list_entry(acm->filled_read_bufs.next, struct acm_rb, list); list_del(&buf->list); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); @@ -356,29 +356,29 @@ next_buffer: memmove(buf->base, buf->base + i, buf->size - i); buf->size -= i; spin_unlock(&acm->throttle_lock); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->filled_read_bufs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } spin_unlock(&acm->throttle_lock); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->spare_read_bufs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); goto next_buffer; urbs: while (!list_empty(&acm->spare_read_bufs)) { - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->spare_read_urbs)) { - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } rcv = list_entry(acm->spare_read_urbs.next, struct acm_ru, list); list_del(&rcv->list); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); buf = list_entry(acm->spare_read_bufs.next, struct acm_rb, list); @@ -400,9 +400,9 @@ urbs: free-urbs-pool and resubmited ASAP */ if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { list_add(&buf->list, &acm->spare_read_bufs); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&rcv->list, &acm->spare_read_urbs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } } -- GitLab From e4a20daa7b44ab9805979eb716f6bb7532bc67b9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Oct 2006 16:31:15 -0400 Subject: [PATCH 1345/1619] USB: unusual_devs entry for Nokia 6131 This patch (as796) adds an unusual_devs entry for the Nokia 6131, which doesn't like large transfer sizes. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c9a8d50106d..0a846e4a101 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -182,6 +182,13 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by Bardur Arantsson */ +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, + "Nokia", + "6131", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Olaf Hering from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", -- GitLab From ccf40d62c70128990cf2e8775853cc3287cd7ce3 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 5 Oct 2006 09:56:44 +0200 Subject: [PATCH 1346/1619] usbatm: fix tiny race If usbatm_do_heavy_init finishes before usbatm_heavy_init writes the pid, the disconnect method could shoot down the wrong process if the pid has been recycled. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 309073f6433..ab091fa4c86 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg) daemonize(instance->driver->driver_name); allow_signal(SIGTERM); + instance->thread_pid = get_current()->pid; complete(&instance->thread_started); @@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance) return ret; } - mutex_lock(&instance->serialize); - instance->thread_pid = ret; - mutex_unlock(&instance->serialize); - wait_for_completion(&instance->thread_started); return 0; -- GitLab From 6a4f1b41357d2bd65d39f7a5d44e92f69daaf04b Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 5 Oct 2006 10:40:55 +0200 Subject: [PATCH 1347/1619] speedtch: "extended reach" The speedtouch modem setup code was reverse engineered many years ago from a prehistoric windows driver. Less ancient windows drivers, even those from a few years ago, perform extra initialization steps which this patch adds to the linux driver. David Woodhouse observed that this initialization along with the firmware bin/sachu3/zzzlp2.eni from the driver at http://www.speedtouch.co.uk/downloads/330/301/UK3012%20Extended.zip improves line sync speeds by about 20%. He provided the original patch, which I've modified to use symbolic names (BMaxDSL, ModemMode, ModemOption) rather than magic numbers. These names may not seem like much of an improvement (after all, what is "ModemOption" exactly?), but they do have one big advantage: they are the names used in the windows registry. I've made them available as module parameters. Thanks are due to Aurelio Arroyo, who noticed the relationship between these magic numbers and the entries in Phonebook.ini. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 93 +++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 7c7b507af29..c870c804470 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch"; #define OFFSET_d 9 /* size 4 */ #define OFFSET_e 13 /* size 1 */ #define OFFSET_f 14 /* size 1 */ -#define TOTAL 15 #define SIZE_7 1 #define SIZE_b 8 @@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST; static int enable_isoc = DEFAULT_ENABLE_ISOC; static int sw_buffering = DEFAULT_SW_BUFFERING; +#define DEFAULT_B_MAX_DSL 8128 +#define DEFAULT_MODEM_MODE 11 +#define MODEM_OPTION_LENGTH 16 +static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { + 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; +static unsigned char ModemMode = DEFAULT_MODEM_MODE; +static unsigned char ModemOption[MODEM_OPTION_LENGTH]; +static int num_ModemOption; + module_param(altsetting, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(altsetting, "Alternative setting for data interface (bulk_default: " @@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering, "Enable software buffering (default: " __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); +module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(BMaxDSL, + "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL)); + +module_param(ModemMode, byte, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ModemMode, + "default: " __MODULE_STRING(DEFAULT_MODEM_MODE)); + +module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO); +MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20"); + #define INTERFACE_DATA 1 #define ENDPOINT_INT 0x81 #define ENDPOINT_BULK_DATA 0x07 @@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering, #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) +struct speedtch_params { + unsigned int altsetting; + unsigned int BMaxDSL; + unsigned char ModemMode; + unsigned char ModemOption[MODEM_OPTION_LENGTH]; +}; + struct speedtch_instance_data { struct usbatm_data *usbatm; - unsigned int altsetting; + struct speedtch_params params; /* set in probe, constant afterwards */ struct work_struct status_checker; @@ -123,7 +152,7 @@ struct speedtch_instance_data { struct urb *int_urb; unsigned char int_data[16]; - unsigned char scratch_buffer[TOTAL]; + unsigned char scratch_buffer[16]; }; /*************** @@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance) 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); if (ret < 0) usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); + + /* Extra initialisation in recent drivers - gives higher speeds */ + + /* URBext1 */ + buf[0] = instance->params.ModemMode; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret); + + /* URBext2 */ + /* This seems to be the one which actually triggers the higher sync + rate -- it does require the new firmware too, although it works OK + with older firmware */ + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x14, 0x00, + instance->params.ModemOption, + MODEM_OPTION_LENGTH, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret); + + /* URBext3 */ + buf[0] = instance->params.BMaxDSL & 0xff; + buf[1] = instance->params.BMaxDSL >> 8; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret); } static int speedtch_upload_firmware(struct speedtch_instance_data *instance, @@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, because we're in our own kernel thread anyway. */ msleep_interruptible(1000); - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret); + if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { + usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret); goto out_free; } @@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance) unsigned char *buf = instance->scratch_buffer; int ret; - memset(buf, 0, TOTAL); + memset(buf, 0, 16); ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, @@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance->usbatm = usbatm; - /* altsetting and enable_isoc may change at any moment, so take a snapshot */ - instance->altsetting = altsetting; + /* module parameters may change at any moment, so take a snapshot */ + instance->params.altsetting = altsetting; + instance->params.BMaxDSL = BMaxDSL; + instance->params.ModemMode = ModemMode; + memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH); + memcpy(instance->params.ModemOption, ModemOption, num_ModemOption); use_isoc = enable_isoc; - if (instance->altsetting) - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret); - instance->altsetting = 0; /* fall back to default */ + if (instance->params.altsetting) + if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { + usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret); + instance->params.altsetting = 0; /* fall back to default */ } - if (!instance->altsetting && use_isoc) + if (!instance->params.altsetting && use_isoc) if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); use_isoc = 0; /* fall back to bulk */ @@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_data *usbatm, usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); } - if (!use_isoc && !instance->altsetting) + if (!use_isoc && !instance->params.altsetting) if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); goto fail_free; } - if (!instance->altsetting) - instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; + if (!instance->params.altsetting) + instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); -- GitLab From 44960af1b6ab3e8fd23dc134fcf7862caf42936b Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 5 Oct 2006 11:05:50 +0200 Subject: [PATCH 1348/1619] cxacru: add the ZTE ZXDSL 852 From http://doc.ubuntu-fr.org/materiel/zxdsl852. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 3892a9e9aee..e6565633ba0 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -793,6 +793,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { { /* V = Conexant P = ADSL modem */ USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 }, + { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */ + USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00 + }, { /* V = Olitec P = ADSL modem version 2 */ USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe }, -- GitLab From 516077c1ee8a4a47cc41634a29954b636f3975ea Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 5 Oct 2006 09:04:11 +0200 Subject: [PATCH 1349/1619] USB: fix suspend support for usblp this implements suspend support for usblp. According to the CUPS people ENODEV will make CUPS retry the job. Thus it is returned in the runtime case. My printer survives suspend/resume cycles with it. Signed-off-by: Oliver Neukum Signed-off-by: Vojtech Pavlik Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 79 +++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index a161d70e1e4..809d465eb25 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -154,6 +154,7 @@ struct usblp { unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ + unsigned char sleeping; /* interface is suspended */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) { dbg("quirks=%d", usblp->quirks); dbg("used=%d", usblp->used); dbg("bidir=%d", usblp->bidir); + dbg("sleeping=%d", usblp->sleeping); dbg("device_id_string=\"%s\"", usblp->device_id_string ? usblp->device_id_string + 2 : @@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err) return newerr; } +static int handle_bidir (struct usblp *usblp) +{ + if (usblp->bidir && usblp->used && !usblp->sleeping) { + usblp->readcount = 0; + usblp->readurb->dev = usblp->dev; + if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { + usblp->used = 0; + return -EIO; + } + } + + return 0; +} + /* * File op functions. */ @@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->writeurb->status = 0; usblp->readurb->status = 0; - if (usblp->bidir) { - usblp->readcount = 0; - usblp->readurb->dev = usblp->dev; - if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { - retval = -EIO; - usblp->used = 0; - file->private_data = NULL; - } + if (handle_bidir(usblp) < 0) { + file->private_data = NULL; + retval = -EIO; } out: mutex_unlock (&usblp_mutex); @@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } + if (usblp->sleeping) { + retval = -ENODEV; + goto done; + } + dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); @@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t return -ENODEV; } + if (usblp->sleeping) { + up (&usblp->sem); + return writecount ? writecount : -ENODEV; + } + if (usblp->writeurb->status != 0) { if (usblp->quirks & USBLP_QUIRK_BIDIR) { if (!usblp->wcomplete) @@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, goto done; } + if (usblp->sleeping) { + count = -ENODEV; + goto done; + } + if (usblp->readurb->status) { err("usblp%d: error %d reading from printer", usblp->minor, usblp->readurb->status); @@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf) mutex_unlock (&usblp_mutex); } +static int usblp_suspend (struct usb_interface *intf, pm_message_t message) +{ + struct usblp *usblp = usb_get_intfdata (intf); + + /* this races against normal access and open */ + mutex_lock (&usblp_mutex); + down (&usblp->sem); + /* we take no more IO */ + usblp->sleeping = 1; + /* we wait for anything printing */ + wait_event (usblp->wait, usblp->wcomplete || !usblp->present); + usblp_unlink_urbs(usblp); + up (&usblp->sem); + mutex_unlock (&usblp_mutex); + + return 0; +} + +static int usblp_resume (struct usb_interface *intf) +{ + struct usblp *usblp = usb_get_intfdata (intf); + int r; + + mutex_lock (&usblp_mutex); + down (&usblp->sem); + + usblp->sleeping = 0; + r = handle_bidir (usblp); + + up (&usblp->sem); + mutex_unlock (&usblp_mutex); + + return r; +} + static struct usb_device_id usblp_ids [] = { { USB_DEVICE_INFO(7, 1, 1) }, { USB_DEVICE_INFO(7, 1, 2) }, @@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = { .name = "usblp", .probe = usblp_probe, .disconnect = usblp_disconnect, + .suspend = usblp_suspend, + .resume = usblp_resume, .id_table = usblp_ids, }; -- GitLab From 96a518928e1fd00a6d0eb344f420ea82aeec8ab9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Oct 2006 12:24:49 -0700 Subject: [PATCH 1350/1619] USB: ftdi-elan: fix sparse warnings Deleted some unused code that could do bad things on non-x86 platforms. Also fixed some minor formatting errors. Thanks to Al Viro for pointing out the sparse errors. Cc: Tony Olech Cc: Al Viro Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 0eb26a26115..37d1f4e90d5 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -1186,11 +1186,8 @@ static ssize_t ftdi_elan_write(struct file *file, int retval = 0; struct urb *urb; char *buf; - char data[30 *3 + 4]; - char *d = data; - const char __user *s = user_buffer; - int m = (sizeof(data) - 1) / 3; - struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; + struct usb_ftdi *ftdi = file->private_data; + if (ftdi->disconnected > 0) { return -ENODEV; } @@ -1220,27 +1217,18 @@ static ssize_t ftdi_elan_write(struct file *file, if (retval) { dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" "d\n", retval); - goto error_4; + goto error_3; } usb_free_urb(urb); - exit:; - if (count > m) { - int I = m - 1; - while (I-- > 0) { - d += sprintf(d, " %02X", 0x000000FF & *s++); - } - d += sprintf(d, " .."); - } else { - int I = count; - while (I-- > 0) { - d += sprintf(d, " %02X", 0x000000FF & *s++); - } - } + +exit: return count; - error_4: error_3:usb_buffer_free(ftdi->udev, count, buf, - urb->transfer_dma); - error_2:usb_free_urb(urb); - error_1:return retval; +error_3: + usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma); +error_2: + usb_free_urb(urb); +error_1: + return retval; } static struct file_operations ftdi_elan_fops = { -- GitLab From b62df4516981745d4b5de01ceec1d65a9174a524 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 Oct 2006 10:54:00 -0400 Subject: [PATCH 1351/1619] UHCI: workaround for Asus motherboard This patch (as798) adds a workaround to uhci-hcd. At least one Asus motherboard is wired in such a way that any device attached to a suspended UHCI controller will prevent the system from entering suspend-to-RAM by immediately waking it up. The only way around the problem is to turn the controller off instead of suspending it. This fixes Bugzilla #6193. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 45ee6920a85..226bf3de8ed 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) return 0; } +static int remote_wakeup_is_broken(struct uhci_hcd *uhci) +{ + static struct dmi_system_id broken_wakeup_table[] = { + { + .ident = "Asus A7V8X", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"), + DMI_MATCH(DMI_BOARD_NAME, "A7V8X"), + DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"), + } + }, + { } + }; + int port; + + /* One of Asus's motherboards has a bug which causes it to + * wake up immediately from suspend-to-RAM if any of the ports + * are connected. In such cases we will not set EGSM. + */ + if (dmi_check_system(broken_wakeup_table)) { + for (port = 0; port < uhci->rh_numports; ++port) { + if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & + USBPORTSC_CCS) + return 1; + } + } + + return 0; +} + static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) __releases(uhci->lock) __acquires(uhci->lock) { int auto_stop; - int int_enable; + int int_enable, egsm_enable; auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, @@ -217,15 +248,18 @@ __acquires(uhci->lock) } /* Enable resume-detect interrupts if they work. - * Then enter Global Suspend mode, still configured. + * Then enter Global Suspend mode if _it_ works, still configured. */ + egsm_enable = USBCMD_EGSM; uhci->working_RD = 1; int_enable = USBINTR_RESUME; - if (resume_detect_interrupts_are_broken(uhci)) { + if (remote_wakeup_is_broken(uhci)) + egsm_enable = 0; + if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable) uhci->working_RD = int_enable = 0; - } + outw(int_enable, uhci->io_addr + USBINTR); - outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); + outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); mb(); udelay(5); -- GitLab From c40fd5ea565587c05b0e2c49c02cad2c35fd85c6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 Oct 2006 11:55:47 -0400 Subject: [PATCH 1352/1619] usbcore: fix refcount bug in endpoint removal This patch (as799) fixes a nasty refcount error in the USB endpoint class. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 3ebb90149e9..40ba76a1757 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -282,8 +282,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint) sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); device_unregister(&endpoint->ep_dev->dev); endpoint->ep_dev = NULL; + destroy_endpoint_class(); } - destroy_endpoint_class(); } - - -- GitLab From d5477c11111467e19787f00d3cab20fb48c2699e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 Oct 2006 11:56:26 -0400 Subject: [PATCH 1353/1619] usbcore: fix endpoint device creation This patch (as800) straightens out the USB endpoint class device creation routine, fixing a refcount bug in the process. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 40ba76a1757..3b2d137912b 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -223,7 +223,7 @@ int usb_create_ep_files(struct device *parent, ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); if (!ep_dev) { retval = -ENOMEM; - goto exit; + goto error_alloc; } /* fun calculation to determine the minor of this endpoint */ @@ -241,33 +241,31 @@ int usb_create_ep_files(struct device *parent, retval = device_register(&ep_dev->dev); if (retval) - goto error; + goto error_register; retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); if (retval) goto error_group; - endpoint->ep_dev = ep_dev; - /* create the symlink to the old-style "ep_XX" directory */ sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - retval = sysfs_create_link(&parent->kobj, - &endpoint->ep_dev->dev.kobj, name); + retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name); if (retval) goto error_link; -exit: + endpoint->ep_dev = ep_dev; return retval; error_link: sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); - error_group: device_unregister(&ep_dev->dev); - endpoint->ep_dev = NULL; destroy_endpoint_class(); return retval; -error: + +error_register: kfree(ep_dev); +error_alloc: destroy_endpoint_class(); +exit: return retval; } -- GitLab From f8ac232ad7388bfff680b26e84b3ac63889d1cea Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 8 Oct 2006 16:02:00 +0400 Subject: [PATCH 1354/1619] USB: drivers/usb/net/*: use BUILD_BUG_ON Signed-off-by: Alexey Dobriyan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/cdc_ether.c | 2 +- drivers/usb/net/usbnet.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 82ce0358d9a..f6971b88349 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = { static int __init cdc_init(void) { - BUG_ON((sizeof(((struct usbnet *)0)->data) + BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct cdc_state))); return usb_register(&cdc_driver); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 24bd3486ee6..af6d061dc79 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1225,7 +1225,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static int __init usbnet_init(void) { /* compiler should optimize this out */ - BUG_ON (sizeof (((struct sk_buff *)0)->cb) + BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)); random_ether_addr(node_id); -- GitLab From 27d39e2627dc7493f554bc0549d8c63953762478 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 9 Oct 2006 18:09:33 +0900 Subject: [PATCH 1355/1619] usb devio: handle class_device_create() error This patch adds missing class_device_create() error check, and makes notifier return NOTIFY_BAD. Signed-off-by: Akinobu Mita Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 724822cac2b..fed92be63b5 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1588,15 +1588,18 @@ const struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -static void usbdev_add(struct usb_device *dev) +static int usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); dev->class_dev = class_device_create(usb_device_class, NULL, MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); + if (IS_ERR(dev->class_dev)) + return PTR_ERR(dev->class_dev); dev->class_dev->class_data = dev; + return 0; } static void usbdev_remove(struct usb_device *dev) @@ -1609,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action, { switch (action) { case USB_DEVICE_ADD: - usbdev_add(dev); + if (usbdev_add(dev)) + return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: usbdev_remove(dev); -- GitLab From 2a36d7083438ccb607055abae633f39495a99947 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Oct 2006 00:08:00 +0200 Subject: [PATCH 1356/1619] USB: driver for mcs7830 (aka DeLOCK) USB ethernet adapter This driver adds support for the DeLOCK USB ethernet adapter and potentially others based on the MosChip MCS7830 chip. It is based on the usbnet and asix drivers as well as the original device driver provided by MosChip, which in turn was based on the usbnet driver. It has been tested successfully on an OHCI, but interestingly there seems to be a problem with the mcs7830 when connected to the ICH6/EHCI in my thinkpad: it keeps receiving lots of broken packets in the RX interrupt. The problem goes away when I'm using an active USB hub, so I assume it's not related to the device driver, but rather to the hardware. Signed-off-by: David Brownell Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 8 + drivers/usb/net/Makefile | 1 + drivers/usb/net/mcs7830.c | 525 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 534 insertions(+) create mode 100644 drivers/usb/net/mcs7830.c diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 054059632a2..454a186b64a 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -207,6 +207,14 @@ config USB_NET_PLUSB Choose this option if you're using a host-to-host cable with one of these chips. +config USB_NET_MCS7830 + tristate "MosChip MCS7830 based Ethernet adapters" + depends on USB_USBNET + help + Choose this option if you're using a 10/100 Ethernet USB2 + adapter based on the MosChip 7830 controller. This includes + adapters marketed under the DeLOCK brand. + config USB_NET_RNDIS_HOST tristate "Host for RNDIS devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 160f19dbdf1..7b51964de17 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o +obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o ifeq ($(CONFIG_USB_DEBUG),y) diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c new file mode 100644 index 00000000000..0266090a1d7 --- /dev/null +++ b/drivers/usb/net/mcs7830.c @@ -0,0 +1,525 @@ +/* + * MosChips MCS7830 based USB 2.0 Ethernet Devices + * + * based on usbnet.c, asix.c and the vendor provided mcs7830 driver + * + * Copyright (C) 2006 Arnd Bergmann + * Copyright (C) 2003-2005 David Hollis + * Copyright (C) 2005 Phil Chang + * Copyright (c) 2002-2003 TiVo 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 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 "usbnet.h" + +/* requests */ +#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ + USB_RECIP_DEVICE) +#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ + USB_RECIP_DEVICE) +#define MCS7830_RD_BREQ 0x0E +#define MCS7830_WR_BREQ 0x0D + +#define MCS7830_CTRL_TIMEOUT 1000 +#define MCS7830_MAX_MCAST 64 + +#define MCS7830_VENDOR_ID 0x9710 +#define MCS7830_PRODUCT_ID 0x7830 + +#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ + ADVERTISE_100HALF | ADVERTISE_10FULL | \ + ADVERTISE_10HALF | ADVERTISE_CSMA) + +/* HIF_REG_XX coressponding index value */ +enum { + HIF_REG_MULTICAST_HASH = 0x00, + HIF_REG_PACKET_GAP1 = 0x08, + HIF_REG_PACKET_GAP2 = 0x09, + HIF_REG_PHY_DATA = 0x0a, + HIF_REG_PHY_CMD1 = 0x0c, + HIF_REG_PHY_CMD1_READ = 0x40, + HIF_REG_PHY_CMD1_WRITE = 0x20, + HIF_REG_PHY_CMD1_PHYADDR = 0x01, + HIF_REG_PHY_CMD2 = 0x0d, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, + HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, + HIF_REG_CONFIG = 0x0e, + HIF_REG_CONFIG_CFG = 0x80, + HIF_REG_CONFIG_SPEED100 = 0x40, + HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, + HIF_REG_CONFIG_RXENABLE = 0x10, + HIF_REG_CONFIG_TXENABLE = 0x08, + HIF_REG_CONFIG_SLEEPMODE = 0x04, + HIF_REG_CONFIG_ALLMULTICAST = 0x02, + HIF_REG_CONFIG_PROMISCIOUS = 0x01, + HIF_REG_ETHERNET_ADDR = 0x0f, + HIF_REG_22 = 0x15, + HIF_REG_PAUSE_THRESHOLD = 0x16, + HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, +}; + +struct mcs7830_data { + u8 multi_filter[8]; + u8 config; +}; + +static const char driver_name[] = "MOSCHIP usb-ethernet driver"; + +static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_device *xdev = dev->udev; + int ret; + + ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, + MCS7830_RD_BMREQ, 0x0000, index, data, + size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); + return ret; +} + +static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_device *xdev = dev->udev; + int ret; + + ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, + MCS7830_WR_BMREQ, 0x0000, index, data, + size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); + return ret; +} + +static void mcs7830_async_cmd_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + + if (urb->status < 0) + printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d", + urb->status); + + kfree(req); + usb_free_urb(urb); +} + +static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_ctrlrequest *req; + int ret; + struct urb *urb; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + dev_dbg(&dev->udev->dev, "Error allocating URB " + "in write_cmd_async!"); + return; + } + + req = kmalloc(sizeof *req, GFP_ATOMIC); + if (!req) { + dev_err(&dev->udev->dev, "Failed to allocate memory for " + "control request"); + goto out; + } + req->bRequestType = MCS7830_WR_BMREQ; + req->bRequest = MCS7830_WR_BREQ; + req->wValue = 0; + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, size, + mcs7830_async_cmd_callback, req); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(&dev->udev->dev, "Error submitting the control " + "message: ret=%d", ret); + goto out; + } + return; +out: + kfree(req); + usb_free_urb(urb); +} + +static int mcs7830_get_address(struct usbnet *dev) +{ + int ret; + ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, + dev->net->dev_addr); + if (ret < 0) + return ret; + return 0; +} + +static int mcs7830_read_phy(struct usbnet *dev, u8 index) +{ + int ret; + int i; + __le16 val; + + u8 cmd[2] = { + HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, + }; + + /* write the MII command */ + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if (ret < 0) + goto out; + + /* wait for the data to become valid, should be within < 1ms */ + for (i = 0; i < 10; i++) { + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) + break; + ret = -EIO; + msleep(1); + } + if (ret < 0) + goto out; + + /* read actual register contents */ + ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); + if (ret < 0) + goto out; + ret = le16_to_cpu(val); + dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", + index, val, i); +out: + return ret; +} + +static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) +{ + int ret; + int i; + __le16 le_val; + + u8 cmd[2] = { + HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), + }; + + /* write the new register contents */ + le_val = cpu_to_le16(val); + ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); + if (ret < 0) + goto out; + + /* write the MII command */ + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if (ret < 0) + goto out; + + /* wait for the command to be accepted by the PHY */ + for (i = 0; i < 10; i++) { + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) + break; + ret = -EIO; + msleep(1); + } + if (ret < 0) + goto out; + + ret = 0; + dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", + index, val, i); +out: + return ret; +} + +/* + * This algorithm comes from the original mcs7830 version 1.4 driver, + * not sure if it is needed. + */ +static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) +{ + int ret; + /* Enable all media types */ + ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); + + /* First reset BMCR */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); + /* Enable Auto Neg */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); + /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART ); + return ret < 0 ? : 0; +} + + +/* + * if we can read register 22, the chip revision is C or higher + */ +static int mcs7830_get_rev(struct usbnet *dev) +{ + u8 dummy[2]; + int ret; + ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); + if (ret > 0) + return 2; /* Rev C or later */ + return 1; /* earlier revision */ +} + +/* + * On rev. C we need to set the pause threshold + */ +static void mcs7830_rev_C_fixup(struct usbnet *dev) +{ + u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; + int retry; + + for (retry = 0; retry < 2; retry++) { + if (mcs7830_get_rev(dev) == 2) { + dev_info(&dev->udev->dev, "applying rev.C fixup\n"); + mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, + 1, &pause_threshold); + } + msleep(1); + } +} + +static int mcs7830_init_dev(struct usbnet *dev) +{ + int ret; + int retry; + + /* Read MAC address from EEPROM */ + ret = -EINVAL; + for (retry = 0; retry < 5 && ret; retry++) + ret = mcs7830_get_address(dev); + if (ret) { + dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); + goto out; + } + + /* Set up PHY */ + ret = mcs7830_set_autoneg(dev, 0); + if (ret) { + dev_info(&dev->udev->dev, "Cannot set autoneg\n"); + goto out; + } + + mcs7830_rev_C_fixup(dev); + ret = 0; +out: + return ret; +} + +static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, + int location) +{ + struct usbnet *dev = netdev->priv; + return mcs7830_read_phy(dev, location); +} + +static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, + int location, int val) +{ + struct usbnet *dev = netdev->priv; + mcs7830_write_phy(dev, location, val); +} + +static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +/* credits go to asix_set_multicast */ +static void mcs7830_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; + + data->config = HIF_REG_CONFIG_TXENABLE; + + /* this should not be needed, but it doesn't work otherwise */ + data->config |= HIF_REG_CONFIG_ALLMULTICAST; + + if (net->flags & IFF_PROMISC) { + data->config |= HIF_REG_CONFIG_PROMISCIOUS; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > MCS7830_MAX_MCAST) { + data->config |= HIF_REG_CONFIG_ALLMULTICAST; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later */ + struct dev_mc_list *mc_list = net->mc_list; + u32 crc_bits; + int i; + + memset(data->multi_filter, 0, sizeof data->multi_filter); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; + data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, + sizeof data->multi_filter, + data->multi_filter); + } + + mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); +} + +static int mcs7830_get_regs_len(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + switch (mcs7830_get_rev(dev)) { + case 1: + return 21; + case 2: + return 32; + } + return 0; +} + +static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) +{ + usbnet_get_drvinfo(net, drvinfo); + drvinfo->regdump_len = mcs7830_get_regs_len(net); +} + +static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) +{ + struct usbnet *dev = netdev_priv(net); + + regs->version = mcs7830_get_rev(dev); + mcs7830_get_reg(dev, 0, regs->len, data); +} + +static struct ethtool_ops mcs7830_ethtool_ops = { + .get_drvinfo = mcs7830_get_drvinfo, + .get_regs_len = mcs7830_get_regs_len, + .get_regs = mcs7830_get_regs, + + /* common usbnet calls */ + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, +}; + +static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) +{ + struct net_device *net = dev->net; + int ret; + + ret = mcs7830_init_dev(dev); + if (ret) + goto out; + + net->do_ioctl = mcs7830_ioctl; + net->ethtool_ops = &mcs7830_ethtool_ops; + net->set_multicast_list = mcs7830_set_multicast; + mcs7830_set_multicast(net); + + /* reserve space for the status byte on rx */ + dev->rx_urb_size = ETH_FRAME_LEN + 1; + + dev->mii.mdio_read = mcs7830_mdio_read; + dev->mii.mdio_write = mcs7830_mdio_write; + dev->mii.dev = net; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = *((u8 *) net->dev_addr + 1); + + ret = usbnet_get_endpoints(dev, udev); +out: + return ret; +} + +/* The chip always appends a status bytes that we need to strip */ +static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + u8 status; + + if (skb->len == 0) { + dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); + return 0; + } + + skb_trim(skb, skb->len - 1); + status = skb->data[skb->len]; + + if (status != 0x20) + dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); + + return skb->len > 0; +} + +static const struct driver_info moschip_info = { + .description = "MOSCHIP 7830 usb-NET adapter", + .bind = mcs7830_bind, + .rx_fixup = mcs7830_rx_fixup, + .flags = FLAG_ETHER, + .in = 1, + .out = 2, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), + .driver_info = (unsigned long) &moschip_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver mcs7830_driver = { + .name = driver_name, + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init mcs7830_init(void) +{ + return usb_register(&mcs7830_driver); +} +module_init(mcs7830_init); + +static void __exit mcs7830_exit(void) +{ + usb_deregister(&mcs7830_driver); +} +module_exit(mcs7830_exit); + +MODULE_DESCRIPTION("USB to network adapter MCS7830)"); +MODULE_LICENSE("GPL"); -- GitLab From c41286fd42f3545513f8de9f61028120b6d38e89 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Oct 2006 00:08:01 +0200 Subject: [PATCH 1357/1619] usbnet: improve generic ethtool support This adds generic support for the ethtool commands get_settings, set_settings, get_link and nway_reset to usbnet. These are now implemented using mii functions when a low-level driver supports mdio_read/mdio_write and does not override the usbnet ethtool commands with its own. Currently, this applies to the asix and the mcs7830 drivers. I have tested it on mcs7830. Signed-off-by: Arnd Bergmann Acked-by: David Hollis Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/asix.c | 44 +++++++-------------------------- drivers/usb/net/mcs7830.c | 4 +++ drivers/usb/net/usbnet.c | 52 ++++++++++++++++++++++++++++++++++++++- drivers/usb/net/usbnet.h | 4 +++ 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index c73dd224aa7..5edd0534c7a 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -700,32 +700,6 @@ static void asix_get_drvinfo (struct net_device *net, info->eedump_len = data->eeprom_len; } -static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_gset(&dev->mii,cmd); -} - -static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - int res = mii_ethtool_sset(&dev->mii,cmd); - - /* link speed/duplex might have changed */ - if (dev->driver_info->link_reset) - dev->driver_info->link_reset(dev); - - return res; -} - -static int asix_nway_reset(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_nway_restart(&dev->mii); -} - static u32 asix_get_link(struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -746,15 +720,15 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) static struct ethtool_ops ax88172_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static void ax88172_set_multicast(struct net_device *net) @@ -885,15 +859,15 @@ out1: static struct ethtool_ops ax88772_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int ax88772_link_reset(struct usbnet *dev) @@ -1046,15 +1020,15 @@ out1: static struct ethtool_ops ax88178_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int marvell_phy_init(struct usbnet *dev) diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c index 0266090a1d7..23a80667f17 100644 --- a/drivers/usb/net/mcs7830.c +++ b/drivers/usb/net/mcs7830.c @@ -430,8 +430,12 @@ static struct ethtool_ops mcs7830_ethtool_ops = { .get_regs = mcs7830_get_regs, /* common usbnet calls */ + .get_link = usbnet_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index af6d061dc79..decc1b17924 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -669,6 +669,37 @@ done: * they'll probably want to use this base set. */ +int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + + if (!dev->mii.mdio_read) + return -EOPNOTSUPP; + + return mii_ethtool_gset(&dev->mii, cmd); +} +EXPORT_SYMBOL_GPL(usbnet_get_settings); + +int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + int retval; + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; + + retval = mii_ethtool_sset(&dev->mii, cmd); + + /* link speed/duplex might have changed */ + if (dev->driver_info->link_reset) + dev->driver_info->link_reset(dev); + + return retval; + +} +EXPORT_SYMBOL_GPL(usbnet_set_settings); + + void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { struct usbnet *dev = netdev_priv(net); @@ -682,7 +713,7 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) } EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); -static u32 usbnet_get_link (struct net_device *net) +u32 usbnet_get_link (struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -690,9 +721,14 @@ static u32 usbnet_get_link (struct net_device *net) if (dev->driver_info->check_connect) return dev->driver_info->check_connect (dev) == 0; + /* if the device has mii operations, use those */ + if (dev->mii.mdio_read) + return mii_link_ok(&dev->mii); + /* Otherwise, say we're up (to avoid breaking scripts) */ return 1; } +EXPORT_SYMBOL_GPL(usbnet_get_link); u32 usbnet_get_msglevel (struct net_device *net) { @@ -710,10 +746,24 @@ void usbnet_set_msglevel (struct net_device *net, u32 level) } EXPORT_SYMBOL_GPL(usbnet_set_msglevel); +int usbnet_nway_reset(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; + + return mii_nway_restart(&dev->mii); +} +EXPORT_SYMBOL_GPL(usbnet_nway_reset); + /* drivers may override default ethtool_ops in their bind() routine */ static struct ethtool_ops usbnet_ethtool_ops = { + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, .get_drvinfo = usbnet_get_drvinfo, .get_link = usbnet_get_link, + .nway_reset = usbnet_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, }; diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index c0746f0454a..743947c3fb8 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -168,9 +168,13 @@ extern void usbnet_defer_kevent (struct usbnet *, int); extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); extern void usbnet_unlink_rx_urbs(struct usbnet *); +extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); +extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); +extern u32 usbnet_get_link (struct net_device *net); extern u32 usbnet_get_msglevel (struct net_device *); extern void usbnet_set_msglevel (struct net_device *, u32); extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); +extern int usbnet_nway_reset(struct net_device *net); /* messaging support includes the interface name, so it must not be * used before it has one ... notably, in minidriver bind() calls. -- GitLab From a9fc6338bd51a3d5735839e756fe7b741c2e6fad Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Oct 2006 00:08:02 +0200 Subject: [PATCH 1358/1619] usbnet: add a mutex around phy register access When working on the mcs7830, I noticed the need for a mutex in its mdio_read/mdio_write functions. A related problem seems to be present in the asix driver in the respective functions. This introduces a mutex in the common usbnet driver and uses it from the two hardware specific drivers. Acked-by: David Hollis Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/asix.c | 4 ++++ drivers/usb/net/mcs7830.c | 5 +++++ drivers/usb/net/usbnet.c | 1 + drivers/usb/net/usbnet.h | 1 + 4 files changed, 11 insertions(+) diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 5edd0534c7a..881841e600d 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -569,10 +569,12 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) struct usbnet *dev = netdev_priv(netdev); u16 res; + mutex_lock(&dev->phy_mutex); asix_set_sw_mii(dev); asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); asix_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); @@ -586,10 +588,12 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) u16 res = cpu_to_le16(val); devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); + mutex_lock(&dev->phy_mutex); asix_set_sw_mii(dev); asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); asix_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); } /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c index 23a80667f17..6240b978fe3 100644 --- a/drivers/usb/net/mcs7830.c +++ b/drivers/usb/net/mcs7830.c @@ -184,6 +184,7 @@ static int mcs7830_read_phy(struct usbnet *dev, u8 index) HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, }; + mutex_lock(&dev->phy_mutex); /* write the MII command */ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); if (ret < 0) @@ -208,6 +209,7 @@ static int mcs7830_read_phy(struct usbnet *dev, u8 index) dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", index, val, i); out: + mutex_unlock(&dev->phy_mutex); return ret; } @@ -222,6 +224,8 @@ static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), }; + mutex_lock(&dev->phy_mutex); + /* write the new register contents */ le_val = cpu_to_le16(val); ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); @@ -248,6 +252,7 @@ static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", index, val, i); out: + mutex_unlock(&dev->phy_mutex); return ret; } diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index decc1b17924..cf3d20eb781 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1144,6 +1144,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); + mutex_init (&dev->phy_mutex); SET_MODULE_OWNER (net); dev->net = net; diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index 743947c3fb8..07c70abbe0e 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -30,6 +30,7 @@ struct usbnet { struct usb_device *udev; struct driver_info *driver_info; wait_queue_head_t *wait; + struct mutex phy_mutex; /* i/o info: pipes etc */ unsigned in, out; -- GitLab From 9fcde235270e6783600d1aee5bcda78c8282bcdd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 10 Oct 2006 13:47:35 -0700 Subject: [PATCH 1359/1619] USB: move trancevibrator.c to the proper usb directory It's not a input driver, so it doesn't belong in the input directory. Cc: Sam Hocevar Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 2 +- drivers/usb/input/Kconfig | 10 ---------- drivers/usb/input/Makefile | 1 - drivers/usb/misc/Kconfig | 10 ++++++++++ drivers/usb/misc/Makefile | 1 + drivers/usb/{input => misc}/trancevibrator.c | 0 6 files changed, 12 insertions(+), 12 deletions(-) rename drivers/usb/{input => misc}/trancevibrator.c (100%) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 97d57cfc343..825bf884537 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_USB_KBTAB) += input/ obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_POWERMATE) += input/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/ obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_XPAD) += input/ @@ -66,6 +65,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_SISUSBVGA) += misc/ obj-$(CONFIG_USB_TEST) += misc/ +obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_ATM) += atm/ diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 21cd2264008..20db36448ab 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -348,13 +348,3 @@ config USB_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. - -config USB_TRANCEVIBRATOR - tristate "PlayStation 2 Trance Vibrator driver support" - depends on USB - help - Say Y here if you want to connect a PlayStation 2 Trance Vibrator - device to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called trancevibrator. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 71437db7e9b..d946d5213b3 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -48,7 +48,6 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o -obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c29658f69e2..a74bf8617e7 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -223,6 +223,16 @@ config USB_LD To compile this driver as a module, choose M here: the module will be called ldusb. +config USB_TRANCEVIBRATOR + tristate "PlayStation 2 Trance Vibrator driver support" + depends on USB + help + Say Y here if you want to connect a PlayStation 2 Trance Vibrator + device to your computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called trancevibrator. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2be70fa259b..11dc59540cd 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_TEST) += usbtest.o +obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ diff --git a/drivers/usb/input/trancevibrator.c b/drivers/usb/misc/trancevibrator.c similarity index 100% rename from drivers/usb/input/trancevibrator.c rename to drivers/usb/misc/trancevibrator.c -- GitLab From 0f64478cbc7a008fe7b7e9ae79a73d8a6904ead8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 9 Apr 2002 12:14:34 -0700 Subject: [PATCH 1360/1619] USB: add USB serial mos7720 driver Add support for Moschip 7720 USB dual port usb to serial device. This driver is originally based on the drivers/usb/io_edgeport.c driver. Cleaned up and forward ported by me. Cc: VijayaKumar Cc: AjayKumar Cc: Gurudeva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/mos7720.c | 1683 ++++++++++++++++++++++++++++++++++ 3 files changed, 1694 insertions(+) create mode 100644 drivers/usb/serial/mos7720.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5076b9d9705..8ca6d3f01e8 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_MOS7720 + tristate "USB Moschip 7720 Single Port Serial Driver" + depends on USB_SERIAL + ---help--- + Say Y here if you want to use a USB Serial single port adapter from + Moschip Semiconductor Tech. + + To compile this driver as a module, choose M here: the + module will be called mos7720. + config USB_SERIAL_MOS7840 tristate "USB Moschip 7840/7820 USB Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 8dce83340e3..a5047dc599b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c new file mode 100644 index 00000000000..82cd15b894b --- /dev/null +++ b/drivers/usb/serial/mos7720.c @@ -0,0 +1,1683 @@ +/* + * mos7720.c + * Controls the Moschip 7720 usb to dual port serial convertor + * + * Copyright 2006 Moschip Semiconductor Tech. Ltd. + * + * 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. + * + * Developed by: + * VijayaKumar.G.N. + * AjayKumar + * Gurudeva.N. + * + * Cleaned up from the original by: + * Greg Kroah-Hartman + * + * Originally based on drivers/usb/serial/io_edgeport.c which is: + * Copyright (C) 2000 Inside Out Networks, All rights reserved. + * Copyright (C) 2001-2002 Greg Kroah-Hartman + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Version Information + */ +#define DRIVER_VERSION "1.0.0.4F" +#define DRIVER_AUTHOR "Aspire Communications pvt Ltd." +#define DRIVER_DESC "Moschip USB Serial Driver" + +/* default urb timeout */ +#define MOS_WDR_TIMEOUT (HZ * 5) + +#define MOS_PORT1 0x0200 +#define MOS_PORT2 0x0300 +#define MOS_VENREG 0x0000 +#define MOS_MAX_PORT 0x02 +#define MOS_WRITE 0x0E +#define MOS_READ 0x0D + +/* Interrupt Rotinue Defines */ +#define SERIAL_IIR_RLS 0x06 +#define SERIAL_IIR_RDA 0x04 +#define SERIAL_IIR_CTI 0x0c +#define SERIAL_IIR_THR 0x02 +#define SERIAL_IIR_MS 0x00 + +#define NUM_URBS 16 /* URB Count */ +#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ + +/* This structure holds all of the local port information */ +struct moschip_port +{ + __u8 shadowLCR; /* last LCR value received */ + __u8 shadowMCR; /* last MCR value received */ + __u8 shadowMSR; /* last MSR value received */ + char open; + struct async_icount icount; + struct usb_serial_port *port; /* loop back to the owner */ + struct urb *write_urb_pool[NUM_URBS]; +}; + +/* This structure holds all of the individual serial device information */ +struct moschip_serial +{ + int interrupt_started; +}; + +static int debug; + +#define USB_VENDOR_ID_MOSCHIP 0x9710 +#define MOSCHIP_DEVICE_ID_7720 0x7720 +#define MOSCHIP_DEVICE_ID_7715 0x7715 + +static struct usb_device_id moschip_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) }, + { } /* terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, moschip_port_id_table); + + +/* + * mos7720_interrupt_callback + * this is the callback function for when we have received data on the + * interrupt endpoint. + */ +static void mos7720_interrupt_callback(struct urb *urb) +{ + int result; + int length; + __u32 *data; + unsigned int status; + __u8 sp1; + __u8 sp2; + __u8 st; + + dbg("%s"," : Entering\n"); + + if (!urb) { + dbg("%s","Invalid Pointer !!!!:\n"); + return; + } + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, + urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, + urb->status); + goto exit; + } + + length = urb->actual_length; + data = urb->transfer_buffer; + + /* Moschip get 4 bytes + * Byte 1 IIR Port 1 (port.number is 0) + * Byte 2 IIR Port 2 (port.number is 1) + * Byte 3 -------------- + * Byte 4 FIFO status for both */ + if (length && length > 4) { + dbg("Wrong data !!!"); + return; + } + + status = *data; + + sp1 = (status & 0xff000000)>>24; + sp2 = (status & 0x00ff0000)>>16; + st = status & 0x000000ff; + + if ((sp1 & 0x01) || (sp2 & 0x01)) { + /* No Interrupt Pending in both the ports */ + dbg("No Interrupt !!!"); + } else { + switch (sp1 & 0x0f) { + case SERIAL_IIR_RLS: + dbg("Serial Port 1: Receiver status error or address " + "bit detected in 9-bit mode\n"); + break; + case SERIAL_IIR_CTI: + dbg("Serial Port 1: Receiver time out"); + break; + case SERIAL_IIR_MS: + dbg("Serial Port 1: Modem status change"); + break; + } + + switch (sp2 & 0x0f) { + case SERIAL_IIR_RLS: + dbg("Serial Port 2: Receiver status error or address " + "bit detected in 9-bit mode"); + break; + case SERIAL_IIR_CTI: + dbg("Serial Port 2: Receiver time out"); + break; + case SERIAL_IIR_MS: + dbg("Serial Port 2: Modem status change"); + break; + } + } + +exit: + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) + dev_err(&urb->dev->dev, + "%s - Error %d submitting control urb\n", + __FUNCTION__, result); + return; +} + +/* + * mos7720_bulk_in_callback + * this is the callback function for when we have received data on the + * bulk in endpoint. + */ +static void mos7720_bulk_in_callback(struct urb *urb) +{ + int status; + unsigned char *data ; + struct usb_serial_port *port; + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + if (urb->status) { + dbg("nonzero read bulk status received: %d",urb->status); + return; + } + + mos7720_port = urb->context; + if (!mos7720_port) { + dbg("%s","NULL mos7720_port pointer \n"); + return ; + } + + port = mos7720_port->port; + + dbg("Entering...%s", __FUNCTION__); + + data = urb->transfer_buffer; + + tty = port->tty; + if (tty && urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } + + if (!port->read_urb) { + dbg("URB KILLED !!!"); + return; + } + + if (port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = port->serial->dev; + + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } +} + +/* + * mos7720_bulk_out_data_callback + * this is the callback function for when we have finished sending serial + * data on the bulk out endpoint. + */ +static void mos7720_bulk_out_data_callback(struct urb *urb) +{ + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + if (urb->status) { + dbg("nonzero write bulk status received:%d", urb->status); + return; + } + + mos7720_port = urb->context; + if (!mos7720_port) { + dbg("NULL mos7720_port pointer"); + return ; + } + + dbg("Entering ........."); + + tty = mos7720_port->port->tty; + + if (tty && mos7720_port->open) { + /* let the tty driver wakeup if it has a special * + * write_wakeup function */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&tty->write_wait); + } + + /* schedule_work(&mos7720_port->port->work); */ +} + +/* + * send_mos_cmd + * this function will be used for sending command to device + */ +static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, + __u16 index, void *data) +{ + int status; + unsigned int pipe; + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + __u8 requesttype; + __u16 size = 0x0000; + + if (value < MOS_MAX_PORT) { + if (product == MOSCHIP_DEVICE_ID_7715) { + value = value*0x100+0x100; + } else { + value = value*0x100+0x200; + } + } else { + value = 0x0000; + if ((product == MOSCHIP_DEVICE_ID_7715) && + (index != 0x08)) { + dbg("serial->product== MOSCHIP_DEVICE_ID_7715"); + //index = 0x01 ; + } + } + + if (request == MOS_WRITE) { + request = (__u8)MOS_WRITE; + requesttype = (__u8)0x40; + value = value + (__u16)*((unsigned char *)data); + data = NULL; + pipe = usb_sndctrlpipe(serial->dev, 0); + } else { + request = (__u8)MOS_READ; + requesttype = (__u8)0xC0; + size = 0x01; + pipe = usb_rcvctrlpipe(serial->dev,0); + } + + status = usb_control_msg(serial->dev, pipe, request, requesttype, + value, index, data, size, MOS_WDR_TIMEOUT); + + if (status < 0) + dbg("Command Write failed Value %x index %x\n",value,index); + + return status; +} + +static int mos7720_open(struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial; + struct usb_serial_port *port0; + struct urb *urb; + struct moschip_serial *mos7720_serial; + struct moschip_port *mos7720_port; + int response; + int port_number; + char data; + int j; + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return -ENODEV; + + port0 = serial->port[0]; + + mos7720_serial = usb_get_serial_data(serial); + + if (mos7720_serial == NULL || port0 == NULL) + return -ENODEV; + + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + + /* Initialising the write urb pool */ + for (j = 0; j < NUM_URBS; ++j) { + urb = usb_alloc_urb(0,SLAB_ATOMIC); + mos7720_port->write_urb_pool[j] = urb; + + if (urb == NULL) { + err("No more urbs???"); + continue; + } + + urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (!urb->transfer_buffer) { + err("%s-out of memory for urb buffers.", __FUNCTION__); + continue; + } + } + + /* Initialize MCS7720 -- Write Init values to corresponding Registers + * + * Register Index + * 1 : IER + * 2 : FCR + * 3 : LCR + * 4 : MCR + * + * 0x08 : SP1/2 Control Reg + */ + port_number = port->number - port->serial->minor; + send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); + dbg("SS::%p LSR:%x\n",mos7720_port, data); + + dbg("Check:Sending Command .........."); + + data = 0x02; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data); + data = 0x02; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + + data = 0xCF; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + data = 0x03; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x0b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + +/* data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data); + data = 0x03; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); + data = 0x00; + send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); +*/ + data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + + data = data | (port->number - port->serial->minor + 1); + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + data = 0x83; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x03; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + +//Matrix + + /* force low_latency on so that our tty_push actually forces * + * the data through,otherwise it is scheduled, and with * + * high data rates (like with OHCI) data can get lost. */ + + if (port->tty) + port->tty->low_latency = 1; + + /* see if we've set up our endpoint info yet * + * (can't set it up in mos7720_startup as the * + * structures were not set up at that time.) */ + if (!mos7720_serial->interrupt_started) { + dbg("Interrupt buffer NULL !!!"); + + /* not set up yet, so do it now */ + mos7720_serial->interrupt_started = 1; + + dbg("To Submit URB !!!"); + + /* set up our interrupt urb */ + usb_fill_int_urb(port0->interrupt_in_urb, serial->dev, + usb_rcvintpipe(serial->dev, + port->interrupt_in_endpointAddress), + port0->interrupt_in_buffer, + port0->interrupt_in_urb->transfer_buffer_length, + mos7720_interrupt_callback, mos7720_port, + port0->interrupt_in_urb->interval); + + /* start interrupt read for this mos7720 this interrupt * + * will continue as long as the mos7720 is connected */ + dbg("Submit URB over !!!"); + response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL); + if (response) + dev_err(&port->dev, + "%s - Error %d submitting control urb", + __FUNCTION__, response); + } + + /* set up our bulk in urb */ + usb_fill_bulk_urb(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, + port->read_urb->transfer_buffer_length, + mos7720_bulk_in_callback, mos7720_port); + response = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (response) + dev_err(&port->dev, + "%s - Error %d submitting read urb", __FUNCTION__, response); + + /* initialize our icount structure */ + memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); + + /* initialize our port settings */ + mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ + + /* send a open port command */ + mos7720_port->open = 1; + + return 0; +} + +/* + * mos7720_chars_in_buffer + * this function is called by the tty driver when it wants to know how many + * bytes of data we currently have outstanding in the port (data that has + * been written, but hasn't made it out the port yet) + * If successful, we return the number of bytes left to be written in the + * system, + * Otherwise we return a negative error number. + */ +static int mos7720_chars_in_buffer(struct usb_serial_port *port) +{ + int i; + int chars = 0; + struct moschip_port *mos7720_port; + + dbg("%s:entering ...........", __FUNCTION__); + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("%s:leaving ...........", __FUNCTION__); + return -ENODEV; + } + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) + chars += URB_TRANSFER_BUFFER_SIZE; + } + dbg("%s - returns %d", __FUNCTION__, chars); + return chars; +} + +static void mos7720_close(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial; + struct moschip_port *mos7720_port; + char data; + int j; + + dbg("mos7720_close:entering..."); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return; + + for (j = 0; j < NUM_URBS; ++j) + usb_kill_urb(mos7720_port->write_urb_pool[j]); + + /* Freeing Write URBs */ + for (j = 0; j < NUM_URBS; ++j) { + if (mos7720_port->write_urb_pool[j]) { + kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); + usb_free_urb(mos7720_port->write_urb_pool[j]); + } + } + + /* While closing port, shutdown all bulk read, write * + * and interrupt read if they exists */ + if (serial->dev) { + dbg("Shutdown bulk write"); + usb_kill_urb(port->write_urb); + dbg("Shutdown bulk read"); + usb_kill_urb(port->read_urb); + } + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x01, &data); + + mos7720_port->open = 0; + + dbg("Leaving %s", __FUNCTION__); +} + +static void mos7720_break(struct usb_serial_port *port, int break_state) +{ + unsigned char data; + struct usb_serial *serial; + struct moschip_port *mos7720_port; + + dbg("Entering %s", __FUNCTION__); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return; + + if (break_state == -1) + data = mos7720_port->shadowLCR | UART_LCR_SBC; + else + data = mos7720_port->shadowLCR & ~UART_LCR_SBC; + + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x03, &data); + + return; +} + +/* + * mos7720_write_room + * this function is called by the tty driver when it wants to know how many + * bytes of data we can accept for a specific port. + * If successful, we return the amount of room that we have for this port + * Otherwise we return a negative error number. + */ +static int mos7720_write_room(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + int room = 0; + int i; + + dbg("%s:entering ...........", __FUNCTION__); + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("%s:leaving ...........", __FUNCTION__); + return -ENODEV; + } + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) + room += URB_TRANSFER_BUFFER_SIZE; + } + + dbg("%s - returns %d", __FUNCTION__, room); + return room; +} + +static int mos7720_write(struct usb_serial_port *port, + const unsigned char *data, int count) +{ + int status; + int i; + int bytes_sent = 0; + int transfer_size; + + struct moschip_port *mos7720_port; + struct usb_serial *serial; + struct urb *urb; + const unsigned char *current_position = data; + + dbg("%s:entering ...........", __FUNCTION__); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("mos7720_port is NULL"); + return -ENODEV; + } + + /* try to find a free urb in the list */ + urb = NULL; + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { + urb = mos7720_port->write_urb_pool[i]; + dbg("URB:%d",i); + break; + } + } + + if (urb == NULL) { + dbg("%s - no more free urbs", __FUNCTION__); + goto exit; + } + + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err("%s no more kernel memory...", __FUNCTION__); + goto exit; + } + } + transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE); + + memcpy(urb->transfer_buffer, current_position, transfer_size); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, + urb->transfer_buffer); + + /* fill urb with data and submit */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, transfer_size, + mos7720_bulk_out_data_callback, mos7720_port); + + /* send it down the pipe */ + status = usb_submit_urb(urb,GFP_ATOMIC); + if (status) { + err("%s - usb_submit_urb(write bulk) failed with status = %d", + __FUNCTION__, status); + bytes_sent = status; + goto exit; + } + bytes_sent = transfer_size; + +exit: + return bytes_sent; +} + +static void mos7720_throttle(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + struct tty_struct *tty; + int status; + + dbg("%s- port %d\n", __FUNCTION__, port->number); + + mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + if (!mos7720_port->open) { + dbg("port not opened"); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + tty = port->tty; + if (!tty) { + dbg("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the stop character */ + if (I_IXOFF(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + status = mos7720_write(port, &stop_char, 1); + if (status <= 0) + return; + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + mos7720_port->shadowMCR &= ~UART_MCR_RTS; + status = send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, + UART_MCR, &mos7720_port->shadowMCR); + if (status != 0) + return; + } +} + +static void mos7720_unthrottle(struct usb_serial_port *port) +{ + struct tty_struct *tty; + int status; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + tty = port->tty; + if (!tty) { + dbg("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the start character */ + if (I_IXOFF(tty)) { + unsigned char start_char = START_CHAR(tty); + status = mos7720_write(port, &start_char, 1); + if (status <= 0) + return; + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + mos7720_port->shadowMCR |= UART_MCR_RTS; + status = send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, + UART_MCR, &mos7720_port->shadowMCR); + if (status != 0) + return; + } +} + +static int set_higher_rates(struct moschip_port *mos7720_port, + unsigned int baud) +{ + unsigned char data; + struct usb_serial_port *port; + struct usb_serial *serial; + int port_number; + + if (mos7720_port == NULL) + return -EINVAL; + + port = mos7720_port->port; + serial = port->serial; + + /*********************************************** + * Init Sequence for higher rates + ***********************************************/ + dbg("Sending Setting Commands .........."); + port_number = port->number - port->serial->minor; + + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + data = 0x0CF; + send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); + data = 0x00b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x00b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + data = 0x000; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + + /*********************************************** + * Set for higher rates * + ***********************************************/ + + data = baud * 0x10; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data); + + data = 0x003; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x003; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + data = 0x02b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x02b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + /*********************************************** + * Set DLL/DLM + ***********************************************/ + + data = mos7720_port->shadowLCR | UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + + data = 0x001; /* DLL */ + send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); + data = 0x000; /* DLM */ + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + + data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + + return 0; +} + +/* baud rate information */ +struct divisor_table_entry +{ + __u32 baudrate; + __u16 divisor; +}; + +/* Define table of divisors for moschip 7720 hardware * + * These assume a 3.6864MHz crystal, the standard /16, and * + * MCR.7 = 0. */ +static struct divisor_table_entry divisor_table[] = { + { 50, 2304}, + { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ + { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ + { 150, 768}, + { 300, 384}, + { 600, 192}, + { 1200, 96}, + { 1800, 64}, + { 2400, 48}, + { 4800, 24}, + { 7200, 16}, + { 9600, 12}, + { 19200, 6}, + { 38400, 3}, + { 57600, 2}, + { 115200, 1}, +}; + +/***************************************************************************** + * calc_baud_rate_divisor + * this function calculates the proper baud rate divisor for the specified + * baud rate. + *****************************************************************************/ +static int calc_baud_rate_divisor(int baudrate, int *divisor) +{ + int i; + __u16 custom; + __u16 round1; + __u16 round; + + + dbg("%s - %d", __FUNCTION__, baudrate); + + for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { + if (divisor_table[i].baudrate == baudrate) { + *divisor = divisor_table[i].divisor; + return 0; + } + } + + /* After trying for all the standard baud rates * + * Try calculating the divisor for this baud rate */ + if (baudrate > 75 && baudrate < 230400) { + /* get the divisor */ + custom = (__u16)(230400L / baudrate); + + /* Check for round off */ + round1 = (__u16)(2304000L / baudrate); + round = (__u16)(round1 - (custom * 10)); + if (round > 4) + custom++; + *divisor = custom; + + dbg("Baud %d = %d",baudrate, custom); + return 0; + } + + dbg("Baud calculation Failed..."); + return -EINVAL; +} + +/* + * send_cmd_write_baud_rate + * this function sends the proper command to change the baud rate of the + * specified port. + */ +static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, + int baudrate) +{ + struct usb_serial_port *port; + struct usb_serial *serial; + int divisor; + int status; + unsigned char data; + unsigned char number; + + if (mos7720_port == NULL) + return -1; + + port = mos7720_port->port; + serial = port->serial; + + dbg("%s: Entering ..........", __FUNCTION__); + + number = port->number - port->serial->minor; + dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate); + + /* Calculate the Divisor */ + status = calc_baud_rate_divisor(baudrate, &divisor); + if (status) { + err("%s - bad baud rate", __FUNCTION__); + return status; + } + + /* Enable access to divisor latch */ + data = mos7720_port->shadowLCR | UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); + + /* Write the divisor */ + data = ((unsigned char)(divisor & 0xff)); + send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); + + data = ((unsigned char)((divisor & 0xff00) >> 8)); + send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); + + /* Disable access to divisor latch */ + data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); + + return status; +} + +/* + * change_port_settings + * This routine is called to set the UART on the device to match + * the specified new settings. + */ +static void change_port_settings(struct moschip_port *mos7720_port, + struct termios *old_termios) +{ + struct usb_serial_port *port; + struct usb_serial *serial; + struct tty_struct *tty; + int baud; + unsigned cflag; + unsigned iflag; + __u8 mask = 0xff; + __u8 lData; + __u8 lParity; + __u8 lStop; + int status; + int port_number; + char data; + + if (mos7720_port == NULL) + return ; + + port = mos7720_port->port; + serial = port->serial; + port_number = port->number - port->serial->minor; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + tty = mos7720_port->port->tty; + + if ((!tty) || (!tty->termios)) { + dbg("%s - no tty structures", __FUNCTION__); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + lData = UART_LCR_WLEN8; + lStop = 0x00; /* 1 stop bit */ + lParity = 0x00; /* No parity */ + + cflag = tty->termios->c_cflag; + iflag = tty->termios->c_iflag; + + /* Change the number of bits */ + switch (cflag & CSIZE) { + case CS5: + lData = UART_LCR_WLEN5; + mask = 0x1f; + break; + + case CS6: + lData = UART_LCR_WLEN6; + mask = 0x3f; + break; + + case CS7: + lData = UART_LCR_WLEN7; + mask = 0x7f; + break; + default: + case CS8: + lData = UART_LCR_WLEN8; + break; + } + + /* Change the Parity bit */ + if (cflag & PARENB) { + if (cflag & PARODD) { + lParity = UART_LCR_PARITY; + dbg("%s - parity = odd", __FUNCTION__); + } else { + lParity = (UART_LCR_EPAR | UART_LCR_PARITY); + dbg("%s - parity = even", __FUNCTION__); + } + + } else { + dbg("%s - parity = none", __FUNCTION__); + } + + if (cflag & CMSPAR) + lParity = lParity | 0x20; + + /* Change the Stop bit */ + if (cflag & CSTOPB) { + lStop = UART_LCR_STOP; + dbg("%s - stop bits = 2", __FUNCTION__); + } else { + lStop = 0x00; + dbg("%s - stop bits = 1", __FUNCTION__); + } + +#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ +#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ +#define LCR_PAR_MASK 0x38 /* Mask for parity field */ + + /* Update the LCR with the correct value */ + mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); + mos7720_port->shadowLCR |= (lData | lParity | lStop); + + + /* Disable Interrupts */ + data = 0x00; + send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + + data = 0xcf; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + + /* Send the updated LCR value to the mos7720 */ + data = mos7720_port->shadowLCR; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data); + + data = 0x00b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x00b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + /* set up the MCR register and send it to the mos7720 */ + mos7720_port->shadowMCR = UART_MCR_OUT2; + if (cflag & CBAUD) + mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); + + if (cflag & CRTSCTS) { + mos7720_port->shadowMCR |= (UART_MCR_XONANY); + + /* To set hardware flow control to the specified * + * serial port, in SP1/2_CONTROL_REG */ + if (port->number) { + data = 0x001; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, + 0x08, &data); + } else { + data = 0x002; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, + 0x08, &data); + } + } else { + mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); + } + + data = mos7720_port->shadowMCR; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data); + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + if (!baud) { + /* pick a default, any default... */ + dbg("Picked default baud..."); + baud = 9600; + } + + if (baud >= 230400) { + set_higher_rates(mos7720_port, baud); + /* Enable Interrupts */ + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + return; + } + + dbg("%s - baud rate = %d", __FUNCTION__, baud); + status = send_cmd_write_baud_rate(mos7720_port, baud); + + /* Enable Interrupts */ + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + + if (port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = serial->dev; + + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } + return; +} + +/* + * mos7720_set_termios + * this function is called by the tty driver when it wants to change the + * termios structure. + */ +static void mos7720_set_termios(struct usb_serial_port *port, + struct termios *old_termios) +{ + int status; + unsigned int cflag; + struct usb_serial *serial; + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + tty = port->tty; + + if (!port->tty || !port->tty->termios) { + dbg("%s - no tty or termios", __FUNCTION__); + return; + } + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + dbg("%s\n","setting termios - ASPIRE"); + + cflag = tty->termios->c_cflag; + + if (!cflag) { + printk("%s %s\n",__FUNCTION__,"cflag is NULL"); + return; + } + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("Nothing to change"); + return; + } + } + + dbg("%s - clfag %08x iflag %08x", __FUNCTION__, + tty->termios->c_cflag, + RELEVANT_IFLAG(tty->termios->c_iflag)); + + if (old_termios) + dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, + RELEVANT_IFLAG(old_termios->c_iflag)); + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* change the port settings to the new ones specified */ + change_port_settings(mos7720_port, old_termios); + + if(!port->read_urb) { + dbg("%s","URB KILLED !!!!!\n"); + return; + } + + if(port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = serial->dev; + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } + return; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + int count; + unsigned int result = 0; + + count = mos7720_chars_in_buffer(mos7720_port->port); + if (count == 0) { + dbg("%s -- Empty", __FUNCTION__); + result = TIOCSER_TEMT; + } + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +/* + * get_number_bytes_avail - get number of bytes available + * + * Purpose: Let user call ioctl to get the count of number of bytes available. + */ +static int get_number_bytes_avail(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + struct tty_struct *tty = mos7720_port->port->tty; + + if (!tty) + return -ENOIOCTLCMD; + + result = tty->read_cnt; + + dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + + return -ENOIOCTLCMD; +} + +static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, + unsigned int __user *value) +{ + unsigned int mcr ; + unsigned int arg; + unsigned char data; + + struct usb_serial_port *port; + + if (mos7720_port == NULL) + return -1; + + port = (struct usb_serial_port*)mos7720_port->port; + mcr = mos7720_port->shadowMCR; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + mcr |= UART_MCR_RTS; + if (arg & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + mcr &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + mcr &= ~UART_MCR_RTS; + if (arg & TIOCM_LOOP) + mcr &= ~UART_MCR_LOOP; + break; + + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); + mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); + break; + } + + mos7720_port->shadowMCR = mcr; + + data = mos7720_port->shadowMCR; + send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, UART_MCR, &data); + + return 0; +} + +static int get_modem_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + unsigned int msr = mos7720_port->shadowMSR; + unsigned int mcr = mos7720_port->shadowMCR; + + result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ + | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ + | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + + + dbg("%s -- %x", __FUNCTION__, result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int get_serial_info(struct moschip_port *mos7720_port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + tmp.type = PORT_16550A; + tmp.line = mos7720_port->port->serial->minor; + tmp.port = mos7720_port->port->number; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int mos7720_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct moschip_port *mos7720_port; + struct async_icount cnow; + struct async_icount cprev; + struct serial_icounter_struct icount; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return -ENODEV; + + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); + + switch (cmd) { + case TIOCINQ: + /* return number of bytes available */ + dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); + return get_number_bytes_avail(mos7720_port, + (unsigned int __user *)arg); + break; + + case TIOCSERGETLSR: + dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); + return get_lsr_info(mos7720_port, (unsigned int __user *)arg); + return 0; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, + port->number); + return set_modem_info(mos7720_port, cmd, + (unsigned int __user *)arg); + + case TIOCMGET: + dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); + return get_modem_info(mos7720_port, + (unsigned int __user *)arg); + + case TIOCGSERIAL: + dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); + return get_serial_info(mos7720_port, + (struct serial_struct __user *)arg); + + case TIOCSSERIAL: + dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); + break; + + case TIOCMIWAIT: + dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); + cprev = mos7720_port->icount; + while (1) { + if (signal_pending(current)) + return -ERESTARTSYS; + cnow = mos7720_port->icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + break; + + case TIOCGICOUNT: + cnow = mos7720_port->icount; + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, + port->number, icount.rx, icount.tx ); + if (copy_to_user((void __user *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + } + + return -ENOIOCTLCMD; +} + +static int mos7720_startup(struct usb_serial *serial) +{ + struct moschip_serial *mos7720_serial; + struct moschip_port *mos7720_port; + struct usb_device *dev; + int i; + char data; + + dbg("%s: Entering ..........", __FUNCTION__); + + if (!serial) { + dbg("Invalid Handler"); + return -ENODEV; + } + + dev = serial->dev; + + /* create our private serial structure */ + mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL); + if (mos7720_serial == NULL) { + err("%s - Out of memory", __FUNCTION__); + return -ENOMEM; + } + + usb_set_serial_data(serial, mos7720_serial); + + /* we set up the pointers to the endpoints in the mos7720_open * + * function, as the structures aren't created yet. */ + + /* set up port private structures */ + for (i = 0; i < serial->num_ports; ++i) { + mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); + if (mos7720_port == NULL) { + err("%s - Out of memory", __FUNCTION__); + usb_set_serial_data(serial, NULL); + kfree(mos7720_serial); + return -ENOMEM; + } + + /* Initialize all port interrupt end point to port 0 int + * endpoint. Our device has only one interrupt endpoint + * comman to all ports */ + serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; + + mos7720_port->port = serial->port[i]; + usb_set_serial_port_data(serial->port[i], mos7720_port); + + dbg("port number is %d", serial->port[i]->number); + dbg("serial number is %d", serial->minor); + } + + + /* setting configuration feature to one */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ); + + send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1 + dbg("LSR:%x",data); + + send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2 + dbg("LSR:%x",data); + + return 0; +} + +static void mos7720_shutdown(struct usb_serial *serial) +{ + int i; + + /* free private structure allocated for serial port */ + for (i=0; i < serial->num_ports; ++i) { + kfree(usb_get_serial_port_data(serial->port[i])); + usb_set_serial_port_data(serial->port[i], NULL); + } + + /* free private structure allocated for serial device */ + kfree(usb_get_serial_data(serial)); + usb_set_serial_data(serial, NULL); +} + +static struct usb_serial_driver moschip7720_2port_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "moschip7720", + }, + .description = "Moschip 2 port adapter", + .id_table = moschip_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 2, + .num_bulk_out = 2, + .num_ports = 2, + .open = mos7720_open, + .close = mos7720_close, + .throttle = mos7720_throttle, + .unthrottle = mos7720_unthrottle, + .attach = mos7720_startup, + .shutdown = mos7720_shutdown, + .ioctl = mos7720_ioctl, + .set_termios = mos7720_set_termios, + .write = mos7720_write, + .write_room = mos7720_write_room, + .chars_in_buffer = mos7720_chars_in_buffer, + .break_ctl = mos7720_break, + .read_bulk_callback = mos7720_bulk_in_callback, +}; + +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, +}; + +static int __init moschip7720_init(void) +{ + int retval; + + dbg("%s: Entering ..........", __FUNCTION__); + + /* Register with the usb serial */ + retval = usb_serial_register(&moschip7720_2port_driver); + if (retval) + goto failed_port_device_register; + + info(DRIVER_DESC " " DRIVER_VERSION); + + /* Register with the usb */ + retval = usb_register(&usb_driver); + if (retval) + goto failed_usb_register; + + return 0; + +failed_usb_register: + usb_serial_deregister(&moschip7720_2port_driver); + +failed_port_device_register: + return retval; +} + +static void __exit moschip7720_exit(void) +{ + usb_deregister(&usb_driver); + usb_serial_deregister(&moschip7720_2port_driver); +} + +module_init(moschip7720_init); +module_exit(moschip7720_exit); + +/* Module information */ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); -- GitLab From a65dc301c7448a9a8d24bf1cbfe292541d1fa390 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Fri, 6 Oct 2006 00:09:29 +0200 Subject: [PATCH 1361/1619] USB: fix dereference in drivers/usb/misc/adutux.c in two of the error cases, dev is still NULL, and we dereference it. Spotted by coverity (cid#1428, 1429) Signed-off-by: Eric Sesterhenn Cc: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index aecd633fe9f..af2934e016a 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -370,7 +370,8 @@ static int adu_release(struct inode *inode, struct file *file) retval = adu_release_internal(dev); exit: - up(&dev->sem); + if (dev) + up(&dev->sem); dbg(2," %s : leave, return value %d", __FUNCTION__, retval); return retval; } -- GitLab From 1ff15e8efc1703eaae1eeec6fc09db6af1e4049f Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Sun, 8 Oct 2006 22:56:40 -0700 Subject: [PATCH 1362/1619] USB: Mitsumi USB FDD 061M: UNUSUAL_DEV multilun fix From: Tobias Lorenz Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 0a846e4a101..0093d9fd023 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE), -UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, +/* modified by Tobias Lorenz */ +UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200, "Mitsumi", "USB FDD", US_SC_DEVICE, US_PR_DEVICE, NULL, -- GitLab From c19ecd654209725444d1f47a4422e6f48846b53c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 9 Oct 2006 01:16:24 +0200 Subject: [PATCH 1363/1619] USB: ftdi-elan.c: remove dead code The Coverity checker spotted this obviously dead code. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 37d1f4e90d5..9b591b8b936 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -513,8 +513,6 @@ static void ftdi_elan_respond_work(void *data) ftdi->disconnected += 1; } else if (retval == -ENODEV) { ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; } else if (retval == -EILSEQ) { ftdi->disconnected += 1; } else { -- GitLab From ad18027f4909c8fc107056460c97dbedb6635128 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 9 Oct 2006 01:16:32 +0200 Subject: [PATCH 1364/1619] USB: mos7840.c: fix a check-after-dereference This patch fixes an obvious check-after-dereference spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 021be39fe16..5b71962d035 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, } mos7840_port = mos7840_get_port_private(port); - tty = mos7840_port->port->tty; if (mos7840_port == NULL) return -1; + tty = mos7840_port->port->tty; + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { -- GitLab From 3ccf25ce185d4798e66a91812a7622f7fe6987df Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 13 Oct 2006 09:59:17 -0400 Subject: [PATCH 1365/1619] USB: unusual_devs entry for Nokia 6234 This patch (as803) adds an unusual_devs entry for the Nokia 6234 mobile phone. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 0093d9fd023..802f3a35c51 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -190,6 +190,13 @@ UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Reported by Alex Corcoles */ +UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, + "Nokia", + "6234", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Olaf Hering from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", -- GitLab From 521b600b58376b7c85a7c615ee32fae185c20b16 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 10 Oct 2006 14:42:46 -0700 Subject: [PATCH 1366/1619] USB: fix usbatm tiny race ia64: drivers/usb/atm/usbatm.c: In function `usbatm_do_heavy_init': drivers/usb/atm/usbatm.c:1004: warning: implicit declaration of function `get_current' drivers/usb/atm/usbatm.c:1004: error: invalid type argument of `->' Signed-off-by: Duncan Sands Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index ab091fa4c86..ec63b0ee074 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1001,7 +1001,7 @@ static int usbatm_do_heavy_init(void *arg) daemonize(instance->driver->driver_name); allow_signal(SIGTERM); - instance->thread_pid = get_current()->pid; + instance->thread_pid = current->pid; complete(&instance->thread_started); -- GitLab From c0fc0ee06f6c9ab37f53afc62b0d94a700fa7a97 Mon Sep 17 00:00:00 2001 From: Jan Mate Date: Tue, 10 Oct 2006 14:42:47 -0700 Subject: [PATCH 1367/1619] USB Storage: unusual_devs.h entry for Sony Ericsson P990i USB Storage: this patch adds support for Sony Ericsson P990i Signed-off-by: Jan Mate Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 802f3a35c51..37ed8e0f2dc 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1306,6 +1306,13 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Jan Mate */ +UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, + "Sony Ericsson", + "P990i", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Reported by Kevin Cernekee * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. -- GitLab From 0e185b7922ac81516c5c4653dcf6aacbf6341e73 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Tue, 10 Oct 2006 14:42:50 -0700 Subject: [PATCH 1368/1619] USB: Memory leak in drivers/usb/serial/airprime.c the commit http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=5dda171202f94127e49c12daf780cdae1b4e668b added a memory leak. In case we cant allocate an urb, we dont free the buffer and leak it. Coverity id #1438 Signed-off-by: Eric Sesterhenn Acked-by: Andy Gay Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 392a5129af6..ba93c72cdba 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -134,6 +134,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) } urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { + kfree(buffer); dev_err(&port->dev, "%s - no more urbs?\n", __FUNCTION__); result = -ENOMEM; -- GitLab From 4550718f6c75c9abe8b987fa4c625fd041aa95a2 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Tue, 10 Oct 2006 14:42:51 -0700 Subject: [PATCH 1369/1619] USB: input: extract() and implement() are bit field manipulation routines extract() and implement() have brain damaged attempts to handle 32-bit wide "fields". The problem is the index math in the original code didn't clear all the relevant bits. (offset >> 5) only compensated for 32-bit index. We need (offset >> 6) if we want to use 64-bit loads. But it was also wrong in that it tried to use quasi-aligned loads. Ie "report" was only incremented in multiples of 4 bytes and then the offset was masked off for values greater than 4 bytes. The right way is to pretend "report" points at a byte array. And offset is then only minor adjustment for < 8 bits of offset. "n" (field width) can then be as big as 24 (assuming 32-bit loads) since "offset" will never be bigger than 7. If someone needs either function to handle more than 24-bits, please document why - point at a specification or specific USB hid device - in comments in the code. extract/implement() are also an eyesore to read. Please banish whoever wrote it to read CodingStyle 3 times in a row to a classroom full of 1st graders armed with rubberbands. Or just flame them. Whatever. Globbing all the code together on two lines does NOT make it faster and is Just Wrong. I've tested this patch on j6000 (dual 750Mhz PA-RISC, 32-bit 2.6.12-rc5). Kyle McMartin tested on c3000 (up 400Mhz PA-RISC, same kernel). "p2-mate" (Peter De Schrijver?) tested on sb1250 (dual core Mips, broadcom "swarm" eval board). Signed-off-by: Grant Grundler Signed-off-by: Matthew Wilcox Cc: Vojtech Pavlik Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a6738a83ff5..feabda73a6f 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -750,21 +750,31 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) } /* - * Extract/implement a data field from/to a report. + * Extract/implement a data field from/to a little endian report (bit array). */ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { - report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1); + u32 x; + + report += offset >> 3; /* adjust byte index */ + offset &= 8 - 1; + x = get_unaligned((u32 *) report); + x = le32_to_cpu(x); + x = (x >> offset) & ((1 << n) - 1); + return x; } static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) { - report += (offset >> 5) << 2; offset &= 31; - put_unaligned((get_unaligned((__le64*)report) - & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) - | cpu_to_le64((__u64)value << offset), (__le64*)report); + u32 x; + + report += offset >> 3; + offset &= 8 - 1; + x = get_unaligned((u32 *)report); + x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset)); + x |= cpu_to_le32(value << offset); + put_unaligned(x,(u32 *)report); } /* -- GitLab From deb8ee43a23d48116cb23eb8dd1de2348efb1e80 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 10 Oct 2006 14:42:48 -0700 Subject: [PATCH 1370/1619] USB: xpad: dance pad support Adds support for dance pads to the xpad driver. Dance pads require the d-pad to be mapped to four buttons instead of two axes, so that combinations of up/down and left/right can be hit simultaneously. Known dance pads are detected, and there is a module parameter added to default unknown xpad devices to map the d-pad to buttons if this is desired. (dpad_to_buttons). Minor modifications were made to port the changes in the original patch to a newer kernel version. This patch was originally from Dominic Cerquetti originally written for kernel 2.6.11.4, with minor modifications (API changes for USB, spelling fixes to the documentation added in the original patch) made to apply to the current kernel. I have modified Dominic's original patch per some suggestions from Dmitry Torokhov. (There was nothing in the patch format description about multiple From: lines, so I haven't added myself.) [akpm@osdl.org: cleanups] Signed-off-by: Adam Buchbinder Acked-by: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- Documentation/input/xpad.txt | 115 +++++++++++++++++++++++------ drivers/usb/input/xpad.c | 139 ++++++++++++++++++++++++----------- 2 files changed, 186 insertions(+), 68 deletions(-) diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt index b9111a703ce..5427bdf225e 100644 --- a/Documentation/input/xpad.txt +++ b/Documentation/input/xpad.txt @@ -3,20 +3,37 @@ xpad - Linux USB driver for X-Box gamepads This is the very first release of a driver for X-Box gamepads. Basically, this was hacked away in just a few hours, so don't expect miracles. + In particular, there is currently NO support for the rumble pack. You won't find many ff-aware linux applications anyway. -0. Status ---------- +0. Notes +-------- + +Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.) -For now, this driver has only been tested on just one Linux-Box. -This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600. +The number of buttons/axes reported varies based on 3 things: +- if you are using a known controller +- if you are using a known dance pad +- if using an unknown device (one not listed below), what you set in the + module configuration for "Map D-PAD to buttons rather than axes for unknown + pads" (module option dpad_to_buttons) -The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports -8 axes and 10 buttons. +If you set dpad_to_buttons to 0 and you are using an unknown device (one +not listed below), the driver will map the directional pad to axes (X/Y), +if you said N it will map the d-pad to buttons, which is needed for dance +style games to function correctly. The default is Y. + +dpad_to_buttons has no effect for known pads. + +0.1 Normal Controllers +---------------------- +With a normal controller, the directional pad is mapped to its own X/Y axes. +The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) will report 8 +axes and 10 buttons. -Alls 8 axes work, though they all have the same range (-32768..32767) +All 8 axes work, though they all have the same range (-32768..32767) and the zero-setting is not correct for the triggers (I don't know if that is some limitation of jstest, since the input device setup should be fine. I didn't have a look at jstest itself yet). @@ -30,16 +47,50 @@ in game functionality were OK. However, I find it rather difficult to play first person shooters with a pad. Your mileage may vary. +0.2 Xbox Dance Pads +------------------- +When using a known dance pad, jstest will report 6 axes and 14 buttons. + +For dance style pads (like the redoctane pad) several changes +have been made. The old driver would map the d-pad to axes, resulting +in the driver being unable to report when the user was pressing both +left+right or up+down, making DDR style games unplayable. + +Known dance pads automatically map the d-pad to buttons and will work +correctly out of the box. + +If your dance pad is recognized by the driver but is using axes instead +of buttons, see section 0.3 - Unknown Controllers + +I've tested this with Stepmania, and it works quite well. + + +0.3 Unkown Controllers +---------------------- +If you have an unkown xbox controller, it should work just fine with +the default settings. + +HOWEVER if you have an unknown dance pad not listed below, it will not +work UNLESS you set "dpad_to_buttons" to 1 in the module configuration. + +PLEASE if you have an unkown controller, email Dom with +a dump from /proc/bus/usb and a description of the pad (manufacturer, country, +whether it is a dance pad or normal controller) so that we can add your pad +to the list of supported devices, ensuring that it will work out of the +box in the future. + + 1. USB adapter -------------- Before you can actually use the driver, you need to get yourself an -adapter cable to connect the X-Box controller to your Linux-Box. +adapter cable to connect the X-Box controller to your Linux-Box. You +can buy these online fairly cheap, or build your own. -Such a cable is pretty easy to build. The Controller itself is a USB compound -device (a hub with three ports for two expansion slots and the controller -device) with the only difference in a nonstandard connector (5 pins vs. 4 on -standard USB connector). +Such a cable is pretty easy to build. The Controller itself is a USB +compound device (a hub with three ports for two expansion slots and +the controller device) with the only difference in a nonstandard connector +(5 pins vs. 4 on standard USB connector). You just need to solder a USB connector onto the cable and keep the yellow wire unconnected. The other pins have the same order on both @@ -51,36 +102,36 @@ original one. You can buy an extension cable and cut that instead. That way, you can still use the controller with your X-Box, if you have one ;) -2. driver installation +2. Driver Installation ---------------------- Once you have the adapter cable and the controller is connected, you need to load your USB subsystem and should cat /proc/bus/usb/devices. There should be an entry like the one at the end [4]. -Currently (as of version 0.0.4), the following three devices are included: +Currently (as of version 0.0.6), the following devices are included: original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 + smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289 original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285 InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a + RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809 -If you have another controller that is not listed above and is not recognized -by the driver, please drop me a line with the appropriate info (that is, include -the name, vendor and product ID, as well as the country where you bought it; -sending the whole dump out of /proc/bus/usb/devices along would be even better). +The driver should work with xbox pads not listed above as well, however +you will need to do something extra for dance pads to work. -In theory, the driver should work with other controllers than mine -(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this -for I only have this one controller. +If you have a controller not listed above, see 0.3 - Unknown Controllers If you compiled and installed the driver, test the functionality: > modprobe xpad > modprobe joydev > jstest /dev/js0 -There should be a single line showing 18 inputs (8 axes, 10 buttons), and -it's values should change if you move the sticks and push the buttons. +If you're using a normal controller, there should be a single line showing +18 inputs (8 axes, 10 buttons), and its values should change if you move +the sticks and push the buttons. If you're using a dance pad, it should +show 20 inputs (6 axes, 14 buttons). -It works? Voila, your done ;) +It works? Voila, you're done ;) 3. Thanks @@ -111,6 +162,22 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none) E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms +5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US): + +T: Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12 MxCh= 0 +D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0c12 ProdID=8809 Rev= 0.01 +S: Product=XBOX DDR +C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad +E: Ad=82(I) Atr=03(Int.) MxPS= 32 Ivl=4ms +E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl=4ms + -- Marko Friedemann 2002-07-16 + - original doc + +Dominic Cerquetti +2005-03-19 + - added stuff for dance pads, new d-pad->axes mappings diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index cebb6c463bf..6a12a943b93 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -1,8 +1,9 @@ /* - * X-Box gamepad - v0.0.5 + * X-Box gamepad - v0.0.6 * * Copyright (c) 2002 Marko Friedemann - * + * 2005 Dominic Cerquetti + * 2006 Adam Buchbinder * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,9 +31,10 @@ * - Greg Kroah-Hartman - usb-skeleton driver * * TODO: - * - fine tune axes + * - fine tune axes (especially trigger axes) * - fix "analog" buttons (reported as digital now) * - get rumble working + * - need USB IDs for other dance pads * * History: * @@ -57,25 +59,40 @@ #include #include #include +#include #include +#include #include #include -#define DRIVER_VERSION "v0.0.5" +#define DRIVER_VERSION "v0.0.6" #define DRIVER_AUTHOR "Marko Friedemann " #define DRIVER_DESC "X-Box pad driver" #define XPAD_PKT_LEN 32 +/* xbox d-pads should map to buttons, as is required for DDR pads + but we map them to axes when possible to simplify things */ +#define MAP_DPAD_TO_BUTTONS 0 +#define MAP_DPAD_TO_AXES 1 +#define MAP_DPAD_UNKNOWN -1 + +static int dpad_to_buttons; +module_param(dpad_to_buttons, bool, S_IRUGO); +MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); + static const struct xpad_device { u16 idVendor; u16 idProduct; char *name; + u8 dpad_mapping; } xpad_device[] = { - { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, - { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, - { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, - { 0x0000, 0x0000, "X-Box pad" } + { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES }, + { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS }, + { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN } }; static const signed short xpad_btn[] = { @@ -84,11 +101,23 @@ static const signed short xpad_btn[] = { -1 /* terminating entry */ }; +/* only used if MAP_DPAD_TO_BUTTONS */ +static const signed short xpad_btn_pad[] = { + BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ + BTN_0, BTN_1, /* d-pad up, down (XXX names??) */ + -1 /* terminating entry */ +}; + static const signed short xpad_abs[] = { ABS_X, ABS_Y, /* left stick */ ABS_RX, ABS_RY, /* right stick */ ABS_Z, ABS_RZ, /* triggers left/right */ - ABS_HAT0X, ABS_HAT0Y, /* digital pad */ + -1 /* terminating entry */ +}; + +/* only used if MAP_DPAD_TO_AXES */ +static const signed short xpad_abs_pad[] = { + ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */ -1 /* terminating entry */ }; @@ -100,14 +129,16 @@ static struct usb_device_id xpad_table [] = { MODULE_DEVICE_TABLE (usb, xpad_table); struct usb_xpad { - struct input_dev *dev; /* input device interface */ - struct usb_device *udev; /* usb device */ + struct input_dev *dev; /* input device interface */ + struct usb_device *udev; /* usb device */ - struct urb *irq_in; /* urb for interrupt in report */ - unsigned char *idata; /* input data */ + struct urb *irq_in; /* urb for interrupt in report */ + unsigned char *idata; /* input data */ dma_addr_t idata_dma; - char phys[65]; /* physical device path */ + char phys[65]; /* physical device path */ + + int dpad_mapping; /* map d-pad to buttons or to axes */ }; /* @@ -137,14 +168,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_abs(dev, ABS_RZ, data[11]); /* digital pad */ - input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { + input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { + input_report_key(dev, BTN_LEFT, data[2] & 0x04); + input_report_key(dev, BTN_RIGHT, data[2] & 0x08); + input_report_key(dev, BTN_0, data[2] & 0x01); // up + input_report_key(dev, BTN_1, data[2] & 0x02); // down + } /* start/back buttons and stick press left/right */ - input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); - input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); - input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); - input_report_key(dev, BTN_THUMBR, data[2] >> 7); + input_report_key(dev, BTN_START, data[2] & 0x10); + input_report_key(dev, BTN_BACK, data[2] & 0x20); + input_report_key(dev, BTN_THUMBL, data[2] & 0x40); + input_report_key(dev, BTN_THUMBR, data[2] & 0x80); /* "analog" buttons A, B, X, Y */ input_report_key(dev, BTN_A, data[4]); @@ -206,6 +244,28 @@ static void xpad_close (struct input_dev *dev) usb_kill_urb(xpad->irq_in); } +static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) +{ + set_bit(abs, input_dev->absbit); + + switch (abs) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); + break; + case ABS_Z: + case ABS_RZ: /* the triggers */ + input_set_abs_params(input_dev, abs, 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */ + input_set_abs_params(input_dev, abs, -1, 1, 0, 0); + break; + } +} + static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev (intf); @@ -235,6 +295,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail2; xpad->udev = udev; + xpad->dpad_mapping = xpad_device[i].dpad_mapping; + if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) + xpad->dpad_mapping = dpad_to_buttons; xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -249,32 +312,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + /* set up buttons */ for (i = 0; xpad_btn[i] >= 0; i++) set_bit(xpad_btn[i], input_dev->keybit); + if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) + for (i = 0; xpad_btn_pad[i] >= 0; i++) + set_bit(xpad_btn_pad[i], input_dev->keybit); - for (i = 0; xpad_abs[i] >= 0; i++) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, -32768, 32767, 16, 128); - break; - case ABS_Z: - case ABS_RZ: /* the triggers */ - input_set_abs_params(input_dev, t, 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, -1, 1, 0, 0); - break; - } - } + /* set up axes */ + for (i = 0; xpad_abs[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs[i]); + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) + for (i = 0; xpad_abs_pad[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs_pad[i]); ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(xpad->irq_in, udev, @@ -305,7 +355,8 @@ static void xpad_disconnect(struct usb_interface *intf) usb_kill_urb(xpad->irq_in); input_unregister_device(xpad->dev); usb_free_urb(xpad->irq_in); - usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); + usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, + xpad->idata, xpad->idata_dma); kfree(xpad); } } -- GitLab From 9ab99c8c513313c1c5931bdbd27dcc4bc7a3b7cd Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Wed, 11 Oct 2006 14:20:56 -0700 Subject: [PATCH 1371/1619] UEAGLE: fix ueagle-atm Oops The array of attribute passed to sysfs_create_group() must be NULL-terminated. The sysfs entries are created before the start of the modem state machine to avoid to stop it in case of errors in sysfs creation. Also {destroy,create}_fs_entries are removed as they do nothing. Signed-off-by: Laurent Riffard Signed-off-by: Matthieu CASTET Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 57052984223..f6b9f7e1f71 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1648,16 +1648,12 @@ static struct attribute *attrs[] = { &dev_attr_stat_usunc.attr, &dev_attr_stat_dsunc.attr, &dev_attr_stat_firmid.attr, + NULL, }; static struct attribute_group attr_grp = { .attrs = attrs, }; -static int create_fs_entries(struct usb_interface *intf) -{ - return sysfs_create_group(&intf->dev.kobj, &attr_grp); -} - static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id) { @@ -1717,31 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, } } + ret = sysfs_create_group(&intf->dev.kobj, &attr_grp); + if (ret < 0) + goto error; + ret = uea_boot(sc); - if (ret < 0) { - kfree(sc); - return ret; - } + if (ret < 0) + goto error; - ret = create_fs_entries(intf); - if (ret) { - uea_stop(sc); - kfree(sc); - return ret; - } return 0; -} - -static void destroy_fs_entries(struct usb_interface *intf) -{ - sysfs_remove_group(&intf->dev.kobj, &attr_grp); +error: + kfree(sc); + return ret; } static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) { struct uea_softc *sc = usbatm->driver_data; - destroy_fs_entries(intf); + sysfs_remove_group(&intf->dev.kobj, &attr_grp); uea_stop(sc); kfree(sc); } -- GitLab From 5dfb5f1d060a6f7dfddb78dc59f9e4d299088cc1 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Wed, 11 Oct 2006 23:40:22 +0200 Subject: [PATCH 1372/1619] usbtouchscreen: fix data reading for ITM touchscreens ITM devices seem to report only garbage when not touched. update usbtouchscreen to do data reading like itmtouch. also fix wrong mask on pressure bits. Signed-off-by: Daniel Ritz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/usbtouchscreen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index f26c1cd1129..2902742895a 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -256,10 +256,10 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr { *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); - *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F); + *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); *touch = ~pkt[7] & 0x20; - return 1; + return *touch; } #endif -- GitLab From b3899dacafb10347b1b7a9f589b6c70cf8f08a3e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 11 Oct 2006 21:50:24 -0400 Subject: [PATCH 1373/1619] USB/gadget/net2280: handle sysfs errors Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2280.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d954daa8e9e..7cfe0e5cf67 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2044,8 +2044,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - device_create_file (&dev->pdev->dev, &dev_attr_function); - device_create_file (&dev->pdev->dev, &dev_attr_queues); + retval = device_create_file (&dev->pdev->dev, &dev_attr_function); + if (retval) goto err_unbind; + retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); + if (retval) goto err_func; /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -2060,6 +2062,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) /* pci writes may still be posted */ return 0; + +err_func: + device_remove_file (&dev->pdev->dev, &dev_attr_function); +err_unbind: + driver->unbind (&dev->gadget); + dev->gadget.dev.driver = NULL; + dev->driver = NULL; + return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -2974,8 +2984,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) : "disabled"); the_controller = dev; - device_register (&dev->gadget.dev); - device_create_file (&pdev->dev, &dev_attr_registers); + retval = device_register (&dev->gadget.dev); + if (retval) goto done; + retval = device_create_file (&pdev->dev, &dev_attr_registers); + if (retval) goto done; return 0; -- GitLab From 61926b975d83aa6c0124b5b0ce40c08579e6cc98 Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Thu, 12 Oct 2006 22:09:56 +0100 Subject: [PATCH 1374/1619] USB-SERIAL:cp2101 Add new device ID This patch adds device ID 0xEA61. This is another factory default ID used by SILabs. Signed-off-by: Craig Shelley Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 486c7411b9a..bbf6532c26e 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; -- GitLab From 5c09d144ff94706c2a5df292329ad83a27380173 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 13 Oct 2006 15:57:58 -0700 Subject: [PATCH 1375/1619] USB: ftdi_sio whitespace fixes Whitespace fixups for drivers/usb/serial/ftdi_sio.c ... removing end-of-line whitespace, and space-before-tab. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 254 +++++++++++++++++----------------- 1 file changed, 127 insertions(+), 127 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d3dc1a15ec6..bd76b4c11fc 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,16 +1,16 @@ /* * USB FTDI SIO driver * - * Copyright (C) 1999 - 2001 - * Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2001 + * Greg Kroah-Hartman (greg@kroah.com) * Bill Ryder (bryder@sgi.com) * Copyright (C) 2002 * Kuba Ober (kuba@mareimbrium.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 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. * * See Documentation/usb/usb-serial.txt for more information on using this driver * @@ -32,7 +32,7 @@ * Changed full name of USB-UIRT device to avoid "/" character. * Added FTDI's alternate PID (0x6006) for FT232/245 devices. * Added PID for "ELV USB Module UO100" from Stefan Frings. - * + * * (21/Oct/2003) Ian Abbott * Renamed some VID/PID macros for Matrix Orbital and Perle Systems * devices. Removed Matrix Orbital and Perle Systems devices from the @@ -69,7 +69,7 @@ * does not incure any measurable overhead. This also relies on the fact * that we have proper reference counting logic for urbs. I nicked this * from Greg KH's Visor driver. - * + * * (23/Jun/2003) Ian Abbott * Reduced flip buffer pushes and corrected a data length test in * ftdi_read_bulk_callback. @@ -77,7 +77,7 @@ * * (21/Jun/2003) Erik Nygren * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. - * See . Only operates properly + * See . Only operates properly * at 100000 and RTS-CTS, so set custom divisor mode on startup. * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. * @@ -137,17 +137,17 @@ * (17/Feb/2003) Bill Ryder * Added write urb buffer pool on a per device basis * Added more checking for open file on callbacks (fixed OOPS) - * Added CrystalFontz 632 and 634 PIDs + * Added CrystalFontz 632 and 634 PIDs * (thanx to CrystalFontz for the sample devices - they flushed out * some driver bugs) * Minor debugging message changes * Added throttle, unthrottle and chars_in_buffer functions * Fixed FTDI_SIO (the original device) bug * Fixed some shutdown handling - * - * - * - * + * + * + * + * * (07/Jun/2002) Kuba Ober * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor * function. It was getting too complex. @@ -158,7 +158,7 @@ * * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch * Not tested by me but it doesn't break anything I use. - * + * * (04/Jan/2002) Kuba Ober * Implemented 38400 baudrate kludge, where it can be substituted with other * values. That's the only way to set custom baudrates. @@ -179,7 +179,7 @@ * (the previous version caused panics) * Removed port iteration code since the device only has one I/O port and it * was wrong anyway. - * + * * (31/May/2001) gkh * Switched from using spinlock to a semaphore, which fixes lots of problems. * @@ -188,16 +188,16 @@ * Cleaned up comments for 8U232 * Added parity, framing and overrun error handling * Added receive break handling. - * + * * (04/08/2001) gb * Identify version on module load. - * + * * (18/March/2001) Bill Ryder * (Not released) * Added send break handling. (requires kernel patch too) * Fixed 8U232AM hardware RTS/CTS etc status reporting. * Added flipbuf fix copied from generic device - * + * * (12/3/2000) Bill Ryder * Added support for 8U232AM device. * Moved PID and VIDs into header file only. @@ -211,14 +211,14 @@ * Cleaned up comments. Removed multiple PID/VID definitions. * Factorised cts/dtr code * Made use of __FUNCTION__ in dbg's - * + * * (11/01/2000) Adam J. Richter * usb_device_id table support - * + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. - * + * * (09/11/2000) gkh * Removed DEBUG #ifdefs with call to usb_serial_debug_data * @@ -226,11 +226,11 @@ * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. * - * (04/04/2000) Bill Ryder + * (04/04/2000) Bill Ryder * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are * handled elsewhere in the tty io driver chain). * - * (03/30/2000) Bill Ryder + * (03/30/2000) Bill Ryder * Implemented lots of ioctls * Fixed a race condition in write * Changed some dbg's to errs @@ -444,13 +444,13 @@ static struct usb_device_id id_table_combined [] = { /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ - { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, - { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, @@ -522,7 +522,7 @@ static struct usb_driver ftdi_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; static const char *ftdi_chip_name[] = { @@ -548,13 +548,13 @@ struct ftdi_private { int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ __u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */ - int write_offset; /* This is the offset in the usb data block to write the serial data - + int write_offset; /* This is the offset in the usb data block to write the serial data - * it is different between devices */ int flags; /* some ASYNC_xxxx flags are supported */ unsigned long last_dtr_rts; /* saved modem control outputs */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - char prev_status, diff_status; /* Used for TIOCMIWAIT */ + 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; @@ -721,7 +721,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned urb_value |= FTDI_SIO_SET_RTS_HIGH; rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, urb_value, priv->interface, buf, 0, WDR_TIMEOUT); @@ -768,7 +768,7 @@ static int change_speed(struct usb_serial_port *port) if (priv->interface) { /* FT2232C */ urb_index = (__u16)((urb_index << 8) | priv->interface); } - + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_BAUDRATE_REQUEST, @@ -827,7 +827,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) /* 3. Convert baudrate to device-specific divisor */ - if (!baud) baud = 9600; + if (!baud) baud = 9600; switch(priv->chip_type) { case SIO: /* SIO chip */ switch(baud) { @@ -843,7 +843,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) case 115200: div_value = ftdi_sio_b115200; break; } /* baud */ if (div_value == 0) { - dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); + dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); div_value = ftdi_sio_b9600; div_okay = 0; } @@ -925,7 +925,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _ /* Make the changes - these are privileged changes! */ priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); + (new_serial.flags & ASYNC_FLAGS)); priv->custom_divisor = new_serial.custom_divisor; port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -950,7 +950,7 @@ check_and_exit: (old_priv.custom_divisor != priv->custom_divisor))) { change_speed(port); } - + return (0); } /* set_serial_info */ @@ -1022,18 +1022,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a struct usb_device *udev; unsigned short latency = 0; int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s",__FUNCTION__); - + rv = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), FTDI_SIO_GET_LATENCY_TIMER_REQUEST, FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, (char*) &latency, 1, WDR_TIMEOUT); - + if (rv < 0) { dev_err(dev, "Unable to read latency timer: %i", rv); return -EIO; @@ -1051,23 +1051,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute * char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s: setting latency timer = %i", __FUNCTION__, v); - + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - v, priv->interface, + v, priv->interface, buf, 0, WDR_TIMEOUT); - + if (rv < 0) { dev_err(dev, "Unable to write latency timer: %i", rv); return -EIO; } - + return count; } @@ -1082,23 +1082,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s: setting event char = %i", __FUNCTION__, v); - + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, - v, priv->interface, + v, priv->interface, buf, 0, WDR_TIMEOUT); - + if (rv < 0) { dbg("Unable to write event character: %i", rv); return -EIO; } - + return count; } @@ -1135,11 +1135,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial) struct ftdi_private *priv; struct usb_device *udev; - dbg("%s",__FUNCTION__); + dbg("%s",__FUNCTION__); priv = usb_get_serial_port_data(serial->port[0]); udev = serial->dev; - + /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&udev->dev, &dev_attr_event_char); @@ -1147,7 +1147,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial) device_remove_file(&udev->dev, &dev_attr_latency_timer); } } - + } /* @@ -1258,7 +1258,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) } /* ftdi_HE_TIRA1_setup */ -/* ftdi_shutdown is called from usbserial:usb_serial_disconnect +/* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * * usbserial:usb_serial_disconnect @@ -1269,16 +1269,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) static void ftdi_shutdown (struct usb_serial *serial) { /* ftdi_shutdown */ - + struct usb_serial_port *port = serial->port[0]; struct ftdi_private *priv = usb_get_serial_port_data(port); dbg("%s", __FUNCTION__); remove_sysfs_attrs(serial); - - /* all open ports are closed at this point - * (by usbserial.c:__serial_close, which calls ftdi_close) + + /* all open ports are closed at this point + * (by usbserial.c:__serial_close, which calls ftdi_close) */ if (priv) { @@ -1293,7 +1293,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned long flags; - + int result = 0; char buf[1]; /* Needed for the usb_control_msg I think */ @@ -1312,8 +1312,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, - FTDI_SIO_RESET_SIO, + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change @@ -1350,12 +1350,12 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) -/* +/* * usbserial:__serial_close only calls ftdi_close if the point is open * * This only gets called when it is the last close - * - * + * + * */ static void ftdi_close (struct usb_serial_port *port, struct file *filp) @@ -1368,14 +1368,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) if (c_cflag & HUPCL){ /* Disable flow control */ - if (usb_control_msg(port->serial->dev, + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); - } + } /* drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); @@ -1384,14 +1384,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) /* cancel any scheduled reading */ cancel_delayed_work(&priv->rx_work); flush_scheduled_work(); - + /* shutdown our bulk read */ if (port->read_urb) usb_kill_urb(port->read_urb); } /* ftdi_close */ - + /* The SIO requires the first byte to have: * B0 1 * B1 0 @@ -1423,7 +1423,7 @@ static int ftdi_write (struct usb_serial_port *port, return 0; } spin_unlock_irqrestore(&priv->tx_lock, flags); - + data_offset = priv->write_offset; dbg("data_offset set to %d",data_offset); @@ -1462,7 +1462,7 @@ static int ftdi_write (struct usb_serial_port *port, user_pktsz = todo; } /* Write the control byte at the front of the packet*/ - *first_byte = 1 | ((user_pktsz) << 2); + *first_byte = 1 | ((user_pktsz) << 2); /* Copy data for packet */ memcpy (first_byte + data_offset, current_position, user_pktsz); @@ -1479,7 +1479,7 @@ static int ftdi_write (struct usb_serial_port *port, usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); /* fill the buffer and send it */ - usb_fill_bulk_urb(urb, port->serial->dev, + usb_fill_bulk_urb(urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), buffer, transfer_size, ftdi_write_bulk_callback, port); @@ -1520,7 +1520,7 @@ static void ftdi_write_bulk_callback (struct urb *urb) kfree (urb->transfer_buffer); dbg("%s - port %d", __FUNCTION__, port->number); - + if (urb->status) { dbg("nonzero write bulk status received: %d", urb->status); return; @@ -1651,7 +1651,7 @@ static void ftdi_process_read (void *param) struct tty_struct *tty; struct ftdi_private *priv; char error_flag; - unsigned char *data; + unsigned char *data; int i; int result; @@ -1759,7 +1759,7 @@ static void ftdi_process_read (void *param) } if (length > 0) { for (i = 2; i < length+2; i++) { - /* Note that the error flag is duplicated for + /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ tty_insert_flip_char(tty, data[packet_offset+i], error_flag); @@ -1773,7 +1773,7 @@ static void ftdi_process_read (void *param) This doesn't work well since the application receives a never ending stream of bad data - even though new data hasn't been sent. Therefore I (bill) have taken this out. - However - this might make sense for framing errors and so on + However - this might make sense for framing errors and so on so I am leaving the code in for now. */ else { @@ -1827,7 +1827,7 @@ static void ftdi_process_read (void *param) /* if the port is closed stop trying to read */ if (port->open_count > 0){ /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ftdi_read_bulk_callback, port); @@ -1844,9 +1844,9 @@ static void ftdi_process_read (void *param) static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) { struct ftdi_private *priv = usb_get_serial_port_data(port); - __u16 urb_value = 0; + __u16 urb_value = 0; char buf[1]; - + /* break_state = -1 to turn on break, and 0 to turn off break */ /* see drivers/char/tty_io.c to see it used */ /* last_set_data_urb_value NEVER has the break bit set in it */ @@ -1854,20 +1854,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) if (break_state) { urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; } else { - urb_value = priv->last_set_data_urb_value; + urb_value = priv->last_set_data_urb_value; } - + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); - } + } dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value); - + } @@ -1883,12 +1883,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ struct ftdi_private *priv = usb_get_serial_port_data(port); __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ - + // Added for xon/xoff support unsigned int iflag = port->tty->termios->c_iflag; unsigned char vstop; unsigned char vstart; - + dbg("%s", __FUNCTION__); /* Force baud rate if this device requires it, unless it is set to B0. */ @@ -1906,20 +1906,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ cflag = port->tty->termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to + /* FIXME -For this cut I don't care if the line is really changing or + not - so just do the change regardless - should be able to compare old_termios and tty->termios */ - /* NOTE These routines can get interrupted by - ftdi_sio_read_bulk_callback - need to examine what this + /* NOTE These routines can get interrupted by + ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ - + /* Set number of data bits, parity, stop bits */ - + urb_value = 0; urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : FTDI_SIO_SET_DATA_STOP_BITS_1); - urb_value |= (cflag & PARENB ? - (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : + urb_value |= (cflag & PARENB ? + (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : FTDI_SIO_SET_DATA_PARITY_EVEN) : FTDI_SIO_SET_DATA_PARITY_NONE); if (cflag & CSIZE) { @@ -1936,25 +1936,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* This is needed by the break command since it uses the same command - but is * or'ed with this value */ priv->last_set_data_urb_value = urb_value; - + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, buf, 0, WDR_SHORT_TIMEOUT) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); - } + } /* Now do the baudrate */ if ((cflag & CBAUD) == B0 ) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); - } + } /* Drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { @@ -1972,16 +1972,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ if (cflag & CRTSCTS) { dbg("%s Setting to CRTSCTS flow control", __FUNCTION__); - if (usb_control_msg(dev, + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); - } - - } else { + } + + } else { /* * Xon/Xoff code * @@ -2011,16 +2011,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */ /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ dbg("%s Turning off hardware flow control", __FUNCTION__); - if (usb_control_msg(dev, + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); - } + } } - + } return; } /* ftdi_termios */ @@ -2036,11 +2036,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) switch (priv->chip_type) { case SIO: /* Request the status from the device */ - if ((ret = usb_control_msg(port->serial->dev, + if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, 0, buf, 1, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2052,11 +2052,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ - if ((ret = usb_control_msg(port->serial->dev, + if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2067,12 +2067,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) return -EFAULT; break; } - + return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; + priv->last_dtr_rts; } static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) @@ -2138,11 +2138,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne break; default: break; - + } - /* This is not necessarily an error - turns out the higher layers will do + /* This is not necessarily an error - turns out the higher layers will do * some ioctls itself (see comment above) */ dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd); @@ -2199,7 +2199,7 @@ static int __init ftdi_init (void) if (retval) goto failed_sio_register; retval = usb_register(&ftdi_driver); - if (retval) + if (retval) goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); -- GitLab From 033a3fb980b041c5b1c865d3e9dce9217d1dc94b Mon Sep 17 00:00:00 2001 From: Kevin Lloyd Date: Fri, 13 Oct 2006 23:53:21 -0700 Subject: [PATCH 1376/1619] USB: Sierra Wireless driver update The largest feature in this patch is that it adds significant throughput increase to the Sierra driver and adds support for modem status line control (e.g. the DTR line). This patch also updates the current sierra.c driver so that it supports both 3-port Sierra devices and 1-port legacy devices and removes Sierra's references in other related files (Kconfig and airprime.c). Signed-off-by: Kevin Lloyd Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 3 +- drivers/usb/serial/airprime.c | 5 - drivers/usb/serial/sierra.c | 729 ++++++++++++++++++++++++++++++++-- 3 files changed, 699 insertions(+), 38 deletions(-) diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 8ca6d3f01e8..9a6ec1b5e3d 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -537,8 +537,7 @@ config USB_SERIAL_OPTION The USB bus on these cards is not accessible externally. Supported devices include (some of?) those made by: - Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or - Anydata. + Option, Huawei, Audiovox, Novatel Wireless, or Anydata. To compile this driver as a module, choose M here: the module will be called option. diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index ba93c72cdba..7f5d546da39 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -18,11 +18,6 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ - { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ { }, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index d29638daa98..39799d21b85 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,21 +1,59 @@ /* - * Sierra Wireless CDMA Wireless Serial USB driver - * - * Current Copy modified by: Kevin Lloyd - * Original Copyright (C) 2005-2006 Greg Kroah-Hartman - * - * 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. - */ + USB Driver for Sierra Wireless + + Copyright (C) 2006 Kevin Lloyd + + IMPORTANT DISCLAIMER: This driver is not commercially supported by + Sierra Wireless. Use at your own risk. + + This driver 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. + + Portions based on the option driver by Matthias Urlichs + Whom based his on the Keyspan driver by Hugh Blemings + + History: +*/ + +#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_AUTHOR "Kevin Lloyd " +#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" #include -#include +#include +#include #include +#include #include #include #include +/* Function prototypes */ +static int sierra_open(struct usb_serial_port *port, struct file *filp); +static void sierra_close(struct usb_serial_port *port, struct file *filp); +static int sierra_startup(struct usb_serial *serial); +static void sierra_shutdown(struct usb_serial *serial); +static void sierra_rx_throttle(struct usb_serial_port *port); +static void sierra_rx_unthrottle(struct usb_serial_port *port); +static int sierra_write_room(struct usb_serial_port *port); + +static void sierra_instat_callback(struct urb *urb); + +static int sierra_write(struct usb_serial_port *port, + const unsigned char *buf, int count); + +static int sierra_chars_in_buffer(struct usb_serial_port *port); +static int sierra_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg); +static void sierra_set_termios(struct usb_serial_port *port, + struct termios *old); +static void sierra_break_ctl(struct usb_serial_port *port, int break_state); +static int sierra_tiocmget(struct usb_serial_port *port, struct file *file); +static int sierra_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear); +static int sierra_send_setup(struct usb_serial_port *port); + static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ @@ -25,51 +63,680 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ - /* Following devices are supported in the airprime.c driver */ - /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */ - /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */ + + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ + { } +}; + +static struct usb_device_id id_table_1port [] = { + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ { } }; + +static struct usb_device_id id_table_3port [] = { + { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ + { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ + { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ + { } +}; + + MODULE_DEVICE_TABLE(usb, id_table); static struct usb_driver sierra_driver = { - .name = "sierra_wireless", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, + .name = "sierra", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 3, +}; + + +//static struct usb_serial_driver *sierra_device; + +static struct usb_serial_driver sierra_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "sierra1", + }, + .description = "Sierra USB modem (1 port)", + .id_table = id_table_1port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, }; -static struct usb_serial_driver sierra_device = { +static struct usb_serial_driver sierra_3port_device = { .driver = { - .owner = THIS_MODULE, - .name = "Sierra_Wireless", + .owner = THIS_MODULE, + .name = "sierra3", }, - .id_table = id_table, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 3, + .description = "Sierra USB modem (3 port)", + .id_table = id_table_3port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 3, + .num_bulk_out = 3, + .num_ports = 3, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, }; +#ifdef CONFIG_USB_DEBUG +static int debug; +#else +#define debug 0 +#endif + +/* per port private data */ + +#define N_IN_URB 4 +#define N_OUT_URB 1 +#define IN_BUFLEN 4096 +#define OUT_BUFLEN 128 + +struct sierra_port_private { + /* Input endpoints and buffer for this port */ + struct urb *in_urbs[N_IN_URB]; + char in_buffer[N_IN_URB][IN_BUFLEN]; + /* Output endpoints and buffer for this port */ + struct urb *out_urbs[N_OUT_URB]; + char out_buffer[N_OUT_URB][OUT_BUFLEN]; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + + unsigned long tx_start_time[N_OUT_URB]; +}; + +/* Functions used by new usb-serial code. */ static int __init sierra_init(void) { int retval; - - retval = usb_serial_register(&sierra_device); + retval = usb_serial_register(&sierra_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&sierra_3port_device); if (retval) - return retval; + goto failed_3port_device_register; + + retval = usb_register(&sierra_driver); if (retval) - usb_serial_deregister(&sierra_device); + goto failed_driver_register; + + info(DRIVER_DESC ": " DRIVER_VERSION); + + return 0; + +failed_driver_register: + usb_serial_deregister(&sierra_3port_device); +failed_3port_device_register: + usb_serial_deregister(&sierra_1port_device); +failed_1port_device_register: return retval; } static void __exit sierra_exit(void) { - usb_deregister(&sierra_driver); - usb_serial_deregister(&sierra_device); + usb_deregister (&sierra_driver); + usb_serial_deregister(&sierra_1port_device); + usb_serial_deregister(&sierra_3port_device); } module_init(sierra_init); module_exit(sierra_exit); + +static void sierra_rx_throttle(struct usb_serial_port *port) +{ + dbg("%s", __FUNCTION__); +} + +static void sierra_rx_unthrottle(struct usb_serial_port *port) +{ + dbg("%s", __FUNCTION__); +} + +static void sierra_break_ctl(struct usb_serial_port *port, int break_state) +{ + /* Unfortunately, I don't know how to send a break */ + dbg("%s", __FUNCTION__); +} + +static void sierra_set_termios(struct usb_serial_port *port, + struct termios *old_termios) +{ + dbg("%s", __FUNCTION__); + + sierra_send_setup(port); +} + +static int sierra_tiocmget(struct usb_serial_port *port, struct file *file) +{ + unsigned int value; + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + value = ((portdata->rts_state) ? TIOCM_RTS : 0) | + ((portdata->dtr_state) ? TIOCM_DTR : 0) | + ((portdata->cts_state) ? TIOCM_CTS : 0) | + ((portdata->dsr_state) ? TIOCM_DSR : 0) | + ((portdata->dcd_state) ? TIOCM_CAR : 0) | + ((portdata->ri_state) ? TIOCM_RNG : 0); + + return value; +} + +static int sierra_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear) +{ + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + if (set & TIOCM_RTS) + portdata->rts_state = 1; + if (set & TIOCM_DTR) + portdata->dtr_state = 1; + + if (clear & TIOCM_RTS) + portdata->rts_state = 0; + if (clear & TIOCM_DTR) + portdata->dtr_state = 0; + return sierra_send_setup(port); +} + +static int sierra_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +/* Write */ +static int sierra_write(struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct sierra_port_private *portdata; + int i; + int left, todo; + struct urb *this_urb = NULL; /* spurious */ + int err; + + portdata = usb_get_serial_port_data(port); + + dbg("%s: write (%d chars)", __FUNCTION__, count); + + i = 0; + left = count; + for (i=0; left > 0 && i < N_OUT_URB; i++) { + todo = left; + if (todo > OUT_BUFLEN) + todo = OUT_BUFLEN; + + this_urb = portdata->out_urbs[i]; + if (this_urb->status == -EINPROGRESS) { + if (time_before(jiffies, + portdata->tx_start_time[i] + 10 * HZ)) + continue; + usb_unlink_urb(this_urb); + continue; + } + if (this_urb->status != 0) + dbg("usb_write %p failed (err=%d)", + this_urb, this_urb->status); + + dbg("%s: endpoint %d buf %d", __FUNCTION__, + usb_pipeendpoint(this_urb->pipe), i); + + /* send the data */ + memcpy (this_urb->transfer_buffer, buf, todo); + this_urb->transfer_buffer_length = todo; + + this_urb->dev = port->serial->dev; + err = usb_submit_urb(this_urb, GFP_ATOMIC); + if (err) { + dbg("usb_submit_urb %p (write bulk) failed " + "(%d, has %d)", this_urb, + err, this_urb->status); + continue; + } + portdata->tx_start_time[i] = jiffies; + buf += todo; + left -= todo; + } + + count -= left; + dbg("%s: wrote (did %d)", __FUNCTION__, count); + return count; +} + +static void sierra_indat_callback(struct urb *urb) +{ + int err; + int endpoint; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + + dbg("%s: %p", __FUNCTION__, urb); + + endpoint = usb_pipeendpoint(urb->pipe); + port = (struct usb_serial_port *) urb->context; + + if (urb->status) { + dbg("%s: nonzero status: %d on endpoint %02x.", + __FUNCTION__, urb->status, endpoint); + } else { + tty = port->tty; + if (urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } else { + dbg("%s: empty read urb received", __FUNCTION__); + } + + /* Resubmit urb so we continue receiving */ + if (port->open_count && urb->status != -ESHUTDOWN) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __FUNCTION__, err); + } + } + return; +} + +static void sierra_outdat_callback(struct urb *urb) +{ + struct usb_serial_port *port; + + dbg("%s", __FUNCTION__); + + port = (struct usb_serial_port *) urb->context; + + usb_serial_port_softint(port); +} + +static void sierra_instat_callback(struct urb *urb) +{ + int err; + struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + + dbg("%s", __FUNCTION__); + dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata); + + if (urb->status == 0) { + struct usb_ctrlrequest *req_pkt = + (struct usb_ctrlrequest *)urb->transfer_buffer; + + if (!req_pkt) { + dbg("%s: NULL req_pkt\n", __FUNCTION__); + return; + } + if ((req_pkt->bRequestType == 0xA1) && + (req_pkt->bRequest == 0x20)) { + int old_dcd_state; + unsigned char signals = *((unsigned char *) + urb->transfer_buffer + + sizeof(struct usb_ctrlrequest)); + + dbg("%s: signal x%x", __FUNCTION__, signals); + + old_dcd_state = portdata->dcd_state; + portdata->cts_state = 1; + portdata->dcd_state = ((signals & 0x01) ? 1 : 0); + portdata->dsr_state = ((signals & 0x02) ? 1 : 0); + portdata->ri_state = ((signals & 0x08) ? 1 : 0); + + if (port->tty && !C_CLOCAL(port->tty) && + old_dcd_state && !portdata->dcd_state) + tty_hangup(port->tty); + } else { + dbg("%s: type %x req %x", __FUNCTION__, + req_pkt->bRequestType,req_pkt->bRequest); + } + } else + dbg("%s: error %d", __FUNCTION__, urb->status); + + /* Resubmit urb so we continue receiving IRQ data */ + if (urb->status != -ESHUTDOWN) { + urb->dev = serial->dev; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dbg("%s: resubmit intr urb failed. (%d)", + __FUNCTION__, err); + } +} + +static int sierra_write_room(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i=0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && this_urb->status != -EINPROGRESS) + data_len += OUT_BUFLEN; + } + + dbg("%s: %d", __FUNCTION__, data_len); + return data_len; +} + +static int sierra_chars_in_buffer(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i=0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && this_urb->status == -EINPROGRESS) + data_len += this_urb->transfer_buffer_length; + } + dbg("%s: %d", __FUNCTION__, data_len); + return data_len; +} + +static int sierra_open(struct usb_serial_port *port, struct file *filp) +{ + struct sierra_port_private *portdata; + struct usb_serial *serial = port->serial; + int i, err; + struct urb *urb; + + portdata = usb_get_serial_port_data(port); + + dbg("%s", __FUNCTION__); + + /* Set some sane defaults */ + portdata->rts_state = 1; + portdata->dtr_state = 1; + + /* Reset low level data toggle and start reading from endpoints */ + for (i = 0; i < N_IN_URB; i++) { + urb = portdata->in_urbs[i]; + if (! urb) + continue; + if (urb->dev != serial->dev) { + dbg("%s: dev %p != %p", __FUNCTION__, + urb->dev, serial->dev); + continue; + } + + /* + * make sure endpoint data toggle is synchronized with the + * device + */ + usb_clear_halt(urb->dev, urb->pipe); + + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + dbg("%s: submit urb %d failed (%d) %d", + __FUNCTION__, i, err, + urb->transfer_buffer_length); + } + } + + /* Reset low level data toggle on out endpoints */ + for (i = 0; i < N_OUT_URB; i++) { + urb = portdata->out_urbs[i]; + if (! urb) + continue; + urb->dev = serial->dev; + /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), 0); */ + } + + port->tty->low_latency = 1; + + sierra_send_setup(port); + + return (0); +} + +static inline void stop_urb(struct urb *urb) +{ + if (urb && urb->status == -EINPROGRESS) + usb_kill_urb(urb); +} + +static void sierra_close(struct usb_serial_port *port, struct file *filp) +{ + int i; + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + portdata = usb_get_serial_port_data(port); + + portdata->rts_state = 0; + portdata->dtr_state = 0; + + if (serial->dev) { + sierra_send_setup(port); + + /* Stop reading/writing urbs */ + for (i = 0; i < N_IN_URB; i++) + stop_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) + stop_urb(portdata->out_urbs[i]); + } + port->tty = NULL; +} + +/* Helper functions used by sierra_setup_urbs */ +static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, char *buf, int len, + void (*callback)(struct urb *)) +{ + struct urb *urb; + + if (endpoint == -1) + return NULL; /* endpoint not needed */ + + urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ + if (urb == NULL) { + dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint); + return NULL; + } + + /* Fill URB using supplied data. */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + return urb; +} + +/* Setup urbs */ +static void sierra_setup_urbs(struct usb_serial *serial) +{ + int i,j; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ + for (j = 0; j < N_IN_URB; ++j) { + portdata->in_urbs[j] = sierra_setup_urb (serial, + port->bulk_in_endpointAddress, USB_DIR_IN, port, + portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback); + } + + /* outdat endpoints */ + for (j = 0; j < N_OUT_URB; ++j) { + portdata->out_urbs[j] = sierra_setup_urb (serial, + port->bulk_out_endpointAddress, USB_DIR_OUT, port, + portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback); + } + } +} + +static int sierra_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + portdata = usb_get_serial_port_data(port); + + if (port->tty) { + int val = 0; + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; + + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + } + + return 0; +} + +static int sierra_startup(struct usb_serial *serial) +{ + int i, err; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) { + dbg("%s: kmalloc for sierra_port_private (%d) failed!.", + __FUNCTION__, i); + return (1); + } + + usb_set_serial_port_data(port, portdata); + + if (! port->interrupt_in_urb) + continue; + err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (err) + dbg("%s: submit irq_in urb failed %d", + __FUNCTION__, err); + } + + sierra_setup_urbs(serial); + + return (0); +} + +static void sierra_shutdown(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + /* Stop reading/writing urbs */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + for (j = 0; j < N_IN_URB; j++) + stop_urb(portdata->in_urbs[j]); + for (j = 0; j < N_OUT_URB; j++) + stop_urb(portdata->out_urbs[j]); + } + + /* Now free them */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + for (j = 0; j < N_IN_URB; j++) { + if (portdata->in_urbs[j]) { + usb_free_urb(portdata->in_urbs[j]); + portdata->in_urbs[j] = NULL; + } + } + for (j = 0; j < N_OUT_URB; j++) { + if (portdata->out_urbs[j]) { + usb_free_urb(portdata->out_urbs[j]); + portdata->out_urbs[j] = NULL; + } + } + } + + /* Now free per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + kfree(usb_get_serial_port_data(port)); + } +} + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); + +#ifdef CONFIG_USB_DEBUG +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug messages"); +#endif + -- GitLab From 964ee1deb3eac802902cd758ddb94b6a95c77987 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Oct 2006 10:17:58 -0700 Subject: [PATCH 1377/1619] USB: cleanup sierra wireless driver a bit This saves over 30 lines and fixes a warning from sparse and allows debugging to work dynamically like all other usb-serial drivers. Cc: Kevin Lloyd Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 269 ++++++++++++++++-------------------- 1 file changed, 118 insertions(+), 151 deletions(-) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 39799d21b85..6bdb11717e5 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -29,30 +29,6 @@ #include #include -/* Function prototypes */ -static int sierra_open(struct usb_serial_port *port, struct file *filp); -static void sierra_close(struct usb_serial_port *port, struct file *filp); -static int sierra_startup(struct usb_serial *serial); -static void sierra_shutdown(struct usb_serial *serial); -static void sierra_rx_throttle(struct usb_serial_port *port); -static void sierra_rx_unthrottle(struct usb_serial_port *port); -static int sierra_write_room(struct usb_serial_port *port); - -static void sierra_instat_callback(struct urb *urb); - -static int sierra_write(struct usb_serial_port *port, - const unsigned char *buf, int count); - -static int sierra_chars_in_buffer(struct usb_serial_port *port); -static int sierra_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg); -static void sierra_set_termios(struct usb_serial_port *port, - struct termios *old); -static void sierra_break_ctl(struct usb_serial_port *port, int break_state); -static int sierra_tiocmget(struct usb_serial_port *port, struct file *file); -static int sierra_tiocmset(struct usb_serial_port *port, struct file *file, - unsigned int set, unsigned int clear); -static int sierra_send_setup(struct usb_serial_port *port); static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ @@ -68,6 +44,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ { } }; +MODULE_DEVICE_TABLE(usb, id_table); static struct usb_device_id id_table_1port [] = { { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ @@ -87,88 +64,22 @@ static struct usb_device_id id_table_3port [] = { { } }; - -MODULE_DEVICE_TABLE(usb, id_table); - static struct usb_driver sierra_driver = { .name = "sierra", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, - .no_dynamic_id = 3, + .no_dynamic_id = 1, }; -//static struct usb_serial_driver *sierra_device; - -static struct usb_serial_driver sierra_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "sierra1", - }, - .description = "Sierra USB modem (1 port)", - .id_table = id_table_1port, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = sierra_open, - .close = sierra_close, - .write = sierra_write, - .write_room = sierra_write_room, - .chars_in_buffer = sierra_chars_in_buffer, - .throttle = sierra_rx_throttle, - .unthrottle = sierra_rx_unthrottle, - .ioctl = sierra_ioctl, - .set_termios = sierra_set_termios, - .break_ctl = sierra_break_ctl, - .tiocmget = sierra_tiocmget, - .tiocmset = sierra_tiocmset, - .attach = sierra_startup, - .shutdown = sierra_shutdown, - .read_int_callback = sierra_instat_callback, -}; - -static struct usb_serial_driver sierra_3port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "sierra3", - }, - .description = "Sierra USB modem (3 port)", - .id_table = id_table_3port, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 3, - .num_bulk_out = 3, - .num_ports = 3, - .open = sierra_open, - .close = sierra_close, - .write = sierra_write, - .write_room = sierra_write_room, - .chars_in_buffer = sierra_chars_in_buffer, - .throttle = sierra_rx_throttle, - .unthrottle = sierra_rx_unthrottle, - .ioctl = sierra_ioctl, - .set_termios = sierra_set_termios, - .break_ctl = sierra_break_ctl, - .tiocmget = sierra_tiocmget, - .tiocmset = sierra_tiocmset, - .attach = sierra_startup, - .shutdown = sierra_shutdown, - .read_int_callback = sierra_instat_callback, -}; - -#ifdef CONFIG_USB_DEBUG static int debug; -#else -#define debug 0 -#endif /* per port private data */ - -#define N_IN_URB 4 -#define N_OUT_URB 1 -#define IN_BUFLEN 4096 -#define OUT_BUFLEN 128 +#define N_IN_URB 4 +#define N_OUT_URB 1 +#define IN_BUFLEN 4096 +#define OUT_BUFLEN 128 struct sierra_port_private { /* Input endpoints and buffer for this port */ @@ -189,44 +100,30 @@ struct sierra_port_private { unsigned long tx_start_time[N_OUT_URB]; }; -/* Functions used by new usb-serial code. */ -static int __init sierra_init(void) +static int sierra_send_setup(struct usb_serial_port *port) { - int retval; - retval = usb_serial_register(&sierra_1port_device); - if (retval) - goto failed_1port_device_register; - retval = usb_serial_register(&sierra_3port_device); - if (retval) - goto failed_3port_device_register; - + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; - retval = usb_register(&sierra_driver); - if (retval) - goto failed_driver_register; + dbg("%s", __FUNCTION__); - info(DRIVER_DESC ": " DRIVER_VERSION); + portdata = usb_get_serial_port_data(port); - return 0; + if (port->tty) { + int val = 0; + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; -failed_driver_register: - usb_serial_deregister(&sierra_3port_device); -failed_3port_device_register: - usb_serial_deregister(&sierra_1port_device); -failed_1port_device_register: - return retval; -} + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + } -static void __exit sierra_exit(void) -{ - usb_deregister (&sierra_driver); - usb_serial_deregister(&sierra_1port_device); - usb_serial_deregister(&sierra_3port_device); + return 0; } -module_init(sierra_init); -module_exit(sierra_exit); - static void sierra_rx_throttle(struct usb_serial_port *port) { dbg("%s", __FUNCTION__); @@ -578,8 +475,8 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp) /* Helper functions used by sierra_setup_urbs */ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, - int dir, void *ctx, char *buf, int len, - void (*callback)(struct urb *)) + int dir, void *ctx, char *buf, int len, + usb_complete_t callback) { struct urb *urb; @@ -629,30 +526,6 @@ static void sierra_setup_urbs(struct usb_serial *serial) } } -static int sierra_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct sierra_port_private *portdata; - - dbg("%s", __FUNCTION__); - - portdata = usb_get_serial_port_data(port); - - if (port->tty) { - int val = 0; - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; - - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); - } - - return 0; -} - static int sierra_startup(struct usb_serial *serial) { int i, err; @@ -730,6 +603,100 @@ static void sierra_shutdown(struct usb_serial *serial) } } +static struct usb_serial_driver sierra_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "sierra1", + }, + .description = "Sierra USB modem (1 port)", + .id_table = id_table_1port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, +}; + +static struct usb_serial_driver sierra_3port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "sierra3", + }, + .description = "Sierra USB modem (3 port)", + .id_table = id_table_3port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 3, + .num_bulk_out = 3, + .num_ports = 3, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, +}; + +/* Functions used by new usb-serial code. */ +static int __init sierra_init(void) +{ + int retval; + retval = usb_serial_register(&sierra_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&sierra_3port_device); + if (retval) + goto failed_3port_device_register; + + + retval = usb_register(&sierra_driver); + if (retval) + goto failed_driver_register; + + info(DRIVER_DESC ": " DRIVER_VERSION); + + return 0; + +failed_driver_register: + usb_serial_deregister(&sierra_3port_device); +failed_3port_device_register: + usb_serial_deregister(&sierra_1port_device); +failed_1port_device_register: + return retval; +} + +static void __exit sierra_exit(void) +{ + usb_deregister (&sierra_driver); + usb_serial_deregister(&sierra_1port_device); + usb_serial_deregister(&sierra_3port_device); +} + +module_init(sierra_init); +module_exit(sierra_exit); + MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); -- GitLab From ab352c2687a4361aec06a184ddb20deb1e5091eb Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Tue, 17 Oct 2006 00:09:00 +0200 Subject: [PATCH 1378/1619] USB: Add device id for Sierra Wireless MC8755 Adds the device id used by the UMTS cards in Lenovo X60s notebooks sold in Europe. Signed-off-by: Jan Luebbe Cc: Kevin Lloyd Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6bdb11717e5..ea16572d19f 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -37,6 +37,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ -- GitLab From ffc45571dfb4b70e7eda8d97f64a05f5e5a992ac Mon Sep 17 00:00:00 2001 From: Aron Griffis Date: Tue, 17 Oct 2006 00:28:15 -0400 Subject: [PATCH 1379/1619] [IA64] move ioremap/ioremap_nocache under __KERNEL__ I noticed these are declared extern outside of __KERNEL__, but surely they wouldn't be available to userland since they're defined in ioremap.c. Am I missing something here? If I'm right about this, then there's probably a good deal of other stuff in io.h that could move inside __KERNEL__, but at least this is a start. Signed-off-by: Aron Griffis Signed-off-by: Tony Luck --- include/asm-ia64/io.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h index 43bfff6c6b8..855c30af72a 100644 --- a/include/asm-ia64/io.h +++ b/include/asm-ia64/io.h @@ -417,6 +417,8 @@ __writeq (unsigned long val, volatile void __iomem *addr) # define outl_p outl #endif +# ifdef __KERNEL__ + extern void __iomem * ioremap(unsigned long offset, unsigned long size); extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); @@ -430,8 +432,6 @@ iounmap (volatile void __iomem *addr) #define dmi_iounmap(x,l) iounmap(x) #define dmi_alloc(l) kmalloc(l, GFP_ATOMIC) -# ifdef __KERNEL__ - /* * String version of IO memory access ops: */ -- GitLab From accaddb27a2d544e38e10ff2a2782b33bbbad913 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Mon, 16 Oct 2006 12:56:54 -0500 Subject: [PATCH 1380/1619] [IA64] - Allow IPIs in timer loop Allow pending IPIs to interrupt a timer interrupt that is looping in the do_timer() "while" loop in timer_interrupt(). (Interrupts are allowed at only 1 spot in the code). Signed-off-by: Jack Steiner Signed-off-by: Tony Luck --- arch/ia64/kernel/time.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 41169a9bc30..39e0cd3a088 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -84,6 +84,12 @@ timer_interrupt (int irq, void *dev_id) if (time_after(new_itm, ia64_get_itc())) break; + + /* + * Allow IPIs to interrupt the timer loop. + */ + local_irq_enable(); + local_irq_disable(); } do { -- GitLab From c12fb1885787dcc2e20c4b88149e1e607e1293b2 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 12 Oct 2006 16:20:59 -0600 Subject: [PATCH 1381/1619] [IA64] remove unused PAL_CALL_IC_OFF Linux maps PAL instructions with an ITR, but uses a DTC for PAL data. Section 11.10.2.1.3, "Making PAL Procedures Calls in Physical or Virtual Mode," of the SDM (rev 2.2), says we must therefore make all PAL calls with PSR.ic = 1 so that Linux can handle any TLB faults. PAL_CALL_IC_OFF is currently unused, and as long as we use the ITR + DTC strategy, we can't use it. So remove it. I also removed the code in ia64_pal_call_static() that conditionally cleared PSR.ic. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/kernel/pal.S | 11 +++-------- include/asm-ia64/pal.h | 11 ++--------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S index ebaf1e685f5..5f50e6bbc68 100644 --- a/arch/ia64/kernel/pal.S +++ b/arch/ia64/kernel/pal.S @@ -50,12 +50,10 @@ END(ia64_pal_default_handler) * * in0 Index of PAL service * in1 - in3 Remaining PAL arguments - * in4 1 ==> clear psr.ic, 0 ==> don't clear psr.ic - * */ GLOBAL_ENTRY(ia64_pal_call_static) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) - alloc loc1 = ar.pfs,5,5,0,0 + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4) + alloc loc1 = ar.pfs,4,5,0,0 movl loc2 = pal_entry_point 1: { mov r28 = in0 @@ -64,7 +62,6 @@ GLOBAL_ENTRY(ia64_pal_call_static) } ;; ld8 loc2 = [loc2] // loc2 <- entry point - tbit.nz p6,p7 = in4, 0 adds r8 = 1f-1b,r8 mov loc4=ar.rsc // save RSE configuration ;; @@ -74,13 +71,11 @@ GLOBAL_ENTRY(ia64_pal_call_static) .body mov r30 = in2 -(p6) rsm psr.i | psr.ic mov r31 = in3 mov b7 = loc2 -(p7) rsm psr.i + rsm psr.i ;; -(p6) srlz.i mov rp = r8 br.cond.sptk.many b7 1: mov psr.l = loc3 diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h index 2c8fd92d0ec..4283ddcc25f 100644 --- a/include/asm-ia64/pal.h +++ b/include/asm-ia64/pal.h @@ -764,7 +764,7 @@ struct ia64_pal_retval { * (generally 0) MUST be passed. Reserved parameters are not optional * parameters. */ -extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64, u64); +extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_stacked (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64); @@ -774,14 +774,7 @@ extern void ia64_load_scratch_fpregs (struct ia64_fpreg *); #define PAL_CALL(iprv,a0,a1,a2,a3) do { \ struct ia64_fpreg fr[6]; \ ia64_save_scratch_fpregs(fr); \ - iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \ - ia64_load_scratch_fpregs(fr); \ -} while (0) - -#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do { \ - struct ia64_fpreg fr[6]; \ - ia64_save_scratch_fpregs(fr); \ - iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \ + iprv = ia64_pal_call_static(a0, a1, a2, a3); \ ia64_load_scratch_fpregs(fr); \ } while (0) -- GitLab From 4d5a31977cc69be8786e0033d5c148e5c62ae949 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 12 Oct 2006 16:21:17 -0600 Subject: [PATCH 1382/1619] [IA64] reformat pal.S to fit in 80 columns, fix typos Reformat to fit in 80 columns. Fix a couple typos. Remove a couple unused labels. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/kernel/pal.S | 47 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S index 5f50e6bbc68..0b533441c3c 100644 --- a/arch/ia64/kernel/pal.S +++ b/arch/ia64/kernel/pal.S @@ -21,11 +21,12 @@ pal_entry_point: .text /* - * Set the PAL entry point address. This could be written in C code, but we do it here - * to keep it all in one module (besides, it's so trivial that it's + * Set the PAL entry point address. This could be written in C code, but we + * do it here to keep it all in one module (besides, it's so trivial that it's * not a big deal). * - * in0 Address of the PAL entry point (text address, NOT a function descriptor). + * in0 Address of the PAL entry point (text address, NOT a function + * descriptor). */ GLOBAL_ENTRY(ia64_pal_handler_init) alloc r3=ar.pfs,1,0,0,0 @@ -36,9 +37,9 @@ GLOBAL_ENTRY(ia64_pal_handler_init) END(ia64_pal_handler_init) /* - * Default PAL call handler. This needs to be coded in assembly because it uses - * the static calling convention, i.e., the RSE may not be used and calls are - * done via "br.cond" (not "br.call"). + * Default PAL call handler. This needs to be coded in assembly because it + * uses the static calling convention, i.e., the RSE may not be used and + * calls are done via "br.cond" (not "br.call"). */ GLOBAL_ENTRY(ia64_pal_default_handler) mov r8=-1 @@ -91,8 +92,8 @@ END(ia64_pal_call_static) * Make a PAL call using the stacked registers calling convention. * * Inputs: - * in0 Index of PAL service - * in2 - in3 Remaning PAL arguments + * in0 Index of PAL service + * in2 - in3 Remaining PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_stacked) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4) @@ -126,18 +127,18 @@ END(ia64_pal_call_stacked) * Make a physical mode PAL call using the static registers calling convention. * * Inputs: - * in0 Index of PAL service - * in2 - in3 Remaning PAL arguments + * in0 Index of PAL service + * in2 - in3 Remaining PAL arguments * * PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel. * So we don't need to clear them. */ -#define PAL_PSR_BITS_TO_CLEAR \ - (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT | \ - IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ +#define PAL_PSR_BITS_TO_CLEAR \ + (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT |\ + IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ IA64_PSR_DFL | IA64_PSR_DFH) -#define PAL_PSR_BITS_TO_SET \ +#define PAL_PSR_BITS_TO_SET \ (IA64_PSR_BN) @@ -173,7 +174,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) ;; andcm r16=loc3,r16 // removes bits to clear from psr br.call.sptk.many rp=ia64_switch_mode_phys -.ret1: mov rp = r8 // install return address (physical) + mov rp = r8 // install return address (physical) mov loc5 = r19 mov loc6 = r20 br.cond.sptk.many b7 @@ -183,7 +184,6 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) mov r19=loc5 mov r20=loc6 br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode -.ret2: mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 @@ -198,8 +198,8 @@ END(ia64_pal_call_phys_static) * Make a PAL call using the stacked registers in physical mode. * * Inputs: - * in0 Index of PAL service - * in2 - in3 Remaning PAL arguments + * in0 Index of PAL service + * in2 - in3 Remaining PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) @@ -207,7 +207,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) movl loc2 = pal_entry_point 1: { mov r28 = in0 // copy procedure index - mov loc0 = rp // save rp + mov loc0 = rp // save rp } .body ;; @@ -240,7 +240,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) mov r16=loc3 // r16= original psr mov r19=loc5 mov r20=loc6 - br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 @@ -252,10 +252,11 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) END(ia64_pal_call_phys_stacked) /* - * Save scratch fp scratch regs which aren't saved in pt_regs already (fp10-fp15). + * Save scratch fp scratch regs which aren't saved in pt_regs already + * (fp10-fp15). * - * NOTE: We need to do this since firmware (SAL and PAL) may use any of the scratch - * regs fp-low partition. + * NOTE: We need to do this since firmware (SAL and PAL) may use any of the + * scratch regs fp-low partition. * * Inputs: * in0 Address of stack storage for fp regs -- GitLab From 8611342f3dda0e13970e724129a8e2066de1362e Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 9 Oct 2006 05:24:57 -0400 Subject: [PATCH 1383/1619] [IA64] update sn2_defconfig The current sn2_defconfig is obsolete, in particular the recent ATA changes are a pain, so here's a patch to get things in sync ... at least for a day or two :) Update sn_defconfig to match current community kernel tree. Signed-off-by: Jes Sorensen Signed-off-by: Tony Luck --- arch/ia64/configs/sn2_defconfig | 219 +++++++++++++++++++++++++------- 1 file changed, 175 insertions(+), 44 deletions(-) diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig index 0f14a82b856..64e951de4e5 100644 --- a/arch/ia64/configs/sn2_defconfig +++ b/arch/ia64/configs/sn2_defconfig @@ -1,8 +1,9 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.17-rc3 -# Thu Apr 27 11:48:23 2006 +# Linux kernel version: 2.6.19-rc1 +# Mon Oct 9 10:53:59 2006 # +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options @@ -18,16 +19,22 @@ CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_CPUSETS=y CONFIG_RELAY=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_TASK_XACCT=y +CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -40,6 +47,8 @@ CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -58,6 +67,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_BLK_DEV_IO_TRACE is not set # @@ -89,7 +99,7 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_IA64_UNCACHED_ALLOCATOR=y -CONFIG_DMA_IS_DMA32=y +CONFIG_AUDIT_ARCH=y # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set # CONFIG_IA64_HP_ZX1 is not set @@ -116,6 +126,7 @@ CONFIG_FORCE_MAX_ZONEORDER=17 CONFIG_SMP=y CONFIG_NR_CPUS=1024 # CONFIG_HOTPLUG_CPU is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_SCHED_SMT=y CONFIG_PREEMPT=y CONFIG_SELECT_MEMORY_MODEL=y @@ -128,6 +139,7 @@ CONFIG_NEED_MULTIPLE_NODES=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y +CONFIG_RESOURCES_64BIT=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_DISCONTIGMEM_ENABLE=y CONFIG_ARCH_FLATMEM_ENABLE=y @@ -135,15 +147,24 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y CONFIG_NUMA=y CONFIG_NODES_SHIFT=10 +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_VIRTUAL_MEM_MAP=y CONFIG_HOLES_IN_ZONE=y CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y CONFIG_IA64_MCA_RECOVERY=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y CONFIG_SGI_SN=y +# CONFIG_IA64_ESI is not set + +# +# SN Devices +# +CONFIG_SGI_IOC4=y +CONFIG_SGI_IOC3=y # # Firmware Drivers @@ -159,6 +180,7 @@ CONFIG_BINFMT_ELF=y CONFIG_PM=y # CONFIG_PM_LEGACY is not set # CONFIG_PM_DEBUG is not set +# CONFIG_PM_SYSFS_DEPRECATED is not set # # ACPI (Advanced Configuration and Power Interface) Support @@ -166,6 +188,7 @@ CONFIG_PM=y CONFIG_ACPI=y # CONFIG_ACPI_BUTTON is not set # CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_DOCK is not set # CONFIG_ACPI_PROCESSOR is not set CONFIG_ACPI_NUMA=y CONFIG_ACPI_BLACKLIST_YEAR=0 @@ -185,7 +208,12 @@ CONFIG_ACPI_SYSTEM=y # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set +CONFIG_PCIEAER=y # CONFIG_PCI_MSI is not set +# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # @@ -215,6 +243,9 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -231,19 +262,31 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_IPCOMP is not set # CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=m CONFIG_INET_TCP_DIAG=m # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_IPV6=m # CONFIG_IPV6_PRIVACY is not set # CONFIG_IPV6_ROUTER_PREF is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set # CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set # @@ -269,7 +312,6 @@ CONFIG_IPV6=m # 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 @@ -298,6 +340,7 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set # # Connector - unified userspace <-> kernelspace linker @@ -335,6 +378,7 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set CONFIG_ATA_OVER_ETH=m @@ -381,6 +425,7 @@ CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_IT821X is not set @@ -404,6 +449,7 @@ CONFIG_IDEDMA_AUTO=y # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -425,12 +471,14 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_ISCSI_ATTRS=m CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set # # SCSI low-level drivers @@ -443,45 +491,81 @@ CONFIG_ISCSI_TCP=m # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set -CONFIG_SCSI_SATA=y -# CONFIG_SCSI_SATA_AHCI is not set -# CONFIG_SCSI_SATA_SVW is not set -# CONFIG_SCSI_ATA_PIIX is not set -# CONFIG_SCSI_SATA_MV is not set -# CONFIG_SCSI_SATA_NV is not set -# CONFIG_SCSI_PDC_ADMA is not set -# CONFIG_SCSI_SATA_QSTOR is not set -# CONFIG_SCSI_SATA_PROMISE is not set -# CONFIG_SCSI_SATA_SX4 is not set -# CONFIG_SCSI_SATA_SIL is not set -# CONFIG_SCSI_SATA_SIL24 is not set -# CONFIG_SCSI_SATA_SIS is not set -# CONFIG_SCSI_SATA_ULI is not set -# CONFIG_SCSI_SATA_VIA is not set -CONFIG_SCSI_SATA_VITESSE=y +# CONFIG_SCSI_HPTIOP is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set CONFIG_SCSI_QLOGIC_1280=y CONFIG_SCSI_QLA_FC=y -CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE=y -# CONFIG_SCSI_QLA21XX is not set -CONFIG_SCSI_QLA22XX=y -CONFIG_SCSI_QLA2300=y -CONFIG_SCSI_QLA2322=y -# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +CONFIG_SATA_VITESSE=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set + # # Multi-device support (RAID and LVM) # @@ -491,12 +575,12 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y # CONFIG_MD_RAID10 is not set -CONFIG_MD_RAID5=y +CONFIG_MD_RAID456=y # CONFIG_MD_RAID5_RESHAPE is not set -# CONFIG_MD_RAID6 is not set CONFIG_MD_MULTIPATH=y # CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m @@ -563,6 +647,7 @@ CONFIG_NETDEVICES=y # CONFIG_SK98LIN is not set CONFIG_TIGON3=y # CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -571,6 +656,7 @@ CONFIG_CHELSIO_T1=m # CONFIG_IXGB is not set CONFIG_S2IO=m # CONFIG_S2IO_NAPI is not set +# CONFIG_MYRI10GE is not set # # Token Ring devices @@ -612,6 +698,7 @@ CONFIG_NET_POLL_CONTROLLER=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -646,6 +733,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set CONFIG_SERIAL_NONSTANDARD=y # CONFIG_COMPUTONE is not set # CONFIG_ROCKETPORT is not set @@ -659,10 +747,12 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_N_HDLC is not set # CONFIG_SPECIALIX is not set # CONFIG_SX is not set +# CONFIG_RIO is not set # CONFIG_STALDRV is not set CONFIG_SGI_SNSC=y CONFIG_SGI_TIOCX=y CONFIG_SGI_MBCS=m +CONFIG_MSPEC=y # # Serial drivers @@ -701,6 +791,7 @@ CONFIG_EFI_RTC=y # Ftape, the floppy tape device driver # CONFIG_AGP=y +# CONFIG_AGP_SIS is not set # CONFIG_AGP_VIA is not set CONFIG_AGP_SGI_TIOCA=y # CONFIG_DRM is not set @@ -730,7 +821,6 @@ CONFIG_MMTIMER=y # # Dallas's 1-wire bus # -# CONFIG_W1 is not set # # Hardware Monitoring support @@ -741,6 +831,7 @@ CONFIG_MMTIMER=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices @@ -756,6 +847,7 @@ CONFIG_MMTIMER=y # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set # @@ -764,6 +856,7 @@ CONFIG_MMTIMER=y CONFIG_VGA_CONSOLE=y # CONFIG_VGACON_SOFT_SCROLLBACK is not set CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -794,6 +887,7 @@ CONFIG_USB=m CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set # CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=m # CONFIG_USB_OHCI_BIG_ENDIAN is not set @@ -843,6 +937,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set # # USB Imaging devices @@ -874,15 +969,18 @@ CONFIG_USB_MON=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGETKIT is not set -# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set @@ -919,18 +1017,15 @@ CONFIG_USB_MON=y CONFIG_INFINIBAND=m # CONFIG_INFINIBAND_USER_MAD is not set CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_ADDR_TRANS=y CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_MTHCA_DEBUG=y +# CONFIG_INFINIBAND_AMSO1100 is not set CONFIG_INFINIBAND_IPOIB=m CONFIG_INFINIBAND_IPOIB_DEBUG=y # CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set CONFIG_INFINIBAND_SRP=m - -# -# SN Devices -# -CONFIG_SGI_IOC4=y -CONFIG_SGI_IOC3=y +# CONFIG_INFINIBAND_ISER is not set # # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) @@ -941,6 +1036,19 @@ CONFIG_SGI_IOC3=y # # CONFIG_RTC_CLASS is not set +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + # # File systems # @@ -965,15 +1073,16 @@ CONFIG_REISERFS_FS_SECURITY=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y CONFIG_XFS_FS=y -CONFIG_XFS_EXPORT=y CONFIG_XFS_QUOTA=y # CONFIG_XFS_SECURITY is not set CONFIG_XFS_POSIX_ACL=y CONFIG_XFS_RT=y +# CONFIG_GFS2_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=y # CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V2 is not set @@ -1007,8 +1116,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y @@ -1046,7 +1157,7 @@ CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=m CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m @@ -1056,7 +1167,9 @@ CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set # CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set # CONFIG_CIFS_EXPERIMENTAL is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -1128,6 +1241,10 @@ CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=y +# +# Distributed Lock Manager +# + # # Library routines # @@ -1138,9 +1255,11 @@ CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=m CONFIG_ZLIB_DEFLATE=m CONFIG_GENERIC_ALLOCATOR=y +CONFIG_PLIST=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_IRQ_PER_CPU=y # # Instrumentation Support @@ -1152,20 +1271,26 @@ CONFIG_GENERIC_PENDING_IRQ=y # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=20 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set -CONFIG_DEBUG_PREEMPT=y -# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set CONFIG_IA64_GRANULE_16MB=y @@ -1186,6 +1311,10 @@ CONFIG_SYSVIPC_COMPAT=y # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=m CONFIG_CRYPTO_HMAC=y # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set @@ -1195,6 +1324,8 @@ CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_DES=m # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set -- GitLab From 219902677351665bf0513115592a6dd665cf06e8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 29 Sep 2006 12:58:31 -0600 Subject: [PATCH 1384/1619] [IA64] remove unused acpi_kbd_controller_present, acpi_legacy_devices Nobody uses either one anymore. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- arch/ia64/kernel/acpi.c | 9 --------- arch/ia64/sn/kernel/setup.c | 12 ------------ 2 files changed, 21 deletions(-) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 32c3abededc..73ef4a85b86 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -64,9 +64,6 @@ EXPORT_SYMBOL(pm_idle); void (*pm_power_off) (void); EXPORT_SYMBOL(pm_power_off); -unsigned char acpi_kbd_controller_present = 1; -unsigned char acpi_legacy_devices; - unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; @@ -628,12 +625,6 @@ static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size) fadt = (struct fadt_descriptor *)fadt_header; - if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER)) - acpi_kbd_controller_present = 0; - - if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES) - acpi_legacy_devices = 1; - acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return 0; } diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 5f2dcba7fa8..7a2d824c5ce 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -65,7 +65,6 @@ extern void sn_timer_init(void); extern unsigned long last_time_offset; extern void (*ia64_mark_idle) (int); extern void snidle(int); -extern unsigned char acpi_kbd_controller_present; extern unsigned long long (*ia64_printk_clock)(void); unsigned long sn_rtc_cycles_per_second; @@ -452,17 +451,6 @@ void __init sn_setup(char **cmdline_p) ia64_printk_clock = ia64_sn2_printk_clock; - /* - * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard - * support here so we don't have to listen to failed keyboard probe - * messages. - */ - if (is_shub1() && version <= 0x0209 && acpi_kbd_controller_present) { - printk(KERN_INFO "Disabling legacy keyboard support as prom " - "is too old and doesn't provide FADT\n"); - acpi_kbd_controller_present = 0; - } - printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF); /* -- GitLab From 9b3377f9921766b6193861d0e3194854b1d765fe Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Mon, 16 Oct 2006 16:17:43 -0500 Subject: [PATCH 1385/1619] [IA64] Count resched interrupts Count the number of "resched" interrupts that each cpu receives. Signed-off-by: Jack Steiner Signed-off-by: Tony Luck --- arch/ia64/kernel/irq_ia64.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 68339dd0c9e..9c6dafa2d0d 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -180,7 +180,9 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) saved_tpr = ia64_getreg(_IA64_REG_CR_TPR); ia64_srlz_d(); while (vector != IA64_SPURIOUS_INT_VECTOR) { - if (!IS_RESCHEDULE(vector)) { + if (unlikely(IS_RESCHEDULE(vector))) + kstat_this_cpu.irqs[vector]++; + else { ia64_setreg(_IA64_REG_CR_TPR, vector); ia64_srlz_d(); @@ -225,7 +227,9 @@ void ia64_process_pending_intr(void) * Perform normal interrupt style processing */ while (vector != IA64_SPURIOUS_INT_VECTOR) { - if (!IS_RESCHEDULE(vector)) { + if (unlikely(IS_RESCHEDULE(vector))) + kstat_this_cpu.irqs[vector]++; + else { struct pt_regs *old_regs = set_irq_regs(NULL); ia64_setreg(_IA64_REG_CR_TPR, vector); @@ -258,11 +262,22 @@ void ia64_process_pending_intr(void) #ifdef CONFIG_SMP extern irqreturn_t handle_IPI (int irq, void *dev_id); +static irqreturn_t dummy_handler (int irq, void *dev_id) +{ + BUG(); +} + static struct irqaction ipi_irqaction = { .handler = handle_IPI, .flags = IRQF_DISABLED, .name = "IPI" }; + +static struct irqaction resched_irqaction = { + .handler = dummy_handler, + .flags = SA_INTERRUPT, + .name = "resched" +}; #endif void @@ -287,6 +302,7 @@ init_IRQ (void) register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); #ifdef CONFIG_SMP register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction); + register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction); #endif #ifdef CONFIG_PERFMON pfm_init_percpu(); -- GitLab From 9950421c1e90d08d52ef47df1fcebe6078b04af3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 17 Oct 2006 18:03:33 -0700 Subject: [PATCH 1386/1619] Fix USB gadget net2280.c compile It would fail the compile due to the newly added error checking testing a bad macro for a "return value" unless USB_GADGET_DEBUG_FILES was enabled. Pointed out by Stephen Hemminger. Acked-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- drivers/usb/gadget/net2280.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 7cfe0e5cf67..3acc896a5d4 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1774,8 +1774,8 @@ static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL); #else -#define device_create_file(a,b) do {} while (0) -#define device_remove_file device_create_file +#define device_create_file(a,b) (0) +#define device_remove_file(a,b) do { } while (0) #endif -- GitLab From 7341df16a1f228be833e918cb42534a34381a37e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Oct 2006 00:24:14 -0700 Subject: [PATCH 1387/1619] [SPARC]: Kill BOOTME_SINGLE. Unused, but still allow the '-s' boot option to be passed down to init. Based upon patches by Martin Habets. Signed-off-by: David S. Miller --- arch/sparc/kernel/setup.c | 2 -- arch/sparc64/kernel/setup.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index f5ee1ac834b..383526ad94f 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -103,7 +103,6 @@ void prom_sync_me(void) unsigned int boot_flags __initdata = 0; #define BOOTME_DEBUG 0x1 -#define BOOTME_SINGLE 0x2 /* Exported for mm/init.c:paging_init. */ unsigned long cmdline_memory_size __initdata = 0; @@ -132,7 +131,6 @@ static void __init process_switch(char c) boot_flags |= BOOTME_DEBUG; break; case 's': - boot_flags |= BOOTME_SINGLE; break; case 'h': prom_printf("boot_flags_init: Halt!\n"); diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index cc8ad480a20..bf033b31d43 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -74,7 +74,6 @@ prom_console_write(struct console *con, const char *s, unsigned n) unsigned int boot_flags = 0; #define BOOTME_DEBUG 0x1 -#define BOOTME_SINGLE 0x2 /* Exported for mm/init.c:paging_init. */ unsigned long cmdline_memory_size = 0; @@ -102,7 +101,6 @@ static void __init process_switch(char c) boot_flags |= BOOTME_DEBUG; break; case 's': - boot_flags |= BOOTME_SINGLE; break; case 'h': prom_printf("boot_flags_init: Halt!\n"); -- GitLab From 5aee87c43e3a71a4aa4e72b0dc2180e4952c0848 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Oct 2006 19:04:44 -0700 Subject: [PATCH 1388/1619] [SPARC64]: Fix PCI memory space root resource on Hummingbird. For Hummingbird PCI controllers, we should create the root PCI memory space resource as the full 4GB area, and then allocate the IOMMU DMA translation window out of there. The old code just assumed that the IOMMU DMA translation base to the top of the 4GB area was unusable. This is not true on many systems such as SB100 and SB150, where the IOMMU DMA translation window sits at 0xc0000000->0xdfffffff. So what would happen is that any device mapped by the firmware at the top section 0xe0000000->0xffffffff would get remapped by Linux somewhere else leading to all kinds of problems and boot failures. While we're here, report more cases of OBP resource assignment conflicts. The only truly valid ones are ROM resource conflicts. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_common.c | 29 ++++++++++------------------- arch/sparc64/kernel/pci_sabre.c | 23 +++++++++++++++++++---- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 7a59cc72c84..827ae30aa49 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -330,19 +330,6 @@ __init get_device_resource(struct linux_prom_pci_registers *ap, return res; } -static int __init pdev_resource_collisions_expected(struct pci_dev *pdev) -{ - if (pdev->vendor != PCI_VENDOR_ID_SUN) - return 0; - - if (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS || - pdev->device == PCI_DEVICE_ID_SUN_RIO_1394 || - pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) - return 1; - - return 0; -} - static void __init pdev_record_assignments(struct pci_pbm_info *pbm, struct pci_dev *pdev) { @@ -400,19 +387,23 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm, pbm->parent->resource_adjust(pdev, res, root); if (request_resource(root, res) < 0) { + int rnum; + /* OK, there is some conflict. But this is fine * since we'll reassign it in the fixup pass. * - * We notify the user that OBP made an error if it - * is a case we don't expect. + * Do not print the warning for ROM resources + * as such a conflict is quite common and + * harmless as the ROM bar is disabled. */ - if (!pdev_resource_collisions_expected(pdev)) { - printk(KERN_ERR "PCI: Address space collision on region %ld " + rnum = (res - &pdev->resource[0]); + if (rnum != PCI_ROM_RESOURCE) + printk(KERN_ERR "PCI: Resource collision, " + "region %d " "[%016lx:%016lx] of device %s\n", - (res - &pdev->resource[0]), + rnum, res->start, res->end, pci_name(pdev)); - } } } } diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 6ec569828c2..de7f7850a84 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1196,7 +1196,7 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p, &pbm->mem_space); } -static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin) +static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end) { struct pci_pbm_info *pbm; struct device_node *node; @@ -1261,6 +1261,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp node = node->sibling; } if (simbas_found == 0) { + struct resource *rp; + /* No APBs underneath, probably this is a hummingbird * system. */ @@ -1302,8 +1304,10 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; pbm->io_space.flags = IORESOURCE_IO; - pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE; - pbm->mem_space.end = pbm->mem_space.start + (unsigned long)dma_begin - 1UL; + pbm->mem_space.start = + (p->pbm_A.controller_regs + SABRE_MEMSPACE); + pbm->mem_space.end = + (pbm->mem_space.start + ((1UL << 32UL) - 1UL)); pbm->mem_space.flags = IORESOURCE_MEM; if (request_resource(&ioport_resource, &pbm->io_space) < 0) { @@ -1315,6 +1319,17 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp prom_halt(); } + rp = kmalloc(sizeof(*rp), GFP_KERNEL); + if (!rp) { + prom_printf("Cannot allocate IOMMU resource.\n"); + prom_halt(); + } + rp->name = "IOMMU"; + rp->start = pbm->mem_space.start + (unsigned long) dma_start; + rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL; + rp->flags = IORESOURCE_BUSY; + request_resource(&pbm->mem_space, rp); + pci_register_legacy_regions(&pbm->io_space, &pbm->mem_space); } @@ -1450,5 +1465,5 @@ void sabre_init(struct device_node *dp, char *model_name) /* * Look for APB underneath. */ - sabre_pbm_init(p, dp, vdma[0]); + sabre_pbm_init(p, dp, vdma[0], vdma[1]); } -- GitLab From b48194bf0dc0f8e2b617fab10df885513fbb3bad Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Tue, 17 Oct 2006 19:11:31 -0700 Subject: [PATCH 1389/1619] [SPARC]: Fix some section mismatch warnings in sparc drivers. Signed-off-by: Ben Collins Signed-off-by: David S. Miller --- drivers/net/myri_code.h | 8 ++++---- drivers/net/myri_sbus.c | 4 ++-- drivers/net/sunbmac.c | 2 +- drivers/scsi/qlogicpti.c | 2 +- drivers/scsi/qlogicpti_asm.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h index e21ec9b2c70..ba7b8652c50 100644 --- a/drivers/net/myri_code.h +++ b/drivers/net/myri_code.h @@ -1,8 +1,8 @@ /* This is the Myrinet MCP code for LANai4.x */ /* Generated by cat $MYRI_HOME/lib/lanai/mcp4.dat > myri_code4.h */ -static unsigned int lanai4_code_off = 0x0000; /* half-word offset */ -static unsigned char lanai4_code[76256] __initdata = { +static unsigned int __devinitdata lanai4_code_off = 0x0000; /* half-word offset */ +static unsigned char __devinitdata lanai4_code[76256] = { 0xF2,0x0E, 0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, @@ -4774,8 +4774,8 @@ static unsigned char lanai4_code[76256] __initdata = { /* This is the LANai data */ -static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */ -static unsigned char lanai4_data[20472] __initdata; +static unsigned int __devinitdata lanai4_data_off = 0x94F0; /* half-word offset */ +static unsigned char __devinitdata lanai4_data[20472]; #ifdef SYMBOL_DEFINES_COMPILED diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 466b484c9fa..7747bfd99f9 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -168,7 +168,7 @@ static int myri_do_handshake(struct myri_eth *mp) return 0; } -static int myri_load_lanai(struct myri_eth *mp) +static int __devinit myri_load_lanai(struct myri_eth *mp) { struct net_device *dev = mp->dev; struct myri_shmem __iomem *shmem = mp->shmem; @@ -891,7 +891,7 @@ static void dump_eeprom(struct myri_eth *mp) } #endif -static int __init myri_ether_init(struct sbus_dev *sdev) +static int __devinit myri_ether_init(struct sbus_dev *sdev) { static int num; static unsigned version_printed; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 6439b0cef1e..18f88853e1e 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -42,7 +42,7 @@ #define DRV_RELDATE "11/24/03" #define DRV_AUTHOR "David S. Miller (davem@redhat.com)" -static char version[] __initdata = +static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; MODULE_VERSION(DRV_VERSION); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index ed58bb48988..9b827ceec50 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host) #define PTI_RESET_LIMIT 400 -static int __init qlogicpti_load_firmware(struct qlogicpti *qpti) +static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) { struct Scsi_Host *host = qpti->qhost; unsigned short csum = 0; diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c index 1545b30681b..19aa84f4601 100644 --- a/drivers/scsi/qlogicpti_asm.c +++ b/drivers/scsi/qlogicpti_asm.c @@ -1,5 +1,5 @@ /* Version 1.31.00 ISP1000 Initiator RISC firmware */ -unsigned short sbus_risc_code01[] __initdata = { +unsigned short sbus_risc_code01[] __devinitdata = { 0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, @@ -1157,4 +1157,4 @@ unsigned short sbus_risc_code01[] __initdata = { 0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c, 0x92a7 }; -unsigned short sbus_risc_code_length01 = 0x2419; +unsigned short __devinitdata sbus_risc_code_length01 = 0x2419; -- GitLab From 872ec6484720e7ddfebb8e15c232fa7ca158ef2e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Oct 2006 19:19:08 -0700 Subject: [PATCH 1390/1619] [SPARC] {bbc_,}envctrl: Use call_usermodehelper(). We should not be calling kernel_execve() directly and this causes module build failures because kernel_execve() is not exported to modules. Signed-off-by: David S. Miller --- drivers/sbus/char/bbc_envctrl.c | 4 ++-- drivers/sbus/char/envctrl.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 0d3660c28f7..a54e4140683 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -5,8 +5,8 @@ */ #include -#include #include +#include #include #include @@ -195,7 +195,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 (kernel_execve("/sbin/shutdown", argv, envp) < 0) + if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0) printk(KERN_CRIT "envctrl: shutdown execution failed\n"); } diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 6b6a855f379..fff4660cdf9 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -976,7 +976,7 @@ static void envctrl_do_shutdown(void) inprog = 1; printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); - ret = kernel_execve("/sbin/shutdown", argv, envp); + ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0); if (ret < 0) { printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); inprog = 0; /* unlikely to succeed, but we could try again */ -- GitLab From 9550e59c4587f637d9aa34689e32eea460e6f50c Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Tue, 17 Oct 2006 19:21:48 -0700 Subject: [PATCH 1391/1619] [SPARC]: Add sparc profiling support This patch adds profiling support to the sparc architecture. It is a copy of the sparc64 implementation. Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/Kconfig | 7 +++++++ arch/sparc/Makefile | 2 ++ arch/sparc/kernel/time.c | 2 ++ arch/sparc/oprofile/Kconfig | 17 +++++++++++++++++ arch/sparc/oprofile/Makefile | 9 +++++++++ arch/sparc/oprofile/init.c | 23 +++++++++++++++++++++++ 6 files changed, 60 insertions(+) create mode 100644 arch/sparc/oprofile/Kconfig create mode 100644 arch/sparc/oprofile/Makefile create mode 100644 arch/sparc/oprofile/init.c diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 9431e967aa4..2f96610a83e 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -289,6 +289,13 @@ endmenu source "fs/Kconfig" +menu "Instrumentation Support" + depends on EXPERIMENTAL + +source "arch/sparc/oprofile/Kconfig" + +endmenu + source "arch/sparc/Kconfig.debug" source "security/Kconfig" diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 4cdbb2d59ed..f33c3817f01 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -30,6 +30,8 @@ HEAD_Y := $(head-y) core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/ libs-y += arch/sparc/prom/ arch/sparc/lib/ +drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/ + # Export what is needed by arch/sparc/boot/Makefile # Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-) INIT_Y := $(patsubst %/, %/built-in.o, $(init-y)) diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 7dcd1a16c6e..6c7aa51b590 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -95,6 +95,8 @@ unsigned long profile_pc(struct pt_regs *regs) return pc; } +EXPORT_SYMBOL(profile_pc); + __volatile__ unsigned int *master_l10_counter; __volatile__ unsigned int *master_l10_limit; diff --git a/arch/sparc/oprofile/Kconfig b/arch/sparc/oprofile/Kconfig new file mode 100644 index 00000000000..d8a84088471 --- /dev/null +++ b/arch/sparc/oprofile/Kconfig @@ -0,0 +1,17 @@ +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + diff --git a/arch/sparc/oprofile/Makefile b/arch/sparc/oprofile/Makefile new file mode 100644 index 00000000000..e9feca1ca28 --- /dev/null +++ b/arch/sparc/oprofile/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) init.o diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c new file mode 100644 index 00000000000..9ab815b95b5 --- /dev/null +++ b/arch/sparc/oprofile/init.c @@ -0,0 +1,23 @@ +/** + * @file init.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include + +int __init oprofile_arch_init(struct oprofile_operations * ops) +{ + return -ENODEV; +} + + +void oprofile_arch_exit(void) +{ +} -- GitLab From f6d7b8a7c9e21a58890a8532143e241409b78664 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 17 Oct 2006 19:23:23 -0700 Subject: [PATCH 1392/1619] [SPARC]: Sparc compilation fix with floppy enabled This patch fixes a typo to make kernel compilable when floppy driver for Sparc is build. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller --- arch/sparc/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index b3b6680a2a3..c8cb211b907 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -351,7 +351,7 @@ void handler_irq(int irq, struct pt_regs * regs) } #ifdef CONFIG_BLK_DEV_FD -extern void floppy_interrupt(int irq, void *dev_id) +extern void floppy_interrupt(int irq, void *dev_id); void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) { -- GitLab From 73ed9a86cd77b6a3b46beec8d353ac3b0d4f50c1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Oct 2006 19:29:41 -0700 Subject: [PATCH 1393/1619] [SPARC64]: Update defconfig. Signed-off-by: David S. Miller --- arch/sparc64/defconfig | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index dcae559879a..2f4612fa81f 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19-rc1 -# Thu Oct 5 02:08:41 2006 +# Linux kernel version: 2.6.19-rc2 +# Tue Oct 17 19:29:20 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -217,6 +217,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m CONFIG_INET6_XFRM_MODE_TUNNEL=m CONFIG_INET6_XFRM_MODE_BEET=m # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m CONFIG_IPV6_TUNNEL=m # CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MULTIPLE_TABLES is not set @@ -333,6 +334,12 @@ CONFIG_CDROM_PKTCDVD_BUFFERS=8 CONFIG_CDROM_PKTCDVD_WCACHE=y CONFIG_ATA_OVER_ETH=m +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + # # ATA/ATAPI/MFM/RLL support # @@ -728,7 +735,6 @@ CONFIG_RTC=y # TPM devices # # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set # # I2C support @@ -841,11 +847,6 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set -# -# Misc devices -# -# CONFIG_TIFM_CORE is not set - # # Multimedia devices # @@ -1104,7 +1105,6 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set -# CONFIG_USB_TRANCEVIBRATOR is not set # # USB Imaging devices @@ -1150,6 +1150,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set # CONFIG_USB_TEST is not set # @@ -1234,6 +1235,7 @@ CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y @@ -1361,10 +1363,6 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set -# -# Distributed Lock Manager -# - # # Instrumentation Support # @@ -1399,6 +1397,7 @@ CONFIG_DEBUG_FS=y # CONFIG_DEBUG_LIST is not set # CONFIG_UNWIND_INFO is not set CONFIG_FORCED_INLINING=y +# CONFIG_HEADERS_CHECK is not set # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_LKDTM is not set # CONFIG_DEBUG_STACK_USAGE is not set -- GitLab From 5cacb9f8bca1ac67cc1f933a4e89b5130ffd1460 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:24:30 -0400 Subject: [PATCH 1394/1619] [alim7101] Add pci dev table for auto module loading. Also fixes comment for nowayout module param. Signed-off-by: Ben Collins --- drivers/char/watchdog/alim7101_wdt.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c index 5948863b592..bf25d0a55a9 100644 --- a/drivers/char/watchdog/alim7101_wdt.c +++ b/drivers/char/watchdog/alim7101_wdt.c @@ -77,7 +77,8 @@ static struct pci_dev *alim7101_pmu; static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")"); /* * Whack the dog @@ -415,6 +416,16 @@ err_out: module_init(alim7101_wdt_init); module_exit(alim7101_wdt_unload); +static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl); + MODULE_AUTHOR("Steve Hill"); MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver"); MODULE_LICENSE("GPL"); -- GitLab From 4596c75c23dde2623cbeec69357d5eb13d28387e Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:33:03 -0400 Subject: [PATCH 1395/1619] [mv643xx] Add pci device table for auto module loading. Signed-off-by: Ben Collins --- drivers/net/mv643xx_eth.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9997081c6da..a4f861bf32d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1557,6 +1557,12 @@ static void __exit mv643xx_cleanup_module(void) module_init(mv643xx_init_module); module_exit(mv643xx_cleanup_module); +static struct pci_device_id pci_marvell_mv64360[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) }, + {} +}; +MODULE_DEVICE_TABLE(pci, pci_marvell_mv64360); + MODULE_LICENSE("GPL"); MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" " and Dale Farnsworth"); -- GitLab From 745b5715fafccc8f0f992a7cccdd1eb2b1f5d23f Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:36:57 -0400 Subject: [PATCH 1396/1619] [BusLogic] Add pci dev table for auto module loading. Signed-off-by: Ben Collins --- drivers/scsi/BusLogic.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 7c59bba9879..cdd03372478 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3600,5 +3600,16 @@ static void __exit BusLogic_exit(void) __setup("BusLogic=", BusLogic_Setup); +static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl); + module_init(BusLogic_init); module_exit(BusLogic_exit); -- GitLab From 3985b977441f857404bb604a4b15911bbb0b9c5b Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:38:41 -0400 Subject: [PATCH 1397/1619] [fdomain] Add pci dev table for module auto loading. Signed-off-by: Ben Collins --- drivers/scsi/fdomain.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 72794a7b6dc..65e6e7b7ba0 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -1736,6 +1736,15 @@ struct scsi_host_template fdomain_driver_template = { }; #ifndef PCMCIA + +static struct pci_device_id fdomain_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { } +}; +MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl); + #define driver_template fdomain_driver_template #include "scsi_module.c" + #endif -- GitLab From 012887327875915f76a6208e81fe0d67a682ec15 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:40:57 -0400 Subject: [PATCH 1398/1619] [initio] Add pci dev table for module auto loading. Signed-off-by: Ben Collins --- drivers/scsi/initio.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 911f2ff4a1f..afed293dd7b 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -142,8 +142,6 @@ #define i91u_MAXQUEUE 2 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a" -#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */ -#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */ #define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */ #define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */ #define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */ @@ -171,13 +169,16 @@ static int setup_debug = 0; static void i91uSCBPost(BYTE * pHcb, BYTE * pScb); -static const PCI_ID i91u_pci_devices[] = { - { INI_VENDOR_ID, I950_DEVICE_ID }, - { INI_VENDOR_ID, I940_DEVICE_ID }, - { INI_VENDOR_ID, I935_DEVICE_ID }, - { INI_VENDOR_ID, I920_DEVICE_ID }, - { DMX_VENDOR_ID, I920_DEVICE_ID }, +/* PCI Devices supported by this driver */ +static struct pci_device_id i91u_pci_devices[] __devinitdata = { + { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } }; +MODULE_DEVICE_TABLE(pci, i91u_pci_devices); #define DEBUG_INTERRUPT 0 #define DEBUG_QUEUE 0 @@ -2771,7 +2772,7 @@ static int tul_NewReturnNumberOfAdapters(void) for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++) { - while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) { + while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) { if (pci_enable_device(pDev)) continue; pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue); -- GitLab From d77f09e51f5793583ede9733a93bd31a324d051c Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:45:30 -0400 Subject: [PATCH 1399/1619] [ixj] Add pci dev table for module auto loading. Signed-off-by: Ben Collins --- drivers/telephony/ixj.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index f6b2948ab28..1b601b6cf2a 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -284,6 +284,14 @@ static int samplerate = 100; module_param(ixjdebug, int, 0); +static struct pci_device_id ixj_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, ixj_pci_tbl); + /************************************************************************ * * ixjdebug meanings are now bit mapped instead of level based @@ -7683,7 +7691,8 @@ static int __init ixj_probe_pci(int *cnt) IXJ *j = NULL; for (i = 0; i < IXJMAX - *cnt; i++) { - pci = pci_find_device(0x15E2, 0x0500, pci); + pci = pci_find_device(PCI_VENDOR_ID_QUICKNET, + PCI_DEVICE_ID_QUICKNET_XJ, pci); if (!pci) break; -- GitLab From d57cdcffe1180cf9b8d1fce048f80d8c6b159827 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:47:37 -0400 Subject: [PATCH 1400/1619] [hid-core] TurboX Keyboard needs NOGET quirk. Signed-off-by: Ben Collins --- drivers/usb/input/hid-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index feabda73a6f..45f44fe33bf 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1391,6 +1391,9 @@ void hid_close(struct hid_device *hid) #define USB_VENDOR_ID_PANJIT 0x134c +#define USB_VENDOR_ID_TURBOX 0x062a +#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 + /* * Initialize all reports */ @@ -1778,6 +1781,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, + { 0, 0 } }; -- GitLab From 4938d3f4f8f1ffd744fa3626df8085118aeb1d79 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:49:31 -0400 Subject: [PATCH 1401/1619] [controlfb] Ifdef for when CONFIG_NVRAM isn't enabled. Signed-off-by: Ben Collins --- drivers/video/controlfb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 8cc6c0e2d27..04c6d928189 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -415,13 +415,15 @@ static int __init init_control(struct fb_info_control *p) full = p->total_vram == 0x400000; /* Try to pick a video mode out of NVRAM if we have one. */ +#ifdef CONFIG_NVRAM if (default_cmode == CMODE_NVRAM){ cmode = nvram_read_byte(NV_CMODE); if(cmode < CMODE_8 || cmode > CMODE_32) cmode = CMODE_8; } else +#endif cmode=default_cmode; - +#ifdef CONFIG_NVRAM if (default_vmode == VMODE_NVRAM) { vmode = nvram_read_byte(NV_VMODE); if (vmode < 1 || vmode > VMODE_MAX || @@ -432,7 +434,9 @@ static int __init init_control(struct fb_info_control *p) if (control_mac_modes[vmode - 1].m[full] < cmode) vmode = VMODE_640_480_60; } - } else { + } else +#endif + { vmode=default_vmode; if (control_mac_modes[vmode - 1].m[full] < cmode) { if (cmode > CMODE_8) -- GitLab From b023429ca30fc18b17a7b3e279b55bd652e9a989 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:50:49 -0400 Subject: [PATCH 1402/1619] [igafb] Add pci dev table for module auto loading. Signed-off-by: Ben Collins --- drivers/video/igafb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 67f384f8675..e6df492c22a 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -573,3 +573,10 @@ int __init igafb_setup(char *options) module_init(igafb_init); MODULE_LICENSE("GPL"); +static struct pci_device_id igafb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, igafb_pci_tbl); -- GitLab From f3f6f9aaced9c8453ef45956a23295e5c2328124 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:52:48 -0400 Subject: [PATCH 1403/1619] [platinumfb] Ifdef for when CONFIG_NVRAM isn't enabled. Signed-off-by: Ben Collins --- drivers/video/platinumfb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 983be3ec234..fdb33cd21a2 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -339,11 +339,12 @@ static int __devinit platinum_init_fb(struct fb_info *info) sense = read_platinum_sense(pinfo); printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense); - if (default_vmode == VMODE_NVRAM) { +#ifdef CONFIG_NVRAM default_vmode = nvram_read_byte(NV_VMODE); if (default_vmode <= 0 || default_vmode > VMODE_MAX || !platinum_reg_init[default_vmode-1]) +#endif default_vmode = VMODE_CHOOSE; } if (default_vmode == VMODE_CHOOSE) { @@ -351,8 +352,10 @@ static int __devinit platinum_init_fb(struct fb_info *info) } if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; +#ifdef CONFIG_NVRAM if (default_cmode == CMODE_NVRAM) default_cmode = nvram_read_byte(NV_CMODE); +#endif if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; /* -- GitLab From 996f324767fd24b7cc682801277add2a4f276635 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:53:37 -0400 Subject: [PATCH 1404/1619] [valkyriefb] Ifdef for when CONFIG_NVRAM isn't enabled. Signed-off-by: Ben Collins --- drivers/video/valkyriefb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 47f27924a7d..06fc19a6119 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -284,7 +284,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense); /* Try to pick a video mode out of NVRAM if we have one. */ -#ifndef CONFIG_MAC +#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM) if (default_vmode == VMODE_NVRAM) { default_vmode = nvram_read_byte(NV_VMODE); if (default_vmode <= 0 @@ -297,7 +297,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) default_vmode = mac_map_monitor_sense(p->sense); if (!valkyrie_reg_init[default_vmode - 1]) default_vmode = VMODE_640_480_67; -#ifndef CONFIG_MAC +#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM) if (default_cmode == CMODE_NVRAM) default_cmode = nvram_read_byte(NV_CMODE); #endif -- GitLab From 74d919465a93b6c2b928b29a8ed3e5e41adbfa93 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:55:54 -0400 Subject: [PATCH 1405/1619] [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(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f069df24546..f3a168f3c9d 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 -- GitLab From 1df23957ba2da6eb8c7a5c2ad7bb1d4732132873 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Wed, 18 Oct 2006 18:30:41 +0200 Subject: [PATCH 1406/1619] [S390] fix vmlinux link when CONFIG_SYSIPC=n Fix the following compile error: CC init/version.o LD init/built-in.o LD .tmp_vmlinux1 arch/s390/kernel/built-in.o(.text+0xdba4): In function `sys32_ipc': : undefined reference to `compat_sys_semtimedop' arch/s390/kernel/built-in.o(.text+0xdbee): In function `sys32_ipc': : undefined reference to `compat_sys_semctl' arch/s390/kernel/built-in.o(.text+0xdc08): In function `sys32_ipc': : undefined reference to `compat_sys_msgsnd' arch/s390/kernel/built-in.o(.text+0xdc30): In function `sys32_ipc': : undefined reference to `compat_sys_msgrcv' arch/s390/kernel/built-in.o(.text+0xdc58): In function `sys32_ipc': : undefined reference to `compat_sys_msgctl' arch/s390/kernel/built-in.o(.text+0xdc76): In function `sys32_ipc': : undefined reference to `compat_sys_shmat' arch/s390/kernel/built-in.o(.text+0xdcb0): In function `sys32_ipc': : undefined reference to `compat_sys_shmctl' make: *** [.tmp_vmlinux1] Error 1 Signed-off-by: Cedric Le Goater Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/compat_linux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index e15e1489aef..2001767e1dc 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -295,6 +295,7 @@ static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i) * * This is really horribly ugly. */ +#ifdef CONFIG_SYSVIPC asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr) { if (call >> 16) /* hack for backward compatibility */ @@ -338,6 +339,7 @@ asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr) return -ENOSYS; } +#endif asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low) { -- GitLab From 8b42f5c20251060cb1ab875459fe66ad7bb92cbd Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 18 Oct 2006 18:30:43 +0200 Subject: [PATCH 1407/1619] [S390] cio: invalid device operational notification Reset device operational notification flag when channel paths become unavailable during path verification. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index fcaf28d7b4e..de3d0857db9 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -578,9 +578,13 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) } break; case -ETIME: + /* Reset oper notify indication after verify error. */ + cdev->private->flags.donotify = 0; ccw_device_done(cdev, DEV_STATE_BOXED); break; default: + /* Reset oper notify indication after verify error. */ + cdev->private->flags.donotify = 0; PREPARE_WORK(&cdev->private->kick_work, ccw_device_nopath_notify, cdev); queue_work(ccw_device_notify_work, &cdev->private->kick_work); -- GitLab From f5956f84072804712cb7b663c5c64e9800180833 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 18 Oct 2006 18:30:45 +0200 Subject: [PATCH 1408/1619] [S390] Wire up epoll_pwait syscall. Signed-off-by: Heiko Carstens --- arch/s390/kernel/syscalls.S | 1 + include/asm-s390/unistd.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index e59baec5652..a4ceae3dbcf 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -320,3 +320,4 @@ SYSCALL(sys_tee,sys_tee,sys_tee_wrapper) SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper) NI_SYSCALL /* 310 sys_move_pages */ SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper) +SYSCALL(sys_epoll_pwait,sys_epoll_pwait,sys_ni_syscall) diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index a19238cbcff..71d3c21b84f 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -249,8 +249,9 @@ #define __NR_vmsplice 309 /* Number 310 is reserved for new sys_move_pages */ #define __NR_getcpu 311 +#define __NR_epoll_pwait 312 -#define NR_syscalls 312 +#define NR_syscalls 313 /* * There are some system calls that are not present on 64 bit, some -- GitLab From 85a4aa64a85a8bd19b86887f70b13a27a363030d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 18 Oct 2006 18:30:47 +0200 Subject: [PATCH 1409/1619] [S390] cio: sch_no -> schid.sch_no conversion. Overlooked one sch_no -> schid.sch_no conversion. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 0648ce5bb68..476aa1da5cb 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -3529,7 +3529,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags, #ifdef CONFIG_QDIO_DEBUG char dbf_text[20]; - sprintf(dbf_text,"doQD%04x",cdev->private->sch_no); + sprintf(dbf_text,"doQD%04x",cdev->private->schid.sch_no); QDIO_DBF_TEXT3(0,trace,dbf_text); #endif /* CONFIG_QDIO_DEBUG */ -- GitLab From 2c91971f84be168a35f937dd6c61e56e492b2185 Mon Sep 17 00:00:00 2001 From: Melissa Howland Date: Wed, 18 Oct 2006 18:30:49 +0200 Subject: [PATCH 1410/1619] [S390] monwriter find header logic. Fix logic for finding matching buffers. Signed-off-by: Melissa Howland Signed-off-by: Martin Schwidefsky --- drivers/s390/char/monwriter.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index abd02ed501c..b9b0fc3f812 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -73,12 +73,15 @@ static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, struct mon_buf *entry, *next; list_for_each_entry_safe(entry, next, &monpriv->list, list) - if (entry->hdr.applid == monhdr->applid && + if ((entry->hdr.mon_function == monhdr->mon_function || + monhdr->mon_function == MONWRITE_STOP_INTERVAL) && + entry->hdr.applid == monhdr->applid && entry->hdr.record_num == monhdr->record_num && entry->hdr.version == monhdr->version && entry->hdr.release == monhdr->release && entry->hdr.mod_level == monhdr->mod_level) return entry; + return NULL; } @@ -92,7 +95,9 @@ static int monwrite_new_hdr(struct mon_private *monpriv) monhdr->mon_function > MONWRITE_START_CONFIG || monhdr->hdrlen != sizeof(struct monwrite_hdr)) return -EINVAL; - monbuf = monwrite_find_hdr(monpriv, monhdr); + monbuf = NULL; + if (monhdr->mon_function != MONWRITE_GEN_EVENT) + monbuf = monwrite_find_hdr(monpriv, monhdr); if (monbuf) { if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) { monhdr->datalen = monbuf->hdr.datalen; @@ -104,7 +109,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) kfree(monbuf); monbuf = NULL; } - } else { + } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) { if (mon_buf_count >= mon_max_bufs) return -ENOSPC; monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL); @@ -118,7 +123,8 @@ static int monwrite_new_hdr(struct mon_private *monpriv) } monbuf->hdr = *monhdr; list_add_tail(&monbuf->list, &monpriv->list); - mon_buf_count++; + if (monhdr->mon_function != MONWRITE_GEN_EVENT) + mon_buf_count++; } monpriv->current_buf = monbuf; return 0; -- GitLab From 833774849d50a59f58e9bdfc3d9c88e682b3596d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 18 Oct 2006 18:30:51 +0200 Subject: [PATCH 1411/1619] [S390] Fix pte type checking. handle_pte_fault uses pte_present, pte_none and pte_file to find out the type of a pte. That is done without holding the page table lock. This clashes with the way how ptep_clear_flush removes active page table entries from the system. First the ipte instruction is used to invalidate the pte and remove all plt entries for the page. The ipte sets the hardware invalid bit without changing any other bit. After the ipte finished the pte is cleared. A concurrent fault can observe the the previously valid pte with the invalid bit set. With the current encoding of the different pte types an invalidated read-only pte can be misinterpreted as a swap-pte. Signed-off-by: Martin Schwidefsky --- include/asm-s390/pgtable.h | 50 ++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 519f0a5ff18..36bb6dacf00 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -200,18 +200,45 @@ extern char empty_zero_page[PAGE_SIZE]; */ /* Hardware bits in the page table entry */ -#define _PAGE_RO 0x200 /* HW read-only */ -#define _PAGE_INVALID 0x400 /* HW invalid */ +#define _PAGE_RO 0x200 /* HW read-only bit */ +#define _PAGE_INVALID 0x400 /* HW invalid bit */ +#define _PAGE_SWT 0x001 /* SW pte type bit t */ +#define _PAGE_SWX 0x002 /* SW pte type bit x */ -/* Mask and six different types of pages. */ -#define _PAGE_TYPE_MASK 0x601 +/* Six different types of pages. */ #define _PAGE_TYPE_EMPTY 0x400 #define _PAGE_TYPE_NONE 0x401 -#define _PAGE_TYPE_SWAP 0x600 -#define _PAGE_TYPE_FILE 0x601 +#define _PAGE_TYPE_SWAP 0x403 +#define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ #define _PAGE_TYPE_RO 0x200 #define _PAGE_TYPE_RW 0x000 +/* + * PTE type bits are rather complicated. handle_pte_fault uses pte_present, + * pte_none and pte_file to find out the pte type WITHOUT holding the page + * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to + * invalidate a given pte. ipte sets the hw invalid bit and clears all tlbs + * for the page. The page table entry is set to _PAGE_TYPE_EMPTY afterwards. + * This change is done while holding the lock, but the intermediate step + * of a previously valid pte with the hw invalid bit set can be observed by + * handle_pte_fault. That makes it necessary that all valid pte types with + * the hw invalid bit set must be distinguishable from the four pte types + * empty, none, swap and file. + * + * irxt ipte irxt + * _PAGE_TYPE_EMPTY 1000 -> 1000 + * _PAGE_TYPE_NONE 1001 -> 1001 + * _PAGE_TYPE_SWAP 1011 -> 1011 + * _PAGE_TYPE_FILE 11?1 -> 11?1 + * _PAGE_TYPE_RO 0100 -> 1100 + * _PAGE_TYPE_RW 0000 -> 1000 + * + * pte_none is true for bits combinations 1000, 1100 + * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 + * pte_file is true for bits combinations 1101, 1111 + * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid. + */ + #ifndef __s390x__ /* Bits in the segment table entry */ @@ -365,18 +392,21 @@ static inline int pmd_bad(pmd_t pmd) static inline int pte_none(pte_t pte) { - return (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_EMPTY; + return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT); } static inline int pte_present(pte_t pte) { - return !(pte_val(pte) & _PAGE_INVALID) || - (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_NONE; + unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT | _PAGE_SWX; + return (pte_val(pte) & mask) == _PAGE_TYPE_NONE || + (!(pte_val(pte) & _PAGE_INVALID) && + !(pte_val(pte) & _PAGE_SWT)); } static inline int pte_file(pte_t pte) { - return (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_FILE; + unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT; + return (pte_val(pte) & mask) == _PAGE_TYPE_FILE; } #define pte_same(a,b) (pte_val(a) == pte_val(b)) -- GitLab From 867dcd0f32b125f45a663f9374a36fb21193ab21 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 18 Oct 2006 18:30:53 +0200 Subject: [PATCH 1412/1619] [S390] dasd: clean up timer. Clean up dasd timer when when a dasd device is set offline. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d0647d116ea..79ffef6bfaf 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -203,6 +203,7 @@ dasd_state_basic_to_known(struct dasd_device * device) rc = dasd_flush_ccw_queue(device, 1); if (rc) return rc; + dasd_clear_timer(device); DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); if (device->debug_area != NULL) { -- GitLab From 9b10fe5b70878fb4b7e3e1b300f1bff0c73d4e2e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 18 Oct 2006 18:30:55 +0200 Subject: [PATCH 1413/1619] [S390] cio: update documentation. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- Documentation/s390/CommonIO | 2 +- Documentation/s390/cds.txt | 52 +++++++++++++---------------- Documentation/s390/driver-model.txt | 3 ++ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index 59d1166d41e..d684a6ac69a 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO @@ -66,7 +66,7 @@ Command line parameters When a device is un-ignored, device recognition and sensing is performed and the device driver will be notified if possible, so the device will become - available to the system. + available to the system. Note that un-ignoring is performed asynchronously. You can also add ranges of devices to be ignored by piping to /proc/cio_ignore; "add , , ..." will ignore the diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index d80e5733827..32a96cc3921 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt @@ -174,14 +174,10 @@ read_dev_chars() - Read Device Characteristics This routine returns the characteristics for the device specified. -The function is meant to be called with an irq handler in place; that is, +The function is meant to be called with the device already enabled; that is, at earliest during set_online() processing. -While the request is processed synchronously, the device interrupt -handler is called for final ending status. In case of error situations the -interrupt handler may recover appropriately. The device irq handler can -recognize the corresponding interrupts by the interruption parameter be -0x00524443. The ccw_device must not be locked prior to calling read_dev_chars(). +The ccw_device must not be locked prior to calling read_dev_chars(). The function may be called enabled or disabled. @@ -410,26 +406,7 @@ individual flag meanings. Usage Notes : -Prior to call ccw_device_start() the device driver must assure disabled state, -i.e. the I/O mask value in the PSW must be disabled. This can be accomplished -by calling local_save_flags( flags). The current PSW flags are preserved and -can be restored by local_irq_restore( flags) at a later time. - -If the device driver violates this rule while running in a uni-processor -environment an interrupt might be presented prior to the ccw_device_start() -routine returning to the device driver main path. In this case we will end in a -deadlock situation as the interrupt handler will try to obtain the irq -lock the device driver still owns (see below) ! - -The driver must assure to hold the device specific lock. This can be -accomplished by - -(i) spin_lock(get_ccwdev_lock(cdev)), or -(ii) spin_lock_irqsave(get_ccwdev_lock(cdev), flags) - -Option (i) should be used if the calling routine is running disabled for -I/O interrupts (see above) already. Option (ii) obtains the device gate und -puts the CPU into I/O disabled state by preserving the current PSW flags. +ccw_device_start() must be called disabled and with the ccw device lock held. The device driver is allowed to issue the next ccw_device_start() call from within its interrupt handler already. It is not required to schedule a @@ -488,7 +465,7 @@ int ccw_device_resume(struct ccw_device *cdev); cdev - ccw_device the resume operation is requested for -The resume_IO() function returns: +The ccw_device_resume() function returns: 0 - suspended channel program is resumed -EBUSY - status pending @@ -507,6 +484,8 @@ a long-running channel program or the device might require to initially issue a halt subchannel (HSCH) I/O command. For those purposes the ccw_device_halt() command is provided. +ccw_device_halt() must be called disabled and with the ccw device lock held. + int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm); @@ -517,7 +496,7 @@ intparm : interruption parameter; value is only used if no I/O The ccw_device_halt() function returns : - 0 - successful completion or request successfully initiated + 0 - request successfully initiated -EBUSY - the device is currently busy, or status pending. -ENODEV - cdev invalid. -EINVAL - The device is not operational or the ccw device is not online. @@ -533,6 +512,23 @@ can then perform an appropriate action. Prior to interrupt of an outstanding read to a network device (with or without PCI flag) a ccw_device_halt() is required to end the pending operation. +ccw_device_clear() - Terminage I/O Request Processing + +In order to terminate all I/O processing at the subchannel, the clear subchannel +(CSCH) command is used. It can be issued via ccw_device_clear(). + +ccw_device_clear() must be called disabled and with the ccw device lock held. + +int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm); + +cdev: ccw_device the clear operation is requested for +intparm: interruption parameter (see ccw_device_halt()) + +The ccw_device_clear() function returns: + + 0 - request successfully initiated +-ENODEV - cdev invalid +-EINVAL - The device is not operational or the ccw device is not online. Miscellaneous Support Routines diff --git a/Documentation/s390/driver-model.txt b/Documentation/s390/driver-model.txt index 62c082387ae..77bf450ec39 100644 --- a/Documentation/s390/driver-model.txt +++ b/Documentation/s390/driver-model.txt @@ -239,6 +239,9 @@ status - Can be 'online' or 'offline'. type - The physical type of the channel path. +shared - Whether the channel path is shared. + +cmg - The channel measurement group. 3. System devices ----------------- -- GitLab From ce9b18f5cdd628196ca13bb783e8dcd5ad29ceaa Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 18 Oct 2006 18:30:59 +0200 Subject: [PATCH 1414/1619] [S390] update default configuration Signed-off-by: Martin Schwidefsky --- arch/s390/defconfig | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index a3257398ea8..c313e9a9304 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18 -# Wed Oct 4 19:45:46 2006 +# Linux kernel version: 2.6.19-rc2 +# Wed Oct 18 17:11:10 2006 # CONFIG_MMU=y CONFIG_LOCKDEP_SUPPORT=y @@ -211,6 +211,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=y CONFIG_INET6_XFRM_MODE_TUNNEL=y CONFIG_INET6_XFRM_MODE_BEET=y # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y # CONFIG_IPV6_TUNNEL is not set # CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MULTIPLE_TABLES is not set @@ -528,6 +529,7 @@ CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y @@ -645,10 +647,6 @@ CONFIG_MSDOS_PARTITION=y # # CONFIG_NLS is not set -# -# Distributed Lock Manager -# - # # Instrumentation Support # @@ -669,7 +667,6 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=17 -# CONFIG_DETECT_SOFTLOCKUP is not set # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set CONFIG_DEBUG_PREEMPT=y @@ -690,6 +687,7 @@ CONFIG_DEBUG_FS=y # CONFIG_FRAME_POINTER is not set # CONFIG_UNWIND_INFO is not set CONFIG_FORCED_INLINING=y +CONFIG_HEADERS_CHECK=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_LKDTM is not set -- GitLab From b4a1efffcf8070dbc7734f27da10ce49fb9f2a34 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 22 Sep 2006 12:52:37 -0700 Subject: [PATCH 1415/1619] shpchp: fix shpchp_wait_cmd in poll This patch fixes the problem that issuing SHPC command in poll mode always fails with the following message. shpchp: Command not completed in 2000 msec Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 54 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 4d8aee11913..446e9beff04 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -302,16 +302,43 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) add_timer(&php_ctlr->int_poll_timer); } +/* + * Returns 1 if SHPC finishes executing a command within 1 sec, + * otherwise returns 0. + */ +static inline int shpc_poll_ctrl_busy(struct controller *ctrl) +{ + int i; + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS); + + if (!(cmd_status & 0x1)) + return 1; + + /* Check every 0.1 sec for a total of 1 sec */ + for (i = 0; i < 10; i++) { + msleep(100); + cmd_status = shpc_readw(ctrl, CMD_STATUS); + if (!(cmd_status & 0x1)) + return 1; + } + + return 0; +} + static inline int shpc_wait_cmd(struct controller *ctrl) { int retval = 0; - unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000; - unsigned long timeout = msecs_to_jiffies(timeout_msec); - int rc = wait_event_interruptible_timeout(ctrl->queue, - !ctrl->cmd_busy, timeout); + unsigned long timeout = msecs_to_jiffies(1000); + int rc; + + if (shpchp_poll_mode) + rc = shpc_poll_ctrl_busy(ctrl); + else + rc = wait_event_interruptible_timeout(ctrl->queue, + !ctrl->cmd_busy, timeout); if (!rc) { retval = -EIO; - err("Command not completed in %d msec\n", timeout_msec); + err("Command not completed in 1000 msec\n"); } else if (rc < 0) { retval = -EINTR; info("Command was interrupted by a signal\n"); @@ -327,26 +354,15 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) u16 cmd_status; int retval = 0; u16 temp_word; - int i; DBG_ENTER_ROUTINE mutex_lock(&slot->ctrl->cmd_lock); - for (i = 0; i < 10; i++) { - cmd_status = shpc_readw(ctrl, CMD_STATUS); - - if (!(cmd_status & 0x1)) - break; - /* Check every 0.1 sec for a total of 1 sec*/ - msleep(100); - } - - cmd_status = shpc_readw(ctrl, CMD_STATUS); - - if (cmd_status & 0x1) { + if (!shpc_poll_ctrl_busy(ctrl)) { /* After 1 sec and and the controller is still busy */ - err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__); + err("%s : Controller is still busy after 1 sec.\n", + __FUNCTION__); retval = -EBUSY; goto out; } -- GitLab From 49ed2b4963cd00993eab518b820a6700f94f222d Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 22 Sep 2006 10:17:10 -0700 Subject: [PATCH 1416/1619] pciehp: fix improper info messages The slot number displayed in info messages would cause a confusion because those are displayed in several ways (decimal and hex). Furthermore, those slot number is not same as slot name (directory name). This patch fixes those improper info messages. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp.h | 8 +++--- drivers/pci/hotplug/pciehp_ctrl.c | 47 +++++++++++++++++++------------ 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index eaea9d36a1b..b71f774aca1 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -166,10 +166,10 @@ struct controller { * error Messages */ #define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_button_on "PCI slot #%d - powering on due to button press.\n" -#define msg_button_off "PCI slot #%d - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" +#define msg_button_on "PCI slot #%s - powering on due to button press.\n" +#define msg_button_off "PCI slot #%s - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n" /* controller functions */ extern int pciehp_event_start_thread (void); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 41290a106bd..f602b042adc 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -43,6 +43,11 @@ static int event_finished; static unsigned long pushbutton_pending; /* = 0 */ static unsigned long surprise_rm_pending; /* = 0 */ +static inline char *slot_name(struct slot *p_slot) +{ + return p_slot->hotplug_slot->name; +} + u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) { struct controller *ctrl = (struct controller *) inst_id; @@ -68,7 +73,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button pressed on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_BUTTON_PRESS; if ((p_slot->state == BLINKINGON_STATE) @@ -78,7 +83,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) * or hot-remove */ taskInfo->event_type = INT_BUTTON_CANCEL; - info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button cancel on Slot(%s)\n", slot_name(p_slot)); } else if ((p_slot->state == POWERON_STATE) || (p_slot->state == POWEROFF_STATE)) { /* Ignore if the slot is on power-on or power-off state; this @@ -86,7 +91,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) * hot-remove is undergoing */ taskInfo->event_type = INT_BUTTON_IGNORE; - info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button ignore on Slot(%s)\n", slot_name(p_slot)); } if (rc) @@ -122,13 +127,13 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) /* * Switch opened */ - info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Latch open on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_SWITCH_OPEN; } else { /* * Switch closed */ - info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Latch close on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_SWITCH_CLOSE; } @@ -166,13 +171,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) /* * Card Present */ - info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Card present on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Card not present on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_PRESENCE_OFF; } @@ -206,13 +211,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) /* * power fault Cleared */ - info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { /* * power fault */ - info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Power fault on Slot(%s)\n", slot_name(p_slot)); taskInfo->event_type = INT_POWER_FAULT; info("power fault bit %x set\n", hp_slot); } @@ -654,7 +659,7 @@ static void interrupt_event_handler(struct controller *ctrl) warn("Not a valid state\n"); return; } - info(msg_button_cancel, p_slot->number); + info(msg_button_cancel, slot_name(p_slot)); p_slot->state = STATIC_STATE; } /* ***********Button Pressed (No action on 1st press...) */ @@ -667,12 +672,12 @@ static void interrupt_event_handler(struct controller *ctrl) /* slot is on */ dbg("slot is on\n"); p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); + info(msg_button_off, slot_name(p_slot)); } else { /* slot is off */ dbg("slot is off\n"); p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); + info(msg_button_on, slot_name(p_slot)); } /* Wait for exclusive access to hardware */ @@ -760,14 +765,16 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: no adapter on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } if (MRL_SENS(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: latch open on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -776,7 +783,8 @@ int pciehp_enable_slot(struct slot *p_slot) if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: already enabled on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -811,7 +819,8 @@ int pciehp_disable_slot(struct slot *p_slot) if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: no adapter on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -820,7 +829,8 @@ int pciehp_disable_slot(struct slot *p_slot) if (MRL_SENS(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: latch open on slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -829,7 +839,8 @@ int pciehp_disable_slot(struct slot *p_slot) if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { - info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); + info("%s: already disabled slot(%s)\n", __FUNCTION__, + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } -- GitLab From dd5619cb4407e830a8921a93c949be37c81105b5 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 22 Sep 2006 10:17:29 -0700 Subject: [PATCH 1417/1619] pciehp - add missing locking This patch fixes the problem that system will panic if multiple power on/off operations are issued to the same slot in parallel. This problem can be easily reproduced by commands below. # while true; do echo 1 > power; echo 0 > power; done & # while true; do echo 1 > power; echo 0 > power; done & The cause is lack of locking for enable/disable operations. This patch fixes this problem. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp.h | 1 + drivers/pci/hotplug/pciehp_core.c | 6 ++-- drivers/pci/hotplug/pciehp_ctrl.c | 54 +++++++++++++++---------------- drivers/pci/hotplug/pciehp_hpc.c | 2 ++ 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index b71f774aca1..30f021c55fe 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -92,6 +92,7 @@ struct php_ctlr_state_s { struct controller { struct controller *next; struct mutex crit_sect; /* critical section mutex */ + struct mutex ctrl_lock; /* controller lock */ struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index c67b7c3f1dd..f93e81e2d2c 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ } /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ @@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) { /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); goto err_out_free_ctrl_slot; } else /* Wait for the command to complete */ @@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return 0; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index f602b042adc..c206a3d63b6 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -234,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return; } wait_for_ctrl_irq (ctrl); @@ -254,14 +254,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) if (ATTN_LED(ctrl->ctrlcap)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return; } wait_for_ctrl_irq (ctrl); } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); } /** @@ -284,13 +284,13 @@ static int board_added(struct slot *p_slot) ctrl->slot_device_offset, hp_slot); /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (POWER_CTRL(ctrl->ctrlcap)) { /* Power on slot */ rc = p_slot->hpc_ops->power_on_slot(p_slot); if (rc) { - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return -1; } @@ -306,7 +306,7 @@ static int board_added(struct slot *p_slot) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); /* Wait for ~1 second */ wait_for_ctrl_irq (ctrl); @@ -340,7 +340,7 @@ static int board_added(struct slot *p_slot) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); if (PWR_LED(ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); p_slot->hpc_ops->green_led_on(p_slot); @@ -348,7 +348,7 @@ static int board_added(struct slot *p_slot) wait_for_ctrl_irq (ctrl); /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); } return 0; @@ -380,14 +380,14 @@ static int remove_board(struct slot *p_slot) dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (POWER_CTRL(ctrl->ctrlcap)) { /* power off slot */ rc = p_slot->hpc_ops->power_off_slot(p_slot); if (rc) { err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return rc; } /* Wait for the command to complete */ @@ -403,7 +403,7 @@ static int remove_board(struct slot *p_slot) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); return 0; } @@ -450,7 +450,7 @@ static void pciehp_pushbutton_thread(unsigned long slot) if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->crit_sect); + mutex_lock(&p_slot->ctrl->ctrl_lock); p_slot->hpc_ops->green_led_off(p_slot); @@ -458,7 +458,7 @@ static void pciehp_pushbutton_thread(unsigned long slot) wait_for_ctrl_irq (p_slot->ctrl); /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->crit_sect); + mutex_unlock(&p_slot->ctrl->ctrl_lock); } p_slot->state = STATIC_STATE; } @@ -500,7 +500,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot) if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->crit_sect); + mutex_lock(&p_slot->ctrl->ctrl_lock); p_slot->hpc_ops->green_led_off(p_slot); @@ -508,7 +508,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot) wait_for_ctrl_irq (p_slot->ctrl); /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->crit_sect); + mutex_unlock(&p_slot->ctrl->ctrl_lock); } p_slot->state = STATIC_STATE; } @@ -621,7 +621,7 @@ static void interrupt_event_handler(struct controller *ctrl) switch (p_slot->state) { case BLINKINGOFF_STATE: /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (PWR_LED(ctrl->ctrlcap)) { p_slot->hpc_ops->green_led_on(p_slot); @@ -635,11 +635,11 @@ static void interrupt_event_handler(struct controller *ctrl) wait_for_ctrl_irq (ctrl); } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); break; case BLINKINGON_STATE: /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (PWR_LED(ctrl->ctrlcap)) { p_slot->hpc_ops->green_led_off(p_slot); @@ -652,7 +652,7 @@ static void interrupt_event_handler(struct controller *ctrl) wait_for_ctrl_irq (ctrl); } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); break; default: @@ -681,7 +681,7 @@ static void interrupt_event_handler(struct controller *ctrl) } /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); /* blink green LED and turn off amber */ if (PWR_LED(ctrl->ctrlcap)) { @@ -698,7 +698,7 @@ static void interrupt_event_handler(struct controller *ctrl) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); init_timer(&p_slot->task_event); p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ @@ -713,7 +713,7 @@ static void interrupt_event_handler(struct controller *ctrl) if (POWER_CTRL(ctrl->ctrlcap)) { dbg("power fault\n"); /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); + mutex_lock(&ctrl->ctrl_lock); if (ATTN_LED(ctrl->ctrlcap)) { p_slot->hpc_ops->set_attention_status(p_slot, 1); @@ -726,7 +726,7 @@ static void interrupt_event_handler(struct controller *ctrl) } /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); + mutex_unlock(&ctrl->ctrl_lock); } } /***********SURPRISE REMOVAL********************/ @@ -789,7 +789,6 @@ int pciehp_enable_slot(struct slot *p_slot) return -EINVAL; } } - mutex_unlock(&p_slot->ctrl->crit_sect); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); @@ -801,6 +800,7 @@ int pciehp_enable_slot(struct slot *p_slot) if (p_slot) update_slot_info(p_slot); + mutex_unlock(&p_slot->ctrl->crit_sect); return rc; } @@ -846,10 +846,10 @@ int pciehp_disable_slot(struct slot *p_slot) } } - mutex_unlock(&p_slot->ctrl->crit_sect); - ret = remove_board(p_slot); update_slot_info(p_slot); + + mutex_unlock(&p_slot->ctrl->crit_sect); return ret; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 703a64a39fe..1c551c697c3 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); + mutex_init(&ctrl->ctrl_lock); + /* setup wait queue */ init_waitqueue_head(&ctrl->queue); -- GitLab From 9ef9977cabc1b2c1718ef6eb883caec8dcb80b4c Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 25 Sep 2006 00:56:53 +0200 Subject: [PATCH 1418/1619] pciehp: Remove unnecessary check in pciehp_ctrl.c this was spotted by coverity (cid #819). We dereference p_slot earlier in the function, and i found no way it could become NULL anywhere. Signed-off-by: Eric Sesterhenn Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_ctrl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index c206a3d63b6..372c63e35aa 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -797,8 +797,7 @@ int pciehp_enable_slot(struct slot *p_slot) p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); } - if (p_slot) - update_slot_info(p_slot); + update_slot_info(p_slot); mutex_unlock(&p_slot->ctrl->crit_sect); return rc; -- GitLab From 09d6029f43ebbe7307854abdae204c25d711ff94 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 25 Sep 2006 16:52:19 -0700 Subject: [PATCH 1419/1619] PCI: VIA IRQ quirk behaviour change The most recent VIA IRQ quirk changes have broken various VIA devices for some users. We are not able to add these devices to the blacklist as they are also available in PCI-card form, and running the quirk on these devices brings us back to square one (running the VIA quirk on non-VIA boards where the quirk is not needed). This patch, based on suggestions from Sergey Vlasov, implements a scheme similar to but more restrictive than the scheme we had in 2.6.16 and earlier. It runs the quirk on all VIA hardware, but *only* if a VIA southbridge was detected on the system. To further reduce the amount of quirked devices, this patch includes a change suggested by Linus at http://lkml.org/lkml/2005/9/27/113 This ensures that devices bound to non-legacy IO-APIC interrupt lines are not quirked. We have made one change to Linus' suggestion: we do a comparison of ">15" rather than ">=15", as 15 is still in the legacy interrupt range. There is still a downside to this patch: if the user inserts a VIA PCI card into a VIA-based motherboard, in some circumstances the quirk will also run on the VIA PCI card. This corner case is hard to avoid. Signed-off-by: Daniel Drake Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 23b599d6a9d..e5425079cec 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -648,11 +648,43 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi * Some of the on-chip devices are actually '586 devices' so they are * listed here. */ + +static int via_irq_fixup_needed = -1; + +/* + * As some VIA hardware is available in PCI-card form, we need to restrict + * this quirk to VIA PCI hardware built onto VIA-based motherboards only. + * We try to locate a VIA southbridge before deciding whether the quirk + * should be applied. + */ +static const struct pci_device_id via_irq_fixup_tbl[] = { + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = PCI_CLASS_BRIDGE_ISA << 8, + .class_mask = 0xffff00, + }, + { 0, }, +}; + static void quirk_via_irq(struct pci_dev *dev) { u8 irq, new_irq; - new_irq = dev->irq & 0xf; + if (via_irq_fixup_needed == -1) + via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl); + + if (!via_irq_fixup_needed) + return; + + new_irq = dev->irq; + + /* Don't quirk interrupts outside the legacy IRQ range */ + if (!new_irq || new_irq > 15) + return; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); if (new_irq != irq) { printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n", @@ -661,14 +693,7 @@ static void quirk_via_irq(struct pci_dev *dev) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); /* * VIA VT82C598 has its device ID settable and many BIOSes -- GitLab From 3ec6a8d02efd54a66640bd85afa8c162647b56c3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 25 Sep 2006 16:52:20 -0700 Subject: [PATCH 1420/1619] PCI: pcie-check-and-return-bus_register-errors fix __must_check goes on the declaration, not the definition. Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/portdrv.h | 4 +++- drivers/pci/pcie/portdrv_core.c | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 67fcd176bab..3656e0349dd 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -9,6 +9,8 @@ #ifndef _PORTDRV_H_ #define _PORTDRV_H_ +#include + #if !defined(PCI_CAP_ID_PME) #define PCI_CAP_ID_PME 1 #endif @@ -39,7 +41,7 @@ extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state); extern int pcie_port_device_resume(struct pci_dev *dev); #endif extern void pcie_port_device_remove(struct pci_dev *dev); -extern int pcie_port_bus_register(void); +extern int __must_check pcie_port_bus_register(void); extern void pcie_port_bus_unregister(void); #endif /* _PORTDRV_H_ */ diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index bd6615b4d40..b20a9b81dae 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -6,7 +6,6 @@ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) */ -#include #include #include #include @@ -401,7 +400,7 @@ void pcie_port_device_remove(struct pci_dev *dev) pci_disable_msi(dev); } -int __must_check pcie_port_bus_register(void) +int pcie_port_bus_register(void) { return bus_register(&pcie_port_bus_type); } -- GitLab From bacedce32b171cd461a7da3160ad794e2240c67a Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Mon, 25 Sep 2006 16:52:21 -0700 Subject: [PATCH 1421/1619] PCI: add ICH7/8 ACPI/GPIO io resource quirks Signed-off-by: Daniel Ritz Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e5425079cec..1d2ccda946f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -453,6 +453,12 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi ); /* * VIA ACPI: One IO region pointed to by longword at -- GitLab From b5e4efe7e061ff52ac97b9fa45acca529d8daeea Mon Sep 17 00:00:00 2001 From: "eiichiro.oiwa.nm@hitachi.com" Date: Thu, 28 Sep 2006 13:55:47 +0900 Subject: [PATCH 1422/1619] PCI: Turn pci_fixup_video into generic for embedded VGA pci_fixup_video turns into generic code because there are many platforms need this fixup for embedded VGA as well as x86. The Video BIOS integrates into System BIOS on a machine has embedded VGA although embedded VGA generally don't have PCI ROM. As a result, embedded VGA need the way that the sysfs rom points to the Video BIOS of System RAM (0xC0000). PCI-to-PCI Bridge Architecture specification describes the condition whether or not PCI ROM forwards VGA compatible memory address. fixup_video suits this specification. Although the Video ROM generally implements in x86 code regardless of platform, some application such as X Window System can run this code by dosemu86. Therefore, pci_fixup_video should turn into generic code. Signed-off-by: Eiichiro Oiwa Acked-by: Alan Cox Acked-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- arch/i386/pci/fixup.c | 45 ------------------------------------------- drivers/pci/quirks.c | 45 +++++++++++++++++++++++++++++++++++++++++++ drivers/pci/rom.c | 5 ++++- 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index b60d7e8689e..908b410f4c9 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -342,51 +342,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_r DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk ); -/* - * Fixup to mark boot BIOS video selected by BIOS before it changes - * - * From information provided by "Jon Smirl" - * - * The standard boot ROM sequence for an x86 machine uses the BIOS - * to select an initial video card for boot display. This boot video - * card will have it's BIOS copied to C0000 in system RAM. - * IORESOURCE_ROM_SHADOW is used to associate the boot video - * card with this copy. On laptops this copy has to be used since - * the main ROM may be compressed or combined with another image. - * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW - * is marked here since the boot video device will be the only enabled - * video device at this point. - */ - -static void __devinit pci_fixup_video(struct pci_dev *pdev) -{ - struct pci_dev *bridge; - struct pci_bus *bus; - u16 config; - - if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return; - - /* Is VGA routed to us? */ - bus = pdev->bus; - while (bus) { - bridge = bus->self; - if (bridge) { - pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, - &config); - if (!(config & PCI_BRIDGE_CTL_VGA)) - return; - } - bus = bus->parent; - } - pci_read_config_word(pdev, PCI_COMMAND, &config); - if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { - pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; - printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); - /* * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. * diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 1d2ccda946f..371ab8821f1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1619,6 +1619,51 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); +/* + * Fixup to mark boot BIOS video selected by BIOS before it changes + * + * From information provided by "Jon Smirl" + * + * The standard boot ROM sequence for an x86 machine uses the BIOS + * to select an initial video card for boot display. This boot video + * card will have it's BIOS copied to C0000 in system RAM. + * IORESOURCE_ROM_SHADOW is used to associate the boot video + * card with this copy. On laptops this copy has to be used since + * the main ROM may be compressed or combined with another image. + * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW + * is marked here since the boot video device will be the only enabled + * video device at this point. + */ + +static void __devinit fixup_video(struct pci_dev *pdev) +{ + struct pci_dev *bridge; + struct pci_bus *bus; + u16 config; + + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return; + + /* Is VGA routed to us? */ + bus = pdev->bus; + while (bus) { + bridge = bus->self; + if (bridge) { + pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, + &config); + if (!(config & PCI_BRIDGE_CTL_VGA)) + return; + } + bus = bus->parent; + } + pci_read_config_word(pdev, PCI_COMMAND, &config); + if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; + printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_video); + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index f5ee7ce16fa..43e4a49f2cc 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -71,7 +71,10 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) void __iomem *image; int last_image; - /* IORESOURCE_ROM_SHADOW only set on x86 */ + /* + * IORESOURCE_ROM_SHADOW set if the VGA enable bit of the Bridge Control + * register is set for embedded VGA. + */ if (res->flags & IORESOURCE_ROM_SHADOW) { /* primary video rom always starts here */ start = (loff_t)0xC0000; -- GitLab From ccc4c7bbd6a2d47bf5899c2c8cf2e0d176a4dc0f Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Fri, 7 Apr 2006 20:00:27 +0200 Subject: [PATCH 1423/1619] Fix DMA resource allocation in ACPIPnP The ACPIPnP implementation had the understanding of Linux resource flags very wrong, resulting in a nonfunctional implementation of DMA resource allocation. This was usually not a problem, since almost no on-board PnP devices use ISA DMA, with the exception of ECP parallel ports. Even with that, parallel port DMA is preconfigured by the BIOS, so this routine isn't normally called. Except in the case where somebody does 'rmmod parport_pc; modprobe parport_pc', where the rmmod case disables the ECP parallel port resources, and they need to be enabled again to initialize the module. This didn't work, resulting in a non-printing printer. The application doing exactly the above to force reprobing of printers is the YaST printer module. Thus without this fix YaST wedged the printer when configuring it, and was not able to print a test page. Reported-by: Ralf Flaxa Reproduced-by: Jiri Dluhos Signed-off-by: Vojtech Pavlik Signed-off-by: Greg Kroah-Hartman --- drivers/pnp/pnpacpi/rsparser.c | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index dc79b0a0059..379048fdf05 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -776,21 +776,32 @@ static void pnpacpi_encode_dma(struct acpi_resource *resource, struct resource *p) { /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ - if (p->flags & IORESOURCE_DMA_COMPATIBLE) - resource->data.dma.type = ACPI_COMPATIBILITY; - else if (p->flags & IORESOURCE_DMA_TYPEA) - resource->data.dma.type = ACPI_TYPE_A; - else if (p->flags & IORESOURCE_DMA_TYPEB) - resource->data.dma.type = ACPI_TYPE_B; - else if (p->flags & IORESOURCE_DMA_TYPEF) - resource->data.dma.type = ACPI_TYPE_F; - if (p->flags & IORESOURCE_DMA_8BIT) - resource->data.dma.transfer = ACPI_TRANSFER_8; - else if (p->flags & IORESOURCE_DMA_8AND16BIT) - resource->data.dma.transfer = ACPI_TRANSFER_8_16; - else if (p->flags & IORESOURCE_DMA_16BIT) - resource->data.dma.transfer = ACPI_TRANSFER_16; - resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER; + switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { + case IORESOURCE_DMA_TYPEA: + resource->data.dma.type = ACPI_TYPE_A; + break; + case IORESOURCE_DMA_TYPEB: + resource->data.dma.type = ACPI_TYPE_B; + break; + case IORESOURCE_DMA_TYPEF: + resource->data.dma.type = ACPI_TYPE_F; + break; + default: + resource->data.dma.type = ACPI_COMPATIBILITY; + } + + switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { + case IORESOURCE_DMA_8BIT: + resource->data.dma.transfer = ACPI_TRANSFER_8; + break; + case IORESOURCE_DMA_8AND16BIT: + resource->data.dma.transfer = ACPI_TRANSFER_8_16; + break; + default: + resource->data.dma.transfer = ACPI_TRANSFER_16; + } + + resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); resource->data.dma.channel_count = 1; resource->data.dma.channels[0] = p->start; } -- GitLab From 0bed208efcb25bed4dc2026488a4417aa68e7c92 Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Thu, 28 Sep 2006 14:35:59 +0800 Subject: [PATCH 1424/1619] PCI: fix pcie_portdrv_restore_config undefined without CONFIG_PM error On Thu, 2006-09-28 at 03:42, Olaf Hering wrote: > PCI-Express AER implemetation: pcie_portdrv error handler > > This patch breaks if CONFIG_PM is not enabled, > pcie_portdrv_restore_config() will be undefined. I move the definition of pcie_portdrv_restore_config out of CONFIG_PM. Below patch is against 2.6.18-mm1. Could you try it? Signed-off-by: Zhang Yanmin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/portdrv_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 037690e08f5..b4da7954611 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -37,7 +37,6 @@ static int pcie_portdrv_save_config(struct pci_dev *dev) return pci_save_state(dev); } -#ifdef CONFIG_PM static int pcie_portdrv_restore_config(struct pci_dev *dev) { int retval; @@ -50,6 +49,7 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) return 0; } +#ifdef CONFIG_PM static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) { int ret = pcie_port_device_suspend(dev, state); -- GitLab From 094ed76e8988d46158b036ab150e0c22aff6db3a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 29 Sep 2006 18:36:15 +0100 Subject: [PATCH 1425/1619] pci: Stamp out pci_find_* usage in fakephp pci_find is not hotplug safe, so it really doesn't want to be in an actual hotplug driver either. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/fakephp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 05a4f0f9018..aaeb1129132 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -181,7 +181,9 @@ static void pci_rescan_slot(struct pci_dev *temp) 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)) { + if ((dev = pci_get_slot(bus, temp->devfn)) != NULL) + pci_dev_put(dev); + else { dev = pci_scan_single_device(bus, temp->devfn); if (dev) { dbg("New device on %s function %x:%x\n", @@ -205,7 +207,9 @@ static void pci_rescan_slot(struct pci_dev *temp) continue; temp->hdr_type = hdr_type & 0x7f; - if (!pci_find_slot(bus->number, temp->devfn)) { + if ((dev = pci_get_slot(bus, temp->devfn)) != NULL) + pci_dev_put(dev); + else { dev = pci_scan_single_device(bus, temp->devfn); if (dev) { dbg("New device on %s function %x:%x\n", @@ -305,7 +309,7 @@ static int disable_slot(struct hotplug_slot *slot) /* search for subfunctions and disable them first */ if (!(dslot->dev->devfn & 7)) { for (func = 1; func < 8; func++) { - dev = pci_find_slot(dslot->dev->bus->number, + dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); if (dev) { hslot = get_slot_from_dev(dev); @@ -315,6 +319,7 @@ static int disable_slot(struct hotplug_slot *slot) err("Hotplug slot not found for subfunction of PCI device\n"); return -ENODEV; } + pci_dev_put(dev); } else dbg("No device in slot found\n"); } -- GitLab From d1729ccecd7ba9ceb6dca1c973dbfd87041d0637 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 28 Sep 2006 15:51:21 -0700 Subject: [PATCH 1426/1619] shpchp: fix command completion check This patch fixes the problem that shpchp driver could mis-detect command failures if the system was under heavy load. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 446e9beff04..4826dd158de 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -302,6 +302,12 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) add_timer(&php_ctlr->int_poll_timer); } +static inline int is_ctrl_busy(struct controller *ctrl) +{ + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS); + return cmd_status & 0x1; +} + /* * Returns 1 if SHPC finishes executing a command within 1 sec, * otherwise returns 0. @@ -309,16 +315,14 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) static inline int shpc_poll_ctrl_busy(struct controller *ctrl) { int i; - u16 cmd_status = shpc_readw(ctrl, CMD_STATUS); - if (!(cmd_status & 0x1)) + if (!is_ctrl_busy(ctrl)) return 1; /* Check every 0.1 sec for a total of 1 sec */ for (i = 0; i < 10; i++) { msleep(100); - cmd_status = shpc_readw(ctrl, CMD_STATUS); - if (!(cmd_status & 0x1)) + if (!is_ctrl_busy(ctrl)) return 1; } @@ -336,7 +340,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl) else rc = wait_event_interruptible_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); - if (!rc) { + if (!rc && is_ctrl_busy(ctrl)) { retval = -EIO; err("Command not completed in 1000 msec\n"); } else if (rc < 0) { -- GitLab From 6aa562c248e05db993e4a5f405f899c0cfabb7f2 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 28 Sep 2006 15:51:36 -0700 Subject: [PATCH 1427/1619] shpchp: remove unnecessary cmd_busy member from struct controller This patch removes unnecessary cmd_busy member from struct controller. Read command status register instead of using cmd_busy. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 1 - drivers/pci/hotplug/shpchp_hpc.c | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index c7103ac5cd0..7e7d490622e 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -103,7 +103,6 @@ struct controller { u32 cap_offset; unsigned long mmio_base; unsigned long mmio_size; - volatile int cmd_busy; }; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 4826dd158de..bbe450f098e 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -339,7 +339,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl) rc = shpc_poll_ctrl_busy(ctrl); else rc = wait_event_interruptible_timeout(ctrl->queue, - !ctrl->cmd_busy, timeout); + !is_ctrl_busy(ctrl), timeout); if (!rc && is_ctrl_busy(ctrl)) { retval = -EIO; err("Command not completed in 1000 msec\n"); @@ -347,7 +347,6 @@ static inline int shpc_wait_cmd(struct controller *ctrl) retval = -EINTR; info("Command was interrupted by a signal\n"); } - ctrl->cmd_busy = 0; return retval; } @@ -378,7 +377,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) /* To make sure the Controller Busy bit is 0 before we send out the * command. */ - slot->ctrl->cmd_busy = 1; shpc_writew(ctrl, CMD, temp_word); /* @@ -928,7 +926,6 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) serr_int &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); - ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } -- GitLab From 662a98fb8de5af4adb56e58f78753cdaa27b6459 Mon Sep 17 00:00:00 2001 From: Amol Lad Date: Thu, 5 Oct 2006 12:07:32 +0530 Subject: [PATCH 1428/1619] PCI hotplug: ioremap balanced with iounmap 1. ioremap must be balanced by an iounmap and failing to do so can result in a memory leak. 2. Handle return value correctly Tested (compilation only) with: - allmodconfig Signed-off-by: Amol Lad Cc: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index bbe450f098e..83a5226ba9e 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -1118,7 +1118,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) { struct php_ctlr_state_s *php_ctlr, *p; void *instance_id = ctrl; - int rc, num_slots = 0; + int rc = -1, num_slots = 0; u8 hp_slot; u32 shpc_base_offset; u32 tempdword, slot_reg, slot_config; @@ -1184,11 +1184,15 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); - if (pci_enable_device(pdev)) + rc = pci_enable_device(pdev); + if (rc) { + err("%s: pci_enable_device failed\n", __FUNCTION__); goto abort_free_ctlr; + } if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { err("%s: cannot reserve MMIO region\n", __FUNCTION__); + rc = -1; goto abort_free_ctlr; } @@ -1197,6 +1201,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, ctrl->mmio_size, ctrl->mmio_base); release_mem_region(ctrl->mmio_base, ctrl->mmio_size); + rc = -1; goto abort_free_ctlr; } dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); @@ -1299,8 +1304,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) */ if (atomic_add_return(1, &shpchp_num_controllers) == 1) { shpchp_wq = create_singlethread_workqueue("shpchpd"); - if (!shpchp_wq) - return -ENOMEM; + if (!shpchp_wq) { + rc = -ENOMEM; + goto abort_free_ctlr; + } } /* @@ -1330,8 +1337,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) /* We end up here for the many possible ways to fail this API. */ abort_free_ctlr: + if (php_ctlr->creg) + iounmap(php_ctlr->creg); kfree(php_ctlr); abort: DBG_LEAVE_ROUTINE - return -1; + return rc; } -- GitLab From 0306ebfa3b45386401f80aa87cb4f7570bf3aadb Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 5 Oct 2006 10:24:31 +0200 Subject: [PATCH 1429/1619] PCI: Improve pci_msi_supported() comments Improve pci_msi_supported() comments. Signed-off-by: Brice Goglin Signed-off-by: Grant Grundler Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f9fdc54473c..9fc9a34ef24 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -627,22 +627,24 @@ static int msix_capability_init(struct pci_dev *dev, * pci_msi_supported - check whether MSI may be enabled on device * @dev: pointer to the pci_dev data structure of MSI device function * - * MSI must be globally enabled and supported by the device and its root - * bus. But, the root bus is not easy to find since some architectures - * have virtual busses on top of the PCI hierarchy (for instance the - * hypertransport bus), while the actual bus where MSI must be supported - * is below. So we test the MSI flag on all parent busses and assume - * that no quirk will ever set the NO_MSI flag on a non-root bus. + * Look at global flags, the device itself, and its parent busses + * to return 0 if MSI are supported for the device. **/ static int pci_msi_supported(struct pci_dev * dev) { struct pci_bus *bus; + /* MSI must be globally enabled and supported by the device */ if (!pci_msi_enable || !dev || dev->no_msi) return -EINVAL; - /* check MSI flags of all parent busses */ + /* Any bridge which does NOT route MSI transactions from it's + * secondary bus to it's primary bus must set NO_MSI flag on + * the secondary pci_bus. + * We expect only arch-specific PCI host bus controller driver + * or quirks for specific PCI bridges to be setting NO_MSI. + */ for (bus = dev->bus; bus; bus = bus->parent) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; -- GitLab From 0cc2b3763e06e84ae5a90b63e03cc1d585a109d0 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 5 Oct 2006 10:24:42 +0200 Subject: [PATCH 1430/1619] PCI: Update MSI-HOWTO.txt according to pci_msi_supported() Update MSI-HOWTO.txt according to pci_msi_supported(). Signed-off-by: Brice Goglin Signed-off-by: Greg Kroah-Hartman --- Documentation/MSI-HOWTO.txt | 63 ++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt index c70306abb7b..5c34910665d 100644 --- a/Documentation/MSI-HOWTO.txt +++ b/Documentation/MSI-HOWTO.txt @@ -470,7 +470,68 @@ LOC: 324553 325068 ERR: 0 MIS: 0 -6. FAQ +6. MSI quirks + +Several PCI chipsets or devices are known to not support MSI. +The PCI stack provides 3 possible levels of MSI disabling: +* on a single device +* on all devices behind a specific bridge +* globally + +6.1. Disabling MSI on a single device + +Under some circumstances, it might be required to disable MSI on a +single device, It may be achived by either not calling pci_enable_msi() +or all, or setting the pci_dev->no_msi flag before (most of the time +in a quirk). + +6.2. Disabling MSI below a bridge + +The vast majority of MSI quirks are required by PCI bridges not +being able to route MSI between busses. In this case, MSI have to be +disabled on all devices behind this bridge. It is achieves by setting +the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge +subordinate bus. There is no need to set the same flag on bridges that +are below the broken brigde. When pci_enable_msi() is called to enable +MSI on a device, pci_msi_supported() takes care of checking the NO_MSI +flag in all parent busses of the device. + +Some bridges actually support dynamic MSI support enabling/disabling +by changing some bits in their PCI configuration space (especially +the Hypertransport chipsets such as the nVidia nForce and Serverworks +HT2000). It may then be required to update the NO_MSI flag on the +corresponding devices in the sysfs hierarchy. To enable MSI support +on device "0000:00:0e", do: + + echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus + +To disable MSI support, echo 0 instead of 1. Note that it should be +used with caution since changing this value might break interrupts. + +6.3. Disabling MSI globally + +Some extreme cases may require to disable MSI globally on the system. +For now, the only known case is a Serverworks PCI-X chipsets (MSI are +not supported on several busses that are not all connected to the +chipset in the Linux PCI hierarchy). In the vast majority of other +cases, disabling only behind a specific bridge is enough. + +For debugging purpose, the user may also pass pci=nomsi on the kernel +command-line to explicitly disable MSI globally. But, once the appro- +priate quirks are added to the kernel, this option should not be +required anymore. + +6.4. Finding why MSI cannot be enabled on a device + +Assuming that MSI are not enabled on a device, you should look at +dmesg to find messages that quirks may output when disabling MSI +on some devices, some bridges or even globally. +Then, lspci -t gives the list of bridges above a device. Reading +/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI +are enabled (1) or disabled (0). In 0 is found in a single bridge +msi_bus file above the device, MSI cannot be enabled. + +7. FAQ Q1. Are there any limitations on using the MSI? -- GitLab From 11f242f04c6d886494cc83097cb6def044eabebb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 10 Oct 2006 14:39:00 -0700 Subject: [PATCH 1431/1619] PCI: quirks: switch quirks code offender to use pci_get API Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 371ab8821f1..e8a7f1b1b2b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1840,7 +1840,7 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) /* 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); + pdev = pci_get_slot(dev->bus, 0); if (dev->subordinate && !msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { printk(KERN_WARNING "PCI: MSI quirk detected. " @@ -1848,6 +1848,7 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) pci_name(dev)); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } + pci_dev_put(pdev); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); -- GitLab From 29f3eb64634cf96903a3cdb56b1f9a80bebad17d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:20:21 -0700 Subject: [PATCH 1432/1619] 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(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index d529462d1b5..2f13eba5d5a 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 5c604f5fad6..09bf88fc80c 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); -- GitLab From 49c61cca2b6591a28ffa4abb73c718091f569746 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 14 Oct 2006 03:07:30 +0900 Subject: [PATCH 1433/1619] cpcihp_generic: prevent loading without "bridge" parameter cpcihp_generic module requires configured "bridge" module parameter. But it can be loaded successfully without that parameter. Because module init call ends up returning positive value. This patch prevents from loading without setting "bridge" module parameter. Signed-off-by: Akinbou Mita Signed-off-by: Scott Murray Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpcihp_generic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c index e847f0d6c7f..f3852a6b74e 100644 --- a/drivers/pci/hotplug/cpcihp_generic.c +++ b/drivers/pci/hotplug/cpcihp_generic.c @@ -84,7 +84,7 @@ static int __init validate_parameters(void) if(!bridge) { info("not configured, disabling."); - return 1; + return -EINVAL; } str = bridge; if(!*str) @@ -147,7 +147,7 @@ static int __init cpcihp_generic_init(void) info(DRIVER_DESC " version: " DRIVER_VERSION); status = validate_parameters(); - if(status != 0) + if (status) return status; r = request_region(port, 1, "#ENUM hotswap signal register"); -- GitLab From 6b4b78fed47e7380dfe9280b154e8b9bfcd4c86c Mon Sep 17 00:00:00 2001 From: Matt Domsch Date: Fri, 29 Sep 2006 15:23:23 -0500 Subject: [PATCH 1434/1619] 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(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ff571f9298e..dd00fd556a6 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 68bce194e68..6d5ace845e4 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 1814f74569c..ad065cebd7b 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 a3b0a5eb505..e159d660449 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 09bf88fc80c..4689e2a699c 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 */ -- GitLab From fb5f4d7a74a140f8e033d1e6854989e88c36c6b8 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Fri, 29 Sep 2006 10:30:27 -0700 Subject: [PATCH 1435/1619] change pci hotplug subsystem maintainer to Kristen Here's a patch adding me to the maintainers file for the pci hotplug subsystem, as we discussed. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 4 ++-- drivers/pci/hotplug/pci_hotplug.h | 2 +- drivers/pci/hotplug/pci_hotplug_core.c | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5305dd69095..9b6b88268d3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2309,8 +2309,8 @@ T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ S: Supported PCI HOTPLUG CORE -P: Greg Kroah-Hartman -M: gregkh@suse.de +P: Kristen Carlson Accardi +M: kristen.c.accardi@intel.com S: Supported PCI HOTPLUG COMPAQ DRIVER diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h index 772523dc386..a675a05c409 100644 --- a/drivers/pci/hotplug/pci_hotplug.h +++ b/drivers/pci/hotplug/pci_hotplug.h @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ #ifndef _PCI_HOTPLUG_H diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index e2823ea9c4e..fa666d0cc48 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -21,9 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to - * - * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * Send feedback to * */ -- GitLab From 7a54f25cef6c763f16c9fd49ae382de162147873 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 13 Oct 2006 20:05:19 -0700 Subject: [PATCH 1436/1619] 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_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 +-- {drivers/pci/hotplug => include/linux}/pci_hotplug.h | 0 23 files changed, 22 insertions(+), 21 deletions(-) rename {drivers/pci/hotplug => include/linux}/pci_hotplug.h (100%) diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 51cb9f817c2..270a33cc08f 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 7fff07e877c..59c5b242d86 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 e2fef60c2d0..c57d9d5ce84 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 83e8e4412de..c44311ac2fd 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 d0a07d9ab30..bd40aee10e1 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 d06ab404513..684551559d4 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 4afcaffd031..7b1beaad275 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 ea040c32f47..298ad7f3f4f 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 1fc259913b6..5617cfdadc5 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 3ec2ad7db49..79ff6b4de3a 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 cf087891753..298a6cfd840 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 0d9688952f4..fc7c74d7259 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 5bab666cd67..634f74d919d 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 aaeb1129132..e27907c91d9 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 dba6d8ca9bd..612d9630150 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_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index fa666d0cc48..f5d632e7232 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 30f021c55fe..4fb12fcda56 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 2b9e10e3861..50bcd3fe61d 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 db69be85b45..6c5be3ff578 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 7288a3eccfb..141486df235 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 f31d83c2c63..b62ad31a973 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 7e7d490622e..ea2087c3414 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/drivers/pci/hotplug/pci_hotplug.h b/include/linux/pci_hotplug.h similarity index 100% rename from drivers/pci/hotplug/pci_hotplug.h rename to include/linux/pci_hotplug.h -- GitLab From acbd39fbc5d8757aa920c6045399374df7a6dd68 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 30 Sep 2006 22:41:43 -0400 Subject: [PATCH 1437/1619] Documentation: feature-removal-schedule typo Fix typo in newly added feature remove schedule item. Signed-off-by: Dominik Brodowski Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- Documentation/feature-removal-schedule.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 24f3c63b301..1ac3c74646e 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -255,7 +255,7 @@ Who: Stephen Hemminger What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment -When: Oktober 2008 +When: October 2008 Why: The stacking of class devices makes these values misleading and inconsistent. Class devices should not carry any of these properties, and bus -- GitLab From 0fbf116d120a2dc5d808204c7d86ad35f7d7846f Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 27 Sep 2006 23:38:08 +0200 Subject: [PATCH 1438/1619] Driver core: plug device probe memory leak Make sure data is freed if the kthread fails to start. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b5f43c3e44f..ef7db6939cb 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -178,7 +178,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) probe_task = kthread_run(really_probe, data, "probe-%s", dev->bus_id); if (IS_ERR(probe_task)) - ret = PTR_ERR(probe_task); + ret = really_probe(data); } else ret = really_probe(data); -- GitLab From 310a922d4307ed38b37982a6f93b11fdf3b8dcb1 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sat, 23 Sep 2006 23:35:04 -0600 Subject: [PATCH 1439/1619] Fix dev_printk() is now GPL-only Make dev_printk usable from non-GPL modules again dev_printk now calls dev_driver_string. We want even proprietary modules to be calling dev_printk, so the export of dev_driver_string needs to be non-GPL-only. Signed-off-by: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index b224bb43ff6..aee3743bd4a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -44,7 +44,7 @@ const char *dev_driver_string(struct device *dev) return dev->driver ? dev->driver->name : (dev->bus ? dev->bus->name : ""); } -EXPORT_SYMBOL_GPL(dev_driver_string); +EXPORT_SYMBOL(dev_driver_string); #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) -- GitLab From 722385f75efd82d9f480f0765a1e97a4d83cac0d Mon Sep 17 00:00:00 2001 From: Diego Calleja Date: Thu, 21 Sep 2006 22:37:10 +0200 Subject: [PATCH 1440/1619] HOWTO: bug report addition I suspect that not many people is subscribed to the bugzilla mailing list, not surprising since the URLs doesn't seem to be in the tree :) After fixing my english, I wonder if the following patch could be applied... Signed-off-by: Diego Calleja Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- Documentation/HOWTO | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/HOWTO b/Documentation/HOWTO index d6f3dd1a346..8d51c148f72 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -395,6 +395,26 @@ bugme-janitor mailing list (every change in the bugzilla is mailed here) +Managing bug reports +-------------------- + +One of the best ways to put into practice your hacking skills is by fixing +bugs reported by other people. Not only you will help to make the kernel +more stable, you'll learn to fix real world problems and you will improve +your skills, and other developers will be aware of your presence. Fixing +bugs is one of the best ways to get merits among other developers, because +not many people like wasting time fixing other people's bugs. + +To work in the already reported bug reports, go to http://bugzilla.kernel.org. +If you want to be advised of the future bug reports, you can subscribe to the +bugme-new mailing list (only new bug reports are mailed here) or to the +bugme-janitor mailing list (every change in the bugzilla is mailed here) + + http://lists.osdl.org/mailman/listinfo/bugme-new + http://lists.osdl.org/mailman/listinfo/bugme-janitors + + + Mailing lists ------------- -- GitLab From e42344514c6e8ca7f5427da9b1407b56550dfa01 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Wed, 20 Sep 2006 16:38:00 +0900 Subject: [PATCH 1441/1619] sysfs: remove duplicated dput in sysfs_update_file Following function can drops d_count twice against one reference by lookup_one_len. /** * sysfs_update_file - update the modified timestamp on an object attribute. * @kobj: object we're acting for. * @attr: attribute descriptor. */ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) { struct dentry * dir = kobj->dentry; struct dentry * victim; int res = -ENOENT; mutex_lock(&dir->d_inode->i_mutex); victim = lookup_one_len(attr->name, dir, strlen(attr->name)); if (!IS_ERR(victim)) { /* make sure dentry is really there */ if (victim->d_inode && (victim->d_parent->d_inode == dir->d_inode)) { victim->d_inode->i_mtime = CURRENT_TIME; fsnotify_modify(victim); /** * Drop reference from initial sysfs_get_dentry(). */ dput(victim); res = 0; } else d_drop(victim); /** * Drop the reference acquired from sysfs_get_dentry() above. */ dput(victim); } mutex_unlock(&dir->d_inode->i_mutex); return res; } PCI-hotplug (drivers/pci/hotplug/pci_hotplug_core.c) is only user of this function. I confirmed that dentry of /sys/bus/pci/slots/XXX/* have negative d_count value. This patch removes unnecessary dput(). Signed-off-by: Hidetoshi Seto Acked-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 146f1dedec8..93218ccb2f6 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -483,11 +483,6 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) (victim->d_parent->d_inode == dir->d_inode)) { victim->d_inode->i_mtime = CURRENT_TIME; fsnotify_modify(victim); - - /** - * Drop reference from initial sysfs_get_dentry(). - */ - dput(victim); res = 0; } else d_drop(victim); -- GitLab From 97a501849d60f3dbb8bfcd2300cf65dd5ebc0355 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Wed, 20 Sep 2006 16:49:02 +0900 Subject: [PATCH 1442/1619] sysfs: update obsolete comment in sysfs_update_file And the obsolete comment should be updated (or totally removed). Signed-off-by: Hidetoshi Seto Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 93218ccb2f6..298303b5a71 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -488,7 +488,7 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) d_drop(victim); /** - * Drop the reference acquired from sysfs_get_dentry() above. + * Drop the reference acquired from lookup_one_len() above. */ dput(victim); } -- GitLab From f0e1761ac528e9d28f3ba06bd268ec41fe872ac8 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 22 Sep 2006 11:37:00 +0200 Subject: [PATCH 1443/1619] driver core fixes: sysfs_create_link() retval check in class.c Check for return value of sysfs_create_link() in class_device_add(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index b32b77ff2dc..0ff267a248d 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -562,7 +562,10 @@ int class_device_add(struct class_device *class_dev) goto out2; /* add the needed attributes to this device */ - sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem"); + error = sysfs_create_link(&class_dev->kobj, + &parent_class->subsys.kset.kobj, "subsystem"); + if (error) + goto out3; class_dev->uevent_attr.attr.name = "uevent"; class_dev->uevent_attr.attr.mode = S_IWUSR; class_dev->uevent_attr.attr.owner = parent_class->owner; -- GitLab From 1bb6881acae1c4f11a6e86f04df32ba45e95031d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 22 Sep 2006 11:37:04 +0200 Subject: [PATCH 1444/1619] driver core fixes: bus_add_attrs() retval check Check return value of bus_add_attrs() in bus_register(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 12173d16bea..b90f6e6f644 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -732,11 +732,15 @@ int bus_register(struct bus_type * bus) klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_drivers, NULL, NULL); - bus_add_attrs(bus); + retval = bus_add_attrs(bus); + if (retval) + goto bus_attrs_fail; pr_debug("bus type '%s' registered\n", bus->name); return 0; +bus_attrs_fail: + kset_unregister(&bus->drivers); bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: -- GitLab From 513e7337adc32cdfbffecb99953e45a44e812c2d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 22 Sep 2006 11:37:08 +0200 Subject: [PATCH 1445/1619] driver core fixes: bus_add_device() cleanup on error Correct cleanup in the error path of bus_add_device(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index b90f6e6f644..d516f7d5f16 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -372,19 +372,30 @@ int bus_add_device(struct device * dev) pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); error = device_add_attrs(bus, dev); if (error) - goto out; + goto out_put; error = sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); if (error) - goto out; + goto out_id; error = sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem"); if (error) - goto out; + goto out_subsys; error = sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); + if (error) + goto out_deprecated; } -out: + return 0; + +out_deprecated: + sysfs_remove_link(&dev->kobj, "subsystem"); +out_subsys: + sysfs_remove_link(&bus->devices.kobj, dev->bus_id); +out_id: + device_remove_attrs(bus, dev); +out_put: + put_bus(dev->bus); return error; } -- GitLab From a306eea40952e6365301e8a2f7d5ffa9c6a1921b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 22 Sep 2006 11:37:13 +0200 Subject: [PATCH 1446/1619] driver core fixes: device_add() cleanup on error Check for return code of device_create_file() and correct cleanup in the error case in device_add(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index aee3743bd4a..365f709715e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -433,14 +433,16 @@ int device_add(struct device *dev) if (dev->driver) dev->uevent_attr.attr.owner = dev->driver->owner; dev->uevent_attr.store = store_uevent; - device_create_file(dev, &dev->uevent_attr); + error = device_create_file(dev, &dev->uevent_attr); + if (error) + goto attrError; if (MAJOR(dev->devt)) { struct device_attribute *attr; attr = kzalloc(sizeof(*attr), GFP_KERNEL); if (!attr) { error = -ENOMEM; - goto PMError; + goto ueventattrError; } attr->attr.name = "dev"; attr->attr.mode = S_IRUGO; @@ -450,7 +452,7 @@ int device_add(struct device *dev) error = device_create_file(dev, attr); if (error) { kfree(attr); - goto attrError; + goto ueventattrError; } dev->devt_attr = attr; @@ -507,6 +509,8 @@ int device_add(struct device *dev) device_remove_file(dev, dev->devt_attr); kfree(dev->devt_attr); } + ueventattrError: + device_remove_file(dev, &dev->uevent_attr); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); -- GitLab From 141ecc5320147d363d060cfc8042d197a3cdd496 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 22 Sep 2006 11:37:27 +0200 Subject: [PATCH 1447/1619] driver core fixes: device_create_file() retval check in dmapool.c Check for device_create_file() return value in dma_pool_create(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/dmapool.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index 33c5cce1560..b2efbd4cf71 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -141,11 +141,20 @@ dma_pool_create (const char *name, struct device *dev, init_waitqueue_head (&retval->waitq); if (dev) { + int ret; + down (&pools_lock); if (list_empty (&dev->dma_pools)) - device_create_file (dev, &dev_attr_pools); + ret = device_create_file (dev, &dev_attr_pools); + else + ret = 0; /* note: not currently insisting "name" be unique */ - list_add (&retval->pools, &dev->dma_pools); + if (!ret) + list_add (&retval->pools, &dev->dma_pools); + else { + kfree(retval); + retval = NULL; + } up (&pools_lock); } else INIT_LIST_HEAD (&retval->pools); -- GitLab From 221c324a336770a911b16bda02b9f4adad506a35 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 22 Sep 2006 11:37:32 +0200 Subject: [PATCH 1448/1619] driver core fixes: sysfs_create_group() retval in topology.c Return the return value of sysfs_create_group() in topology_add_dev(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 3ef9d514b91..28dccb730af 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -97,8 +97,7 @@ static struct attribute_group topology_attr_group = { /* Add/Remove cpu_topology interface for CPU device */ static int __cpuinit topology_add_dev(struct sys_device * sys_dev) { - sysfs_create_group(&sys_dev->kobj, &topology_attr_group); - return 0; + return sysfs_create_group(&sys_dev->kobj, &topology_attr_group); } static int __cpuinit topology_remove_dev(struct sys_device * sys_dev) -- GitLab From 952ab431cd36c7ab573f685af8679c3677cbdc29 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 28 Sep 2006 23:56:01 +0200 Subject: [PATCH 1449/1619] Driver core: Don't leak 'old_class_name' in drivers/base/core.c::device_rename() If kmalloc() fails to allocate space for 'old_symlink_name' in drivers/base/core.c::device_rename(), then we'll leak 'old_class_name'. Spotted by the Coverity checker. Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 365f709715e..41f3dca55cd 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -809,8 +809,10 @@ int device_rename(struct device *dev, char *new_name) if (dev->class) { old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); - if (!old_symlink_name) - return -ENOMEM; + if (!old_symlink_name) { + error = -ENOMEM; + goto out_free_old_class; + } strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); } @@ -834,9 +836,10 @@ int device_rename(struct device *dev, char *new_name) } put_device(dev); - kfree(old_class_name); kfree(new_class_name); kfree(old_symlink_name); + out_free_old_class: + kfree(old_class_name); return error; } -- GitLab From f70fa6296c2ec8f541f0a9b406ccc2d9d127d639 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 5 Oct 2006 17:03:24 -0400 Subject: [PATCH 1450/1619] Driver core: Don't ignore error returns from probing This patch (as797) fixes device_add() in the driver core. It needs to pay attention when the driver for a new device reports an error. At the same time, since bus_remove_device() undoes the effects of both bus_add_device() and bus_attach_device(), it needs to check whether the bus_attach_device step failed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 6 ++++-- drivers/base/core.c | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d516f7d5f16..d7c5ea246a0 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -439,8 +439,10 @@ void bus_remove_device(struct device * dev) sysfs_remove_link(&dev->kobj, "bus"); sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); - dev->is_registered = 0; - klist_del(&dev->knode_bus); + if (dev->is_registered) { + dev->is_registered = 0; + klist_del(&dev->knode_bus); + } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); put_bus(dev->bus); diff --git a/drivers/base/core.c b/drivers/base/core.c index 41f3dca55cd..68ad11af22b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -479,7 +479,8 @@ int device_add(struct device *dev) if ((error = bus_add_device(dev))) goto BusError; kobject_uevent(&dev->kobj, KOBJ_ADD); - bus_attach_device(dev); + if ((error = bus_attach_device(dev))) + goto AttachError; if (parent) klist_add_tail(&dev->knode_parent, &parent->klist_children); @@ -498,6 +499,8 @@ int device_add(struct device *dev) kfree(class_name); put_device(dev); return error; + AttachError: + bus_remove_device(dev); BusError: device_pm_remove(dev); PMError: -- GitLab From d9fd4d3b317a231e47f31d64d66c8cc7765d458f Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 07:48:03 -0400 Subject: [PATCH 1451/1619] Driver core: bus: remove indentation level Before potentially fixing up these functions, this cosmetic change reduces the indentation level to make the code easier to read and maintain. No functional changes at all. Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 77 ++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d7c5ea246a0..7d8a7ce73fb 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -518,34 +518,36 @@ int bus_add_driver(struct device_driver *drv) struct bus_type * bus = get_bus(drv->bus); int error = 0; - if (bus) { - pr_debug("bus %s: add driver %s\n", bus->name, drv->name); - error = kobject_set_name(&drv->kobj, "%s", drv->name); - if (error) - goto out_put_bus; - drv->kobj.kset = &bus->drivers; - if ((error = kobject_register(&drv->kobj))) - goto out_put_bus; - - error = driver_attach(drv); - if (error) - goto out_unregister; - klist_add_tail(&drv->knode_bus, &bus->klist_drivers); - module_add_driver(drv->owner, drv); - - error = driver_add_attrs(bus, drv); - if (error) { - /* How the hell do we get out of this pickle? Give up */ - printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", - __FUNCTION__, drv->name); - } - error = add_bind_files(drv); - if (error) { - /* Ditto */ - printk(KERN_ERR "%s: add_bind_files(%s) failed\n", - __FUNCTION__, drv->name); - } + if (!bus) + return 0; + + pr_debug("bus %s: add driver %s\n", bus->name, drv->name); + error = kobject_set_name(&drv->kobj, "%s", drv->name); + if (error) + goto out_put_bus; + drv->kobj.kset = &bus->drivers; + if ((error = kobject_register(&drv->kobj))) + goto out_put_bus; + + error = driver_attach(drv); + if (error) + goto out_unregister; + klist_add_tail(&drv->knode_bus, &bus->klist_drivers); + module_add_driver(drv->owner, drv); + + error = driver_add_attrs(bus, drv); + if (error) { + /* How the hell do we get out of this pickle? Give up */ + printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", + __FUNCTION__, drv->name); + } + error = add_bind_files(drv); + if (error) { + /* Ditto */ + printk(KERN_ERR "%s: add_bind_files(%s) failed\n", + __FUNCTION__, drv->name); } + return error; out_unregister: kobject_unregister(&drv->kobj); @@ -565,16 +567,17 @@ out_put_bus: void bus_remove_driver(struct device_driver * drv) { - if (drv->bus) { - remove_bind_files(drv); - driver_remove_attrs(drv->bus, drv); - klist_remove(&drv->knode_bus); - pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); - driver_detach(drv); - module_remove_driver(drv); - kobject_unregister(&drv->kobj); - put_bus(drv->bus); - } + if (!drv->bus) + return; + + remove_bind_files(drv); + driver_remove_attrs(drv->bus, drv); + klist_remove(&drv->knode_bus); + pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); + driver_detach(drv); + module_remove_driver(drv); + kobject_unregister(&drv->kobj); + put_bus(drv->bus); } -- GitLab From 4d664238207a82c4018757e2d87cf2a780462dcd Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 9 Oct 2006 18:04:30 +0900 Subject: [PATCH 1452/1619] driver core: kmalloc() failure check in driver_probe_device driver_probe_device() is missing kmalloc() failure check. Signed-off-by: Akinobu Mita Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index ef7db6939cb..db01b95a47a 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -171,6 +171,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) drv->bus->name, dev->bus_id, drv->name); data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; data->drv = drv; data->dev = dev; -- GitLab From 463c2c12dce78dd0cb77b65beba93f029a164ba3 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:34:41 -0400 Subject: [PATCH 1453/1619] aoe: eliminate isbusy message This message doesn't help users because the circumstance isn't problematic. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoedev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index ed4258a62df..c2bc3edb32c 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -20,11 +20,8 @@ aoedev_isbusy(struct aoedev *d) f = d->frames; e = f + d->nframes; do { - if (f->tag != FREETAG) { - printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n", - d->aoemajor, d->aoeminor); + if (f->tag != FREETAG) return 1; - } } while (++f < e); return 0; -- GitLab From 2611464d7f36685fb1990275d3de1e72e6aff9d9 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:48 -0400 Subject: [PATCH 1454/1619] aoe: update copyright date Update the copyright year to 2006. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 2 +- drivers/block/aoe/aoeblk.c | 2 +- drivers/block/aoe/aoechr.c | 2 +- drivers/block/aoe/aoecmd.c | 2 +- drivers/block/aoe/aoedev.c | 2 +- drivers/block/aoe/aoemain.c | 2 +- drivers/block/aoe/aoenet.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 6eebcb7be97..507c3779988 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ #define VERSION "22" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 393b86a3dbf..fa0e8cae610 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoeblk.c * block device routines diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 1bc1cf9603f..8a7a0819141 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoechr.c * AoE character device driver diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 39da28d344f..d1d8759eca8 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoecmd.c * Filesystem request handling methods diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index c2bc3edb32c..c7e05ed8251 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoedev.c * AoE device utility functions; maintains device list. diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c index de08491ebe6..727c34d8bc7 100644 --- a/drivers/block/aoe/aoemain.c +++ b/drivers/block/aoe/aoemain.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoemain.c * Module initialization routines, discover timer diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index c1434ed1188..1bba140549c 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ /* * aoenet.c * Ethernet portion of AoE driver -- GitLab From 2fdc0ea75b26e3009cfdf72e79901e4e16bb99bd Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:48 -0400 Subject: [PATCH 1455/1619] aoe: remove unused NARGS enum The NARGS enum is left over from older code versions. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoechr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 8a7a0819141..0c543d3bfe5 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -15,7 +15,6 @@ enum { MINOR_INTERFACES, MINOR_REVALIDATE, MSGSZ = 2048, - NARGS = 10, NMSG = 100, /* message backlog to retain */ }; -- GitLab From e407a7f6cd143b3ab4eb3d7e1cf882e96b710eb5 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:49 -0400 Subject: [PATCH 1456/1619] aoe: zero copy write 1 of 2 Avoid memory copy on writes. (This patch depends on fixes in patch 9 to follow.) Although skb->len should not be set when working with linear skbuffs, the skb->tail pointer maintained by skb_put/skb_trim is not relevant to what happens when the skb_fill_page_desc function is called. This issue was raised without comment in linux-kernel and netdev earlier this month: http://thread.gmane.org/gmane.linux.kernel/446474/ http://thread.gmane.org/gmane.linux.network/45444/ So until there is something analogous to skb_put that works for zero-copy write skbuffs, we will do what the other callers of skb_fill_page_desc are doing. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 7 +-- drivers/block/aoe/aoecmd.c | 94 +++++++++++++++----------------------- drivers/block/aoe/aoedev.c | 42 ++++++++++++----- 3 files changed, 69 insertions(+), 74 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 507c3779988..fa2d804b266 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -107,11 +107,7 @@ struct frame { ulong waited; struct buf *buf; char *bufaddr; - int writedatalen; - int ndata; - - /* largest possible */ - unsigned char data[sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr)]; + struct sk_buff *skb; }; struct aoedev { @@ -157,6 +153,7 @@ 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); +struct sk_buff *new_skb(ulong); int aoedev_init(void); void aoedev_exit(void); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d1d8759eca8..1aeb2969987 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -17,15 +17,14 @@ #define MAXTIMER (HZ << 1) #define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */ -static struct sk_buff * -new_skb(struct net_device *if_dev, ulong len) +struct sk_buff * +new_skb(ulong len) { struct sk_buff *skb; skb = alloc_skb(len, GFP_ATOMIC); if (skb) { skb->nh.raw = skb->mac.raw = skb->data; - skb->dev = if_dev; skb->protocol = __constant_htons(ETH_P_AOE); skb->priority = 0; skb_put(skb, len); @@ -40,29 +39,6 @@ new_skb(struct net_device *if_dev, ulong len) return skb; } -static struct sk_buff * -skb_prepare(struct aoedev *d, struct frame *f) -{ - struct sk_buff *skb; - char *p; - - skb = new_skb(d->ifp, f->ndata + f->writedatalen); - if (!skb) { - printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n"); - return NULL; - } - - p = skb->mac.raw; - memcpy(p, f->data, f->ndata); - - if (f->writedatalen) { - p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); - memcpy(p, f->bufaddr, f->writedatalen); - } - - return skb; -} - static struct frame * getframe(struct aoedev *d, int tag) { @@ -129,10 +105,11 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) bcnt = MAXATADATA; /* initialize the headers & frame */ - h = (struct aoe_hdr *) f->data; + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - f->ndata = sizeof *h + sizeof *ah; - memset(h, 0, f->ndata); + skb->len = sizeof *h + sizeof *ah; + memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, h); f->waited = 0; f->buf = buf; @@ -155,11 +132,13 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) } if (bio_data_dir(buf->bio) == WRITE) { + skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), + offset_in_page(f->bufaddr), bcnt); ah->aflags |= AOEAFL_WRITE; - f->writedatalen = bcnt; } else { + skb_shinfo(skb)->nr_frags = 0; + skb->len = ETH_ZLEN; writebit = 0; - f->writedatalen = 0; } ah->cmdstat = WIN_READ | writebit | extbit; @@ -179,15 +158,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; } - skb = skb_prepare(d, f); - if (skb) { - skb->next = NULL; - if (d->sendq_hd) - d->sendq_tl->next = skb; - else - d->sendq_hd = skb; - d->sendq_tl = skb; - } + skb->dev = d->ifp; + skb_get(skb); + skb->next = NULL; + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; } /* some callers cannot sleep, and they can call this function, @@ -209,11 +187,12 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) if (!is_aoe_netif(ifp)) continue; - skb = new_skb(ifp, sizeof *h + sizeof *ch); + skb = new_skb(sizeof *h + sizeof *ch); if (skb == NULL) { printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n"); continue; } + skb->dev = ifp; if (sl_tail == NULL) sl_tail = skb; h = (struct aoe_hdr *) skb->mac.raw; @@ -283,21 +262,21 @@ rexmit(struct aoedev *d, struct frame *f) d->aoemajor, d->aoeminor, f->tag, jiffies, n); aoechr_error(buf); - h = (struct aoe_hdr *) f->data; + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; f->tag = n; h->tag = cpu_to_be32(n); memcpy(h->dst, d->addr, sizeof h->dst); memcpy(h->src, d->ifp->dev_addr, sizeof h->src); - skb = skb_prepare(d, f); - if (skb) { - skb->next = NULL; - if (d->sendq_hd) - d->sendq_tl->next = skb; - else - d->sendq_hd = skb; - d->sendq_tl = skb; - } + skb->dev = d->ifp; + skb_get(skb); + skb->next = NULL; + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; } static int @@ -514,7 +493,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) calc_rttavg(d, tsince(f->tag)); ahin = (struct aoe_atahdr *) (hin+1); - ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr)); + ahout = (struct aoe_atahdr *) (f->skb->mac.raw + sizeof(struct aoe_hdr)); buf = f->buf; if (ahout->cmdstat == WIN_IDENTIFY) @@ -620,20 +599,21 @@ aoecmd_ata_id(struct aoedev *d) } /* initialize the headers & frame */ - h = (struct aoe_hdr *) f->data; + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - f->ndata = sizeof *h + sizeof *ah; - memset(h, 0, f->ndata); + skb->len = sizeof *h + sizeof *ah; + memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, h); f->waited = 0; - f->writedatalen = 0; /* set up ata header */ ah->scnt = 1; ah->cmdstat = WIN_IDENTIFY; ah->lba3 = 0xa0; - skb = skb_prepare(d, f); + skb->dev = d->ifp; + skb_get(skb); d->rttavg = MAXTIMER; d->timer.function = rexmit_timer; diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index c7e05ed8251..abf1d3c073e 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -63,22 +63,32 @@ aoedev_newdev(ulong nframes) struct frame *f, *e; d = kzalloc(sizeof *d, GFP_ATOMIC); - if (d == NULL) - return NULL; f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); - if (f == NULL) { - kfree(d); + switch (!d || !f) { + case 0: + d->nframes = nframes; + d->frames = f; + e = f + nframes; + for (; ftag = FREETAG; + f->skb = new_skb(ETH_ZLEN); + if (!f->skb) + break; + } + if (f == e) + break; + while (f > d->frames) { + f--; + dev_kfree_skb(f->skb); + } + default: + if (f) + kfree(f); + if (d) + kfree(d); return NULL; } - INIT_WORK(&d->work, aoecmd_sleepwork, d); - - d->nframes = nframes; - d->frames = f; - e = f + nframes; - for (; ftag = FREETAG; - spin_lock_init(&d->lock); init_timer(&d->timer); d->timer.data = (ulong) d; @@ -160,11 +170,19 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) static void aoedev_freedev(struct aoedev *d) { + struct frame *f, *e; + if (d->gd) { aoedisk_rm_sysfs(d); del_gendisk(d->gd); put_disk(d->gd); } + f = d->frames; + e = f + d->nframes; + for (; fskb)->nr_frags = 0; + dev_kfree_skb(f->skb); + } kfree(d->frames); if (d->bufpool) mempool_destroy(d->bufpool); -- GitLab From 19bf26353c50bc2be375109ec73f2f0bbd616ed1 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:49 -0400 Subject: [PATCH 1457/1619] aoe: jumbo frame support 1 of 2 Add support for jumbo ethernet frames. (This patch depends on patch 7 to follow.) Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 11 ++++-- drivers/block/aoe/aoechr.c | 1 + drivers/block/aoe/aoecmd.c | 77 +++++++++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index fa2d804b266..1cec19986c4 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -65,7 +65,7 @@ struct aoe_atahdr { struct aoe_cfghdr { __be16 bufcnt; __be16 fwver; - unsigned char res; + unsigned char scnt; unsigned char aoeccmd; unsigned char cslen[2]; }; @@ -78,12 +78,13 @@ enum { DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */ DEVFL_PAUSE = (1<<5), DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */ + DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */ BUFFL_FAIL = 1, }; enum { - MAXATADATA = 1024, + DEFAULTBCNT = 2 * 512, /* 2 sectors */ NPERSHELF = 16, /* number of slots per shelf address */ FREETAG = -1, MIN_BUFS = 8, @@ -107,6 +108,8 @@ struct frame { ulong waited; struct buf *buf; char *bufaddr; + ulong bcnt; + sector_t lba; struct sk_buff *skb; }; @@ -120,6 +123,7 @@ struct aoedev { ulong nopen; /* (bd_openers isn't available without sleeping) */ ulong rttavg; /* round trip average of requests/responses */ u16 fw_ver; /* version of blade's firmware */ + u16 maxbcnt; struct work_struct work;/* disk create work struct */ struct gendisk *gd; request_queue_t blkq; @@ -134,7 +138,8 @@ struct aoedev { struct list_head bufq; /* queue of bios to work on */ struct buf *inprocess; /* the one we're currently working on */ ulong lasttag; /* last tag sent */ - ulong nframes; /* number of frames below */ + ushort lostjumbo; + ushort nframes; /* number of frames below */ struct frame *frames; }; diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 0c543d3bfe5..2b5256cc733 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -89,6 +89,7 @@ revalidate(const char __user *str, size_t size) return -EINVAL; spin_lock_irqsave(&d->lock, flags); + d->flags &= ~DEVFL_MAXBCNT; d->flags |= DEVFL_PAUSE; spin_unlock_irqrestore(&d->lock, flags); aoecmd_cfg(major, minor); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 1aeb2969987..666797d646d 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -83,6 +83,17 @@ aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h) return host_tag; } +static inline void +put_lba(struct aoe_atahdr *ah, sector_t lba) +{ + ah->lba0 = lba; + ah->lba1 = lba >>= 8; + ah->lba2 = lba >>= 8; + ah->lba3 = lba >>= 8; + ah->lba4 = lba >>= 8; + ah->lba5 = lba >>= 8; +} + static void aoecmd_ata_rw(struct aoedev *d, struct frame *f) { @@ -101,8 +112,8 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) sector = buf->sector; bcnt = buf->bv_resid; - if (bcnt > MAXATADATA) - bcnt = MAXATADATA; + if (bcnt > d->maxbcnt) + bcnt = d->maxbcnt; /* initialize the headers & frame */ skb = f->skb; @@ -114,17 +125,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) f->waited = 0; f->buf = buf; f->bufaddr = buf->bufaddr; + f->bcnt = bcnt; + f->lba = sector; /* set up ata header */ ah->scnt = bcnt >> 9; - ah->lba0 = sector; - ah->lba1 = sector >>= 8; - ah->lba2 = sector >>= 8; - ah->lba3 = sector >>= 8; + put_lba(ah, sector); if (d->flags & DEVFL_EXT) { ah->aflags |= AOEAFL_EXT; - ah->lba4 = sector >>= 8; - ah->lba5 = sector >>= 8; } else { extbit = 0; ah->lba3 &= 0x0f; @@ -251,6 +259,7 @@ rexmit(struct aoedev *d, struct frame *f) { struct sk_buff *skb; struct aoe_hdr *h; + struct aoe_atahdr *ah; char buf[128]; u32 n; @@ -264,11 +273,27 @@ rexmit(struct aoedev *d, struct frame *f) skb = f->skb; h = (struct aoe_hdr *) skb->mac.raw; + ah = (struct aoe_atahdr *) (h+1); f->tag = n; h->tag = cpu_to_be32(n); memcpy(h->dst, d->addr, sizeof h->dst); memcpy(h->src, d->ifp->dev_addr, sizeof h->src); + n = DEFAULTBCNT / 512; + if (ah->scnt > n) { + ah->scnt = n; + if (ah->aflags & AOEAFL_WRITE) + skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), + offset_in_page(f->bufaddr), DEFAULTBCNT); + if (++d->lostjumbo > (d->nframes << 1)) + if (d->maxbcnt != DEFAULTBCNT) { + printk(KERN_INFO "aoe: rexmit: too many lost jumbo. " + "dropping back to 1KB frames.\n"); + d->maxbcnt = DEFAULTBCNT; + d->flags |= DEVFL_MAXBCNT; + } + } + skb->dev = d->ifp; skb_get(skb); skb->next = NULL; @@ -506,10 +531,10 @@ aoecmd_ata_rsp(struct sk_buff *skb) if (buf) buf->flags |= BUFFL_FAIL; } else { + n = ahout->scnt << 9; switch (ahout->cmdstat) { case WIN_READ: case WIN_READ_EXT: - n = ahout->scnt << 9; if (skb->len - sizeof *hin - sizeof *ahin < n) { printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt " "ata data size in read. skb->len=%d\n", @@ -521,6 +546,22 @@ aoecmd_ata_rsp(struct sk_buff *skb) memcpy(f->bufaddr, ahin+1, n); case WIN_WRITE: case WIN_WRITE_EXT: + if (f->bcnt -= n) { + f->bufaddr += n; + put_lba(ahout, f->lba += ahout->scnt); + n = f->bcnt > DEFAULTBCNT ? DEFAULTBCNT : f->bcnt; + ahout->scnt = n >> 9; + if (ahout->aflags & AOEAFL_WRITE) + skb_fill_page_desc(f->skb, 0, virt_to_page(f->bufaddr), + offset_in_page(f->bufaddr), n); + skb_get(f->skb); + f->skb->next = NULL; + spin_unlock_irqrestore(&d->lock, flags); + aoenet_xmit(f->skb); + return; + } + if (n > DEFAULTBCNT) + d->lostjumbo = 0; break; case WIN_IDENTIFY: if (skb->len - sizeof *hin - sizeof *ahin < 512) { @@ -628,9 +669,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb) struct aoe_hdr *h; struct aoe_cfghdr *ch; ulong flags, sysminor, aoemajor; - u16 bufcnt; struct sk_buff *sl; enum { MAXFRAMES = 16 }; + u16 n; h = (struct aoe_hdr *) skb->mac.raw; ch = (struct aoe_cfghdr *) (h+1); @@ -654,11 +695,11 @@ aoecmd_cfg_rsp(struct sk_buff *skb) return; } - bufcnt = be16_to_cpu(ch->bufcnt); - if (bufcnt > MAXFRAMES) /* keep it reasonable */ - bufcnt = MAXFRAMES; + n = be16_to_cpu(ch->bufcnt); + if (n > MAXFRAMES) /* keep it reasonable */ + n = MAXFRAMES; - d = aoedev_by_sysminor_m(sysminor, bufcnt); + d = aoedev_by_sysminor_m(sysminor, n); if (d == NULL) { printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n"); return; @@ -669,6 +710,14 @@ aoecmd_cfg_rsp(struct sk_buff *skb) /* permit device to migrate mac and network interface */ d->ifp = skb->dev; memcpy(d->addr, h->src, sizeof d->addr); + if (!(d->flags & DEVFL_MAXBCNT)) { + n = d->ifp->mtu; + n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); + n /= 512; + if (n > ch->scnt) + n = ch->scnt; + d->maxbcnt = n ? n * 512 : DEFAULTBCNT; + } /* don't change users' perspective */ if (d->nopen && !(d->flags & DEVFL_PAUSE)) { -- GitLab From 6bb6285fdb948cedee586c6bebc9ebc5e32a5c35 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:49 -0400 Subject: [PATCH 1458/1619] aoe: clean up printks via macros Use simple macros to clean up the printks. (This patch is reverted by the 14th patch to follow.) Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 5 ++++ drivers/block/aoe/aoeblk.c | 16 +++++------ drivers/block/aoe/aoechr.c | 13 ++++----- drivers/block/aoe/aoecmd.c | 57 +++++++++++++++++-------------------- drivers/block/aoe/aoedev.c | 2 +- drivers/block/aoe/aoemain.c | 8 ++---- drivers/block/aoe/aoenet.c | 7 ++--- 7 files changed, 50 insertions(+), 58 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 1cec19986c4..4d79f1eaf70 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -10,6 +10,11 @@ #define AOE_PARTITIONS (16) #endif +#define xprintk(L, fmt, arg...) printk(L "aoe: " "%s: " fmt, __func__, ## arg) +#define iprintk(fmt, arg...) xprintk(KERN_INFO, fmt, ## arg) +#define eprintk(fmt, arg...) xprintk(KERN_ERR, fmt, ## arg) +#define dprintk(fmt, arg...) xprintk(KERN_DEBUG, fmt, ## arg) + #define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * NPERSHELF + (aoeminor)) #define AOEMAJOR(sysminor) ((sysminor) / NPERSHELF) #define AOEMINOR(sysminor) ((sysminor) % NPERSHELF) diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index fa0e8cae610..a7dbe6f53c1 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -132,8 +132,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) d = bio->bi_bdev->bd_disk->private_data; buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { - printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation " - "failure\n"); + iprintk("buf allocation failure\n"); bio_endio(bio, bio->bi_size, -ENOMEM); return 0; } @@ -150,8 +149,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) spin_lock_irqsave(&d->lock, flags); if ((d->flags & DEVFL_UP) == 0) { - printk(KERN_INFO "aoe: aoeblk_make_request: device %ld.%ld is not up\n", - d->aoemajor, d->aoeminor); + iprintk("device %ld.%ld is not up\n", d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); bio_endio(bio, bio->bi_size, -ENXIO); @@ -176,7 +174,7 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo) struct aoedev *d = bdev->bd_disk->private_data; if ((d->flags & DEVFL_UP) == 0) { - printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n"); + eprintk("disk not up\n"); return -ENODEV; } @@ -203,8 +201,8 @@ aoeblk_gdalloc(void *vp) gd = alloc_disk(AOE_PARTITIONS); if (gd == NULL) { - printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk " - "structure for %ld.%ld\n", d->aoemajor, d->aoeminor); + eprintk("cannot allocate disk structure for %ld.%ld\n", + d->aoemajor, d->aoeminor); spin_lock_irqsave(&d->lock, flags); d->flags &= ~DEVFL_GDALLOC; spin_unlock_irqrestore(&d->lock, flags); @@ -213,8 +211,8 @@ aoeblk_gdalloc(void *vp) d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache); if (d->bufpool == NULL) { - printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool " - "for %ld.%ld\n", d->aoemajor, d->aoeminor); + eprintk("cannot allocate bufpool for %ld.%ld\n", + d->aoemajor, d->aoeminor); put_disk(gd); spin_lock_irqsave(&d->lock, flags); d->flags &= ~DEVFL_GDALLOC; diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 2b5256cc733..f5cab69fbc9 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -55,9 +55,7 @@ static int interfaces(const char __user *str, size_t size) { if (set_aoe_iflist(str, size)) { - printk(KERN_CRIT - "%s: could not set interface list: %s\n", - __FUNCTION__, "too many interfaces"); + eprintk("could not set interface list: too many interfaces\n"); return -EINVAL; } return 0; @@ -80,8 +78,7 @@ revalidate(const char __user *str, size_t size) /* should be e%d.%d format */ n = sscanf(buf, "e%d.%d", &major, &minor); if (n != 2) { - printk(KERN_ERR "aoe: %s: invalid device specification\n", - __FUNCTION__); + eprintk("invalid device specification\n"); return -EINVAL; } d = aoedev_by_aoeaddr(major, minor); @@ -116,7 +113,7 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags); mp = kmalloc(n, GFP_ATOMIC); if (mp == NULL) { - printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ld\n", n); + eprintk("allocation failure, len=%ld\n", n); goto bail; } @@ -141,7 +138,7 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp switch ((unsigned long) filp->private_data) { default: - printk(KERN_INFO "aoe: aoechr_write: can't write to that file.\n"); + iprintk("can't write to that file.\n"); break; case MINOR_DISCOVER: ret = discover(); @@ -250,7 +247,7 @@ aoechr_init(void) n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops); if (n < 0) { - printk(KERN_ERR "aoe: aoechr_init: can't register char device\n"); + eprintk("can't register char device\n"); return n; } sema_init(&emsgs_sema, 0); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 666797d646d..63c456082d8 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -155,7 +155,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) buf->nframesout += 1; buf->bufaddr += bcnt; buf->bv_resid -= bcnt; -/* printk(KERN_INFO "aoe: bv_resid=%ld\n", buf->bv_resid); */ +/* dprintk("bv_resid=%ld\n", buf->bv_resid); */ buf->resid -= bcnt; buf->sector += bcnt >> 9; if (buf->resid == 0) { @@ -197,7 +197,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) skb = new_skb(sizeof *h + sizeof *ch); if (skb == NULL) { - printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n"); + iprintk("skb alloc failure\n"); continue; } skb->dev = ifp; @@ -247,7 +247,7 @@ loop: return; buf = container_of(d->bufq.next, struct buf, bufs); list_del(d->bufq.next); -/*printk(KERN_INFO "aoecmd_work: bi_size=%ld\n", buf->bio->bi_size); */ +/*dprintk("bi_size=%ld\n", buf->bio->bi_size); */ d->inprocess = buf; } aoecmd_ata_rw(d, f); @@ -287,8 +287,7 @@ rexmit(struct aoedev *d, struct frame *f) offset_in_page(f->bufaddr), DEFAULTBCNT); if (++d->lostjumbo > (d->nframes << 1)) if (d->maxbcnt != DEFAULTBCNT) { - printk(KERN_INFO "aoe: rexmit: too many lost jumbo. " - "dropping back to 1KB frames.\n"); + iprintk("too many lost jumbo - using 1KB frames.\n"); d->maxbcnt = DEFAULTBCNT; d->flags |= DEVFL_MAXBCNT; } @@ -435,8 +434,8 @@ ataid_complete(struct aoedev *d, unsigned char *id) } if (d->ssize != ssize) - printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu " - "sectors\n", (unsigned long long)mac_addr(d->addr), + iprintk("%012llx e%lu.%lu v%04x has %llu sectors\n", + (unsigned long long)mac_addr(d->addr), d->aoemajor, d->aoeminor, d->fw_ver, (long long)ssize); d->ssize = ssize; @@ -446,11 +445,9 @@ ataid_complete(struct aoedev *d, unsigned char *id) d->flags |= DEVFL_NEWSIZE; } else { if (d->flags & DEVFL_GDALLOC) { - printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n", - __FUNCTION__, - "can't schedule work for", + eprintk("can't schedule work for e%lu.%lu, %s\n", d->aoemajor, d->aoeminor, - "it's already on! (This really shouldn't happen).\n"); + "it's already on! This shouldn't happen.\n"); return; } d->flags |= DEVFL_GDALLOC; @@ -524,8 +521,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) if (ahout->cmdstat == WIN_IDENTIFY) d->flags &= ~DEVFL_PAUSE; if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ - printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh " - "stat=%2.2Xh from e%ld.%ld\n", + eprintk("ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n", ahout->cmdstat, ahin->cmdstat, d->aoemajor, d->aoeminor); if (buf) @@ -536,8 +532,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) case WIN_READ: case WIN_READ_EXT: if (skb->len - sizeof *hin - sizeof *ahin < n) { - printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt " - "ata data size in read. skb->len=%d\n", + eprintk("runt data size in read. skb->len=%d\n", skb->len); /* fail frame f? just returning will rexmit. */ spin_unlock_irqrestore(&d->lock, flags); @@ -549,10 +544,13 @@ aoecmd_ata_rsp(struct sk_buff *skb) if (f->bcnt -= n) { f->bufaddr += n; put_lba(ahout, f->lba += ahout->scnt); - n = f->bcnt > DEFAULTBCNT ? DEFAULTBCNT : f->bcnt; + n = f->bcnt; + if (n > DEFAULTBCNT) + n = DEFAULTBCNT; ahout->scnt = n >> 9; if (ahout->aflags & AOEAFL_WRITE) - skb_fill_page_desc(f->skb, 0, virt_to_page(f->bufaddr), + skb_fill_page_desc(f->skb, 0, + virt_to_page(f->bufaddr), offset_in_page(f->bufaddr), n); skb_get(f->skb); f->skb->next = NULL; @@ -565,19 +563,18 @@ aoecmd_ata_rsp(struct sk_buff *skb) break; case WIN_IDENTIFY: if (skb->len - sizeof *hin - sizeof *ahin < 512) { - printk(KERN_INFO "aoe: aoecmd_ata_rsp: runt data size " - "in ataid. skb->len=%d\n", skb->len); + iprintk("runt data size in ataid. skb->len=%d\n", + skb->len); spin_unlock_irqrestore(&d->lock, flags); return; } ataid_complete(d, (char *) (ahin+1)); break; default: - printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized " - "outbound ata command %2.2Xh for %d.%d\n", - ahout->cmdstat, - be16_to_cpu(hin->major), - hin->minor); + iprintk("unrecognized ata command %2.2Xh for %d.%d\n", + ahout->cmdstat, + be16_to_cpu(hin->major), + hin->minor); } } @@ -634,8 +631,7 @@ aoecmd_ata_id(struct aoedev *d) f = getframe(d, FREETAG); if (f == NULL) { - printk(KERN_CRIT "aoe: aoecmd_ata_id: can't get a frame. " - "This shouldn't happen.\n"); + eprintk("can't get a frame. This shouldn't happen.\n"); return NULL; } @@ -682,15 +678,14 @@ aoecmd_cfg_rsp(struct sk_buff *skb) */ aoemajor = be16_to_cpu(h->major); if (aoemajor == 0xfff) { - printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf " - "address is all ones. Check shelf dip switches\n"); + eprintk("Warning: shelf address is all ones. " + "Check shelf dip switches.\n"); return; } sysminor = SYSMINOR(aoemajor, h->minor); if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { - printk(KERN_INFO - "aoe: e%ld.%d: minor number too large\n", + iprintk("e%ld.%d: minor number too large\n", aoemajor, (int) h->minor); return; } @@ -701,7 +696,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) d = aoedev_by_sysminor_m(sysminor, n); if (d == NULL) { - printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n"); + iprintk("device sysminor_m failure\n"); return; } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index abf1d3c073e..f51d87bbb50 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -155,7 +155,7 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) d = aoedev_newdev(bufcnt); if (d == NULL) { spin_unlock_irqrestore(&devlist_lock, flags); - printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); + iprintk("aoedev_newdev failure.\n"); return NULL; } d->sysminor = sysminor; diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c index 727c34d8bc7..13e634db6fd 100644 --- a/drivers/block/aoe/aoemain.c +++ b/drivers/block/aoe/aoemain.c @@ -84,13 +84,11 @@ aoe_init(void) goto net_fail; ret = register_blkdev(AOE_MAJOR, DEVICE_NAME); if (ret < 0) { - printk(KERN_ERR "aoe: aoeblk_init: can't register major\n"); + eprintk("can't register major\n"); goto blkreg_fail; } - printk(KERN_INFO - "aoe: aoe_init: AoE v%s initialised.\n", - VERSION); + iprintk("AoE v%s initialised.\n", VERSION); discover_timer(TINIT); return 0; @@ -103,7 +101,7 @@ aoe_init(void) chr_fail: aoedev_exit(); - printk(KERN_INFO "aoe: aoe_init: initialisation failure.\n"); + iprintk("initialisation failure.\n"); return ret; } diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 1bba140549c..f1cf2666fc7 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -74,7 +74,7 @@ set_aoe_iflist(const char __user *user_str, size_t size) return -EINVAL; if (copy_from_user(aoe_iflist, user_str, size)) { - printk(KERN_INFO "aoe: %s: copy from user failed\n", __FUNCTION__); + iprintk("copy from user failed\n"); return -EFAULT; } aoe_iflist[size] = 0x00; @@ -132,8 +132,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, if (n > NECODES) n = 0; if (net_ratelimit()) - printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; " - "ecode=%d '%s'\n", + eprintk("error packet from %d.%d; ecode=%d '%s'\n", be16_to_cpu(h->major), h->minor, h->err, aoe_errlist[n]); goto exit; @@ -147,7 +146,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, aoecmd_cfg_rsp(skb); break; default: - printk(KERN_INFO "aoe: aoenet_rcv: unknown cmd %d\n", h->cmd); + iprintk("unknown cmd %d\n", h->cmd); } exit: dev_kfree_skb(skb); -- GitLab From ddec63e86752b89776547e93aa68af01f1cbb10c Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:49 -0400 Subject: [PATCH 1459/1619] aoe: jumbo frame support 2 of 2 Add support for jumbo ethernet frames. (This patch follows patch 5.) Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoecmd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 63c456082d8..621fdbbc4cd 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -475,7 +475,7 @@ void aoecmd_ata_rsp(struct sk_buff *skb) { struct aoedev *d; - struct aoe_hdr *hin; + struct aoe_hdr *hin, *hout; struct aoe_atahdr *ahin, *ahout; struct frame *f; struct buf *buf; @@ -515,7 +515,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) calc_rttavg(d, tsince(f->tag)); ahin = (struct aoe_atahdr *) (hin+1); - ahout = (struct aoe_atahdr *) (f->skb->mac.raw + sizeof(struct aoe_hdr)); + hout = (struct aoe_hdr *) f->skb->mac.raw; + ahout = (struct aoe_atahdr *) (hout+1); buf = f->buf; if (ahout->cmdstat == WIN_IDENTIFY) @@ -552,6 +553,9 @@ aoecmd_ata_rsp(struct sk_buff *skb) skb_fill_page_desc(f->skb, 0, virt_to_page(f->bufaddr), offset_in_page(f->bufaddr), n); + f->tag = newtag(d); + hout->tag = cpu_to_be32(f->tag); + skb->dev = d->ifp; skb_get(f->skb); f->skb->next = NULL; spin_unlock_irqrestore(&d->lock, flags); -- GitLab From dced3a053dd5415a7321e1ae153c96dea644da4e Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:49 -0400 Subject: [PATCH 1460/1619] aoe: improve retransmission heuristics Add a dynamic minimum timer for better retransmission behavior. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 7 ++++--- drivers/block/aoe/aoecmd.c | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 4d79f1eaf70..7b112174863 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -125,8 +125,10 @@ struct aoedev { ulong sysminor; ulong aoemajor; ulong aoeminor; - ulong nopen; /* (bd_openers isn't available without sleeping) */ - ulong rttavg; /* round trip average of requests/responses */ + u16 nopen; /* (bd_openers isn't available without sleeping) */ + u16 lasttag; /* last tag sent */ + u16 rttavg; /* round trip average of requests/responses */ + u16 mintimer; u16 fw_ver; /* version of blade's firmware */ u16 maxbcnt; struct work_struct work;/* disk create work struct */ @@ -142,7 +144,6 @@ struct aoedev { mempool_t *bufpool; /* for deadlock-free Buf allocation */ struct list_head bufq; /* queue of bios to work on */ struct buf *inprocess; /* the one we're currently working on */ - ulong lasttag; /* last tag sent */ ushort lostjumbo; ushort nframes; /* number of frames below */ struct frame *frames; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 621fdbbc4cd..c0bdc1fe21f 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -461,8 +461,15 @@ calc_rttavg(struct aoedev *d, int rtt) register long n; n = rtt; - if (n < MINTIMER) - n = MINTIMER; + if (n < 0) { + n = -rtt; + if (n < MINTIMER) + n = MINTIMER; + else if (n > MAXTIMER) + n = MAXTIMER; + d->mintimer += (n - d->mintimer) >> 1; + } else if (n < d->mintimer) + n = d->mintimer; else if (n > MAXTIMER) n = MAXTIMER; @@ -498,8 +505,10 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - f = getframe(d, be32_to_cpu(hin->tag)); + n = be32_to_cpu(hin->tag); + f = getframe(d, n); if (f == NULL) { + calc_rttavg(d, -tsince(n)); spin_unlock_irqrestore(&d->lock, flags); snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", @@ -724,6 +733,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) return; } d->flags |= DEVFL_PAUSE; /* force pause */ + d->mintimer = MINTIMER; d->fw_ver = be16_to_cpu(ch->fwver); /* check for already outstanding ataid */ -- GitLab From 4f51dc5e9ae195d2e8c22e5f574e004c2f6518a4 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:49 -0400 Subject: [PATCH 1461/1619] aoe: zero copy write 2 of 2 Avoid memory copy on writes. (This patch follows patch 4.) Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 1 + drivers/block/aoe/aoecmd.c | 82 ++++++++++++++++++++++++++++---------- drivers/block/aoe/aoedev.c | 1 + 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 7b112174863..b41fdfe0f4b 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -84,6 +84,7 @@ enum { DEVFL_PAUSE = (1<<5), DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */ DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */ + DEVFL_KICKME = (1<<8), BUFFL_FAIL = 1, }; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index c0bdc1fe21f..9ebc98ade3c 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -120,7 +120,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); skb->len = sizeof *h + sizeof *ah; - memset(h, 0, skb->len); + memset(h, 0, ETH_ZLEN); f->tag = aoehdr_atainit(d, h); f->waited = 0; f->buf = buf; @@ -143,8 +143,9 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), offset_in_page(f->bufaddr), bcnt); ah->aflags |= AOEAFL_WRITE; + skb->len += bcnt; + skb->data_len = bcnt; } else { - skb_shinfo(skb)->nr_frags = 0; skb->len = ETH_ZLEN; writebit = 0; } @@ -167,8 +168,9 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) } skb->dev = d->ifp; - skb_get(skb); - skb->next = NULL; + skb = skb_clone(skb, GFP_ATOMIC); + if (skb == NULL) + return; if (d->sendq_hd) d->sendq_tl->next = skb; else @@ -224,6 +226,29 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) return sl; } +static struct frame * +freeframe(struct aoedev *d) +{ + struct frame *f, *e; + int n = 0; + + f = d->frames; + e = f + d->nframes; + for (; ftag != FREETAG) + continue; + if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { + skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; + return f; + } + n++; + } + if (n == d->nframes) /* wait for network layer */ + d->flags |= DEVFL_KICKME; + + return NULL; +} + /* enters with d->lock held */ void aoecmd_work(struct aoedev *d) @@ -239,7 +264,7 @@ aoecmd_work(struct aoedev *d) } loop: - f = getframe(d, FREETAG); + f = freeframe(d); if (f == NULL) return; if (d->inprocess == NULL) { @@ -282,20 +307,25 @@ rexmit(struct aoedev *d, struct frame *f) n = DEFAULTBCNT / 512; if (ah->scnt > n) { ah->scnt = n; - if (ah->aflags & AOEAFL_WRITE) + if (ah->aflags & AOEAFL_WRITE) { skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), offset_in_page(f->bufaddr), DEFAULTBCNT); + skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT; + skb->data_len = DEFAULTBCNT; + } if (++d->lostjumbo > (d->nframes << 1)) if (d->maxbcnt != DEFAULTBCNT) { - iprintk("too many lost jumbo - using 1KB frames.\n"); + iprintk("e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", + d->aoemajor, d->aoeminor, d->ifp->name); d->maxbcnt = DEFAULTBCNT; d->flags |= DEVFL_MAXBCNT; } } skb->dev = d->ifp; - skb_get(skb); - skb->next = NULL; + skb = skb_clone(skb, GFP_ATOMIC); + if (skb == NULL) + return; if (d->sendq_hd) d->sendq_tl->next = skb; else @@ -350,6 +380,10 @@ rexmit_timer(ulong vp) rexmit(d, f); } } + if (d->flags & DEVFL_KICKME) { + d->flags &= ~DEVFL_KICKME; + aoecmd_work(d); + } sl = d->sendq_hd; d->sendq_hd = d->sendq_tl = NULL; @@ -552,23 +586,27 @@ aoecmd_ata_rsp(struct sk_buff *skb) case WIN_WRITE: case WIN_WRITE_EXT: if (f->bcnt -= n) { + skb = f->skb; f->bufaddr += n; put_lba(ahout, f->lba += ahout->scnt); n = f->bcnt; if (n > DEFAULTBCNT) n = DEFAULTBCNT; ahout->scnt = n >> 9; - if (ahout->aflags & AOEAFL_WRITE) - skb_fill_page_desc(f->skb, 0, + if (ahout->aflags & AOEAFL_WRITE) { + skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), offset_in_page(f->bufaddr), n); + skb->len = sizeof *hout + sizeof *ahout + n; + skb->data_len = n; + } f->tag = newtag(d); hout->tag = cpu_to_be32(f->tag); skb->dev = d->ifp; - skb_get(f->skb); - f->skb->next = NULL; + skb = skb_clone(skb, GFP_ATOMIC); spin_unlock_irqrestore(&d->lock, flags); - aoenet_xmit(f->skb); + if (skb) + aoenet_xmit(skb); return; } if (n > DEFAULTBCNT) @@ -642,7 +680,7 @@ aoecmd_ata_id(struct aoedev *d) struct frame *f; struct sk_buff *skb; - f = getframe(d, FREETAG); + f = freeframe(d); if (f == NULL) { eprintk("can't get a frame. This shouldn't happen.\n"); return NULL; @@ -652,8 +690,8 @@ aoecmd_ata_id(struct aoedev *d) skb = f->skb; h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - skb->len = sizeof *h + sizeof *ah; - memset(h, 0, skb->len); + skb->len = ETH_ZLEN; + memset(h, 0, ETH_ZLEN); f->tag = aoehdr_atainit(d, h); f->waited = 0; @@ -663,12 +701,11 @@ aoecmd_ata_id(struct aoedev *d) ah->lba3 = 0xa0; skb->dev = d->ifp; - skb_get(skb); d->rttavg = MAXTIMER; d->timer.function = rexmit_timer; - return skb; + return skb_clone(skb, GFP_ATOMIC); } void @@ -724,7 +761,12 @@ aoecmd_cfg_rsp(struct sk_buff *skb) n /= 512; if (n > ch->scnt) n = ch->scnt; - d->maxbcnt = n ? n * 512 : DEFAULTBCNT; + n = n ? n * 512 : DEFAULTBCNT; + if (n != d->maxbcnt) { + iprintk("e%ld.%ld: setting %d byte data frames on %s\n", + d->aoemajor, d->aoeminor, n, d->ifp->name); + d->maxbcnt = n; + } } /* don't change users' perspective */ diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index f51d87bbb50..7fd63d4daf5 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -121,6 +121,7 @@ aoedev_downdev(struct aoedev *d) mempool_free(buf, d->bufpool); bio_endio(bio, bio->bi_size, -EIO); } + skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; } d->inprocess = NULL; -- GitLab From b751e8b6590efdb76e1682c85bfcd5f3531ccae4 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:50 -0400 Subject: [PATCH 1462/1619] aoe: module parameter for device timeout The aoe_deadsecs module parameter sets the number of seconds that elapse before a nonresponsive AoE device is marked as dead. This is runtime settable in sysfs or settable with a module load or kernel boot parameter. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoecmd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 9ebc98ade3c..f2b8f558e1b 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -15,7 +15,10 @@ #define TIMERTICK (HZ / 10) #define MINTIMER (2 * TIMERTICK) #define MAXTIMER (HZ << 1) -#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */ + +static int aoe_deadsecs = 60 * 3; +module_param(aoe_deadsecs, int, 0644); +MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); struct sk_buff * new_skb(ulong len) @@ -373,7 +376,7 @@ rexmit_timer(ulong vp) if (f->tag != FREETAG && tsince(f->tag) >= timeout) { n = f->waited += timeout; n /= HZ; - if (n > MAXWAIT) { /* waited too long. device failure. */ + if (n > aoe_deadsecs) { /* waited too long for response */ aoedev_downdev(d); break; } -- GitLab From 392e4845f9728114f7ffa8d7612683397fd4d441 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:50 -0400 Subject: [PATCH 1463/1619] aoe: use bio->bi_idx Instead of starting with bio->bi_io_vec, use the offset in bio->bi_idx. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoeblk.c | 3 ++- drivers/block/aoe/aoecmd.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index a7dbe6f53c1..196ae7a3764 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -142,7 +142,8 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) buf->bio = bio; buf->resid = bio->bi_size; buf->sector = bio->bi_sector; - buf->bv = buf->bio->bi_io_vec; + buf->bv = &bio->bi_io_vec[bio->bi_idx]; + WARN_ON(buf->bv->bv_len == 0); buf->bv_resid = buf->bv->bv_len; buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index f2b8f558e1b..2d0bcdd9669 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -166,6 +166,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) d->inprocess = NULL; } else if (buf->bv_resid == 0) { buf->bv++; + WARN_ON(buf->bv->bv_len == 0); buf->bv_resid = buf->bv->bv_len; buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; } -- GitLab From b849086d8f77f8a1269a01d5552fbf355311f7ac Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:51 -0400 Subject: [PATCH 1464/1619] aoe: remove sysfs comment Remove unecessary comment. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoeblk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 196ae7a3764..088acf48ffa 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -14,7 +14,6 @@ static kmem_cache_t *buf_pool_cache; -/* add attributes for our block devices in sysfs */ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) { struct aoedev *d = disk->private_data; -- GitLab From 086216db1435f44a58c18454acfa59f013510c95 Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:51 -0400 Subject: [PATCH 1465/1619] aoe: update driver version Update aoe driver version number to 32. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index b41fdfe0f4b..188bf09876d 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ /* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "22" +#define VERSION "32" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" -- GitLab From a12c93f08b8fc83b7fcdabaf92b1adcea7489f5e Mon Sep 17 00:00:00 2001 From: "Ed L. Cashin" Date: Wed, 20 Sep 2006 14:36:51 -0400 Subject: [PATCH 1466/1619] aoe: revert printk macros This patch addresses the concern that the aoe driver should not introduce unecessary conventions that must be learned by the reader. It reverts patch 6. Signed-off-by: "Ed L. Cashin" Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoe.h | 5 ----- drivers/block/aoe/aoeblk.c | 11 ++++++----- drivers/block/aoe/aoechr.c | 11 ++++++----- drivers/block/aoe/aoecmd.c | 35 ++++++++++++++++++++--------------- drivers/block/aoe/aoedev.c | 2 +- drivers/block/aoe/aoemain.c | 6 +++--- drivers/block/aoe/aoenet.c | 6 +++--- 7 files changed, 39 insertions(+), 37 deletions(-) diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 188bf09876d..6d111228cfa 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -10,11 +10,6 @@ #define AOE_PARTITIONS (16) #endif -#define xprintk(L, fmt, arg...) printk(L "aoe: " "%s: " fmt, __func__, ## arg) -#define iprintk(fmt, arg...) xprintk(KERN_INFO, fmt, ## arg) -#define eprintk(fmt, arg...) xprintk(KERN_ERR, fmt, ## arg) -#define dprintk(fmt, arg...) xprintk(KERN_DEBUG, fmt, ## arg) - #define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * NPERSHELF + (aoeminor)) #define AOEMAJOR(sysminor) ((sysminor) / NPERSHELF) #define AOEMINOR(sysminor) ((sysminor) % NPERSHELF) diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 088acf48ffa..4259b52b01e 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -131,7 +131,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) d = bio->bi_bdev->bd_disk->private_data; buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { - iprintk("buf allocation failure\n"); + printk(KERN_INFO "aoe: buf allocation failure\n"); bio_endio(bio, bio->bi_size, -ENOMEM); return 0; } @@ -149,7 +149,8 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) spin_lock_irqsave(&d->lock, flags); if ((d->flags & DEVFL_UP) == 0) { - iprintk("device %ld.%ld is not up\n", d->aoemajor, d->aoeminor); + printk(KERN_INFO "aoe: device %ld.%ld is not up\n", + d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); bio_endio(bio, bio->bi_size, -ENXIO); @@ -174,7 +175,7 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo) struct aoedev *d = bdev->bd_disk->private_data; if ((d->flags & DEVFL_UP) == 0) { - eprintk("disk not up\n"); + printk(KERN_ERR "aoe: disk not up\n"); return -ENODEV; } @@ -201,7 +202,7 @@ aoeblk_gdalloc(void *vp) gd = alloc_disk(AOE_PARTITIONS); if (gd == NULL) { - eprintk("cannot allocate disk structure for %ld.%ld\n", + printk(KERN_ERR "aoe: cannot allocate disk structure for %ld.%ld\n", d->aoemajor, d->aoeminor); spin_lock_irqsave(&d->lock, flags); d->flags &= ~DEVFL_GDALLOC; @@ -211,7 +212,7 @@ aoeblk_gdalloc(void *vp) d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache); if (d->bufpool == NULL) { - eprintk("cannot allocate bufpool for %ld.%ld\n", + printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%ld\n", d->aoemajor, d->aoeminor); put_disk(gd); spin_lock_irqsave(&d->lock, flags); diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index f5cab69fbc9..e22b4c9520a 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -55,7 +55,8 @@ static int interfaces(const char __user *str, size_t size) { if (set_aoe_iflist(str, size)) { - eprintk("could not set interface list: too many interfaces\n"); + printk(KERN_ERR + "aoe: could not set interface list: too many interfaces\n"); return -EINVAL; } return 0; @@ -78,7 +79,7 @@ revalidate(const char __user *str, size_t size) /* should be e%d.%d format */ n = sscanf(buf, "e%d.%d", &major, &minor); if (n != 2) { - eprintk("invalid device specification\n"); + printk(KERN_ERR "aoe: invalid device specification\n"); return -EINVAL; } d = aoedev_by_aoeaddr(major, minor); @@ -113,7 +114,7 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags); mp = kmalloc(n, GFP_ATOMIC); if (mp == NULL) { - eprintk("allocation failure, len=%ld\n", n); + printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n); goto bail; } @@ -138,7 +139,7 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp switch ((unsigned long) filp->private_data) { default: - iprintk("can't write to that file.\n"); + printk(KERN_INFO "aoe: can't write to that file.\n"); break; case MINOR_DISCOVER: ret = discover(); @@ -247,7 +248,7 @@ aoechr_init(void) n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops); if (n < 0) { - eprintk("can't register char device\n"); + printk(KERN_ERR "aoe: can't register char device\n"); return n; } sema_init(&emsgs_sema, 0); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 2d0bcdd9669..8a13b1af8ba 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -159,7 +159,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) buf->nframesout += 1; buf->bufaddr += bcnt; buf->bv_resid -= bcnt; -/* dprintk("bv_resid=%ld\n", buf->bv_resid); */ +/* printk(KERN_DEBUG "aoe: bv_resid=%ld\n", buf->bv_resid); */ buf->resid -= bcnt; buf->sector += bcnt >> 9; if (buf->resid == 0) { @@ -203,7 +203,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) skb = new_skb(sizeof *h + sizeof *ch); if (skb == NULL) { - iprintk("skb alloc failure\n"); + printk(KERN_INFO "aoe: skb alloc failure\n"); continue; } skb->dev = ifp; @@ -276,7 +276,7 @@ loop: return; buf = container_of(d->bufq.next, struct buf, bufs); list_del(d->bufq.next); -/*dprintk("bi_size=%ld\n", buf->bio->bi_size); */ +/*printk(KERN_DEBUG "aoe: bi_size=%ld\n", buf->bio->bi_size); */ d->inprocess = buf; } aoecmd_ata_rw(d, f); @@ -319,7 +319,7 @@ rexmit(struct aoedev *d, struct frame *f) } if (++d->lostjumbo > (d->nframes << 1)) if (d->maxbcnt != DEFAULTBCNT) { - iprintk("e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", + printk(KERN_INFO "aoe: e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", d->aoemajor, d->aoeminor, d->ifp->name); d->maxbcnt = DEFAULTBCNT; d->flags |= DEVFL_MAXBCNT; @@ -472,7 +472,7 @@ ataid_complete(struct aoedev *d, unsigned char *id) } if (d->ssize != ssize) - iprintk("%012llx e%lu.%lu v%04x has %llu sectors\n", + printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n", (unsigned long long)mac_addr(d->addr), d->aoemajor, d->aoeminor, d->fw_ver, (long long)ssize); @@ -483,7 +483,7 @@ ataid_complete(struct aoedev *d, unsigned char *id) d->flags |= DEVFL_NEWSIZE; } else { if (d->flags & DEVFL_GDALLOC) { - eprintk("can't schedule work for e%lu.%lu, %s\n", + printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n", d->aoemajor, d->aoeminor, "it's already on! This shouldn't happen.\n"); return; @@ -569,7 +569,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) if (ahout->cmdstat == WIN_IDENTIFY) d->flags &= ~DEVFL_PAUSE; if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ - eprintk("ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n", + printk(KERN_ERR + "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n", ahout->cmdstat, ahin->cmdstat, d->aoemajor, d->aoeminor); if (buf) @@ -580,7 +581,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) case WIN_READ: case WIN_READ_EXT: if (skb->len - sizeof *hin - sizeof *ahin < n) { - eprintk("runt data size in read. skb->len=%d\n", + printk(KERN_ERR + "aoe: runt data size in read. skb->len=%d\n", skb->len); /* fail frame f? just returning will rexmit. */ spin_unlock_irqrestore(&d->lock, flags); @@ -618,7 +620,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) break; case WIN_IDENTIFY: if (skb->len - sizeof *hin - sizeof *ahin < 512) { - iprintk("runt data size in ataid. skb->len=%d\n", + printk(KERN_INFO + "aoe: runt data size in ataid. skb->len=%d\n", skb->len); spin_unlock_irqrestore(&d->lock, flags); return; @@ -626,7 +629,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) ataid_complete(d, (char *) (ahin+1)); break; default: - iprintk("unrecognized ata command %2.2Xh for %d.%d\n", + printk(KERN_INFO + "aoe: unrecognized ata command %2.2Xh for %d.%d\n", ahout->cmdstat, be16_to_cpu(hin->major), hin->minor); @@ -686,7 +690,7 @@ aoecmd_ata_id(struct aoedev *d) f = freeframe(d); if (f == NULL) { - eprintk("can't get a frame. This shouldn't happen.\n"); + printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n"); return NULL; } @@ -732,14 +736,14 @@ aoecmd_cfg_rsp(struct sk_buff *skb) */ aoemajor = be16_to_cpu(h->major); if (aoemajor == 0xfff) { - eprintk("Warning: shelf address is all ones. " + printk(KERN_ERR "aoe: Warning: shelf address is all ones. " "Check shelf dip switches.\n"); return; } sysminor = SYSMINOR(aoemajor, h->minor); if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { - iprintk("e%ld.%d: minor number too large\n", + printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", aoemajor, (int) h->minor); return; } @@ -750,7 +754,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) d = aoedev_by_sysminor_m(sysminor, n); if (d == NULL) { - iprintk("device sysminor_m failure\n"); + printk(KERN_INFO "aoe: device sysminor_m failure\n"); return; } @@ -767,7 +771,8 @@ aoecmd_cfg_rsp(struct sk_buff *skb) n = ch->scnt; n = n ? n * 512 : DEFAULTBCNT; if (n != d->maxbcnt) { - iprintk("e%ld.%ld: setting %d byte data frames on %s\n", + printk(KERN_INFO + "aoe: e%ld.%ld: setting %d byte data frames on %s\n", d->aoemajor, d->aoeminor, n, d->ifp->name); d->maxbcnt = n; } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 7fd63d4daf5..6125921bbec 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -156,7 +156,7 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) d = aoedev_newdev(bufcnt); if (d == NULL) { spin_unlock_irqrestore(&devlist_lock, flags); - iprintk("aoedev_newdev failure.\n"); + printk(KERN_INFO "aoe: aoedev_newdev failure.\n"); return NULL; } d->sysminor = sysminor; diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c index 13e634db6fd..a04b7d61329 100644 --- a/drivers/block/aoe/aoemain.c +++ b/drivers/block/aoe/aoemain.c @@ -84,11 +84,11 @@ aoe_init(void) goto net_fail; ret = register_blkdev(AOE_MAJOR, DEVICE_NAME); if (ret < 0) { - eprintk("can't register major\n"); + printk(KERN_ERR "aoe: can't register major\n"); goto blkreg_fail; } - iprintk("AoE v%s initialised.\n", VERSION); + printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION); discover_timer(TINIT); return 0; @@ -101,7 +101,7 @@ aoe_init(void) chr_fail: aoedev_exit(); - iprintk("initialisation failure.\n"); + printk(KERN_INFO "aoe: initialisation failure.\n"); return ret; } diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index f1cf2666fc7..9626e0f5da9 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -74,7 +74,7 @@ set_aoe_iflist(const char __user *user_str, size_t size) return -EINVAL; if (copy_from_user(aoe_iflist, user_str, size)) { - iprintk("copy from user failed\n"); + printk(KERN_INFO "aoe: copy from user failed\n"); return -EFAULT; } aoe_iflist[size] = 0x00; @@ -132,7 +132,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, if (n > NECODES) n = 0; if (net_ratelimit()) - eprintk("error packet from %d.%d; ecode=%d '%s'\n", + printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n", be16_to_cpu(h->major), h->minor, h->err, aoe_errlist[n]); goto exit; @@ -146,7 +146,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, aoecmd_cfg_rsp(skb); break; default: - iprintk("unknown cmd %d\n", h->cmd); + printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd); } exit: dev_kfree_skb(skb); -- GitLab From 4ca5224f3ea4779054d96e885ca9b3980801ce13 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 9 Apr 2002 12:14:34 -0700 Subject: [PATCH 1467/1619] aoe: fix sysfs_create_file warnings Moved the attributes into a group, making the compiler be quiet about ignoring the return value of the file create calls. This also also fixed a bug when removing the files, which were not symlinks. Cc: "Ed L. Cashin" Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/block/aoe/aoeblk.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 4259b52b01e..d433f27e0ce 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -63,21 +63,26 @@ static struct disk_attribute disk_attr_fwver = { .show = aoedisk_show_fwver }; -static void +static struct attribute *aoe_attrs[] = { + &disk_attr_state.attr, + &disk_attr_mac.attr, + &disk_attr_netif.attr, + &disk_attr_fwver.attr, +}; + +static const struct attribute_group attr_group = { + .attrs = aoe_attrs, +}; + +static int aoedisk_add_sysfs(struct aoedev *d) { - sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr); - sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr); - sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr); - sysfs_create_file(&d->gd->kobj, &disk_attr_fwver.attr); + return sysfs_create_group(&d->gd->kobj, &attr_group); } void aoedisk_rm_sysfs(struct aoedev *d) { - sysfs_remove_link(&d->gd->kobj, "state"); - sysfs_remove_link(&d->gd->kobj, "mac"); - sysfs_remove_link(&d->gd->kobj, "netif"); - sysfs_remove_link(&d->gd->kobj, "firmware-version"); + sysfs_remove_group(&d->gd->kobj, &attr_group); } static int -- GitLab From 34fc921a253f3ddfc4ad9de1dbc88683f84fbaaa Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sun, 8 Oct 2006 21:56:29 +0200 Subject: [PATCH 1468/1619] w83791d: Fix unchecked return status Replace all unchecked calls to device_create_file with a single group declaration, and one call to sysfs_create_group, and check that one return status. Also remove the files on device detach. Signed-off-by: Jim Cromie Signed-off by: Charles Spirakis Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83791d.c | 85 +++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 371ed4f69a9..9e5f885368b 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -746,6 +746,52 @@ static ssize_t store_vrm_reg(struct device *dev, static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define IN_UNIT_ATTRS(X) \ + &sda_in_input[X].dev_attr.attr, \ + &sda_in_min[X].dev_attr.attr, \ + &sda_in_max[X].dev_attr.attr + +#define FAN_UNIT_ATTRS(X) \ + &sda_fan_input[X].dev_attr.attr, \ + &sda_fan_min[X].dev_attr.attr, \ + &sda_fan_div[X].dev_attr.attr + +#define TEMP_UNIT_ATTRS(X) \ + &sda_temp_input[X].dev_attr.attr, \ + &sda_temp_max[X].dev_attr.attr, \ + &sda_temp_max_hyst[X].dev_attr.attr + +static struct attribute *w83791d_attributes[] = { + IN_UNIT_ATTRS(0), + IN_UNIT_ATTRS(1), + IN_UNIT_ATTRS(2), + IN_UNIT_ATTRS(3), + IN_UNIT_ATTRS(4), + IN_UNIT_ATTRS(5), + IN_UNIT_ATTRS(6), + IN_UNIT_ATTRS(7), + IN_UNIT_ATTRS(8), + IN_UNIT_ATTRS(9), + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + FAN_UNIT_ATTRS(3), + FAN_UNIT_ATTRS(4), + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), + &dev_attr_alarms.attr, + &sda_beep_ctrl[0].dev_attr.attr, + &sda_beep_ctrl[1].dev_attr.attr, + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + NULL +}; + +static const struct attribute_group w83791d_group = { + .attrs = w83791d_attributes, +}; + /* This function is called when: * w83791d_driver is inserted (when this module is loaded), for each available adapter @@ -967,41 +1013,20 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind) } /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group))) + goto error3; + + /* Everything is ready, now register the working device */ data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto error3; + goto error4; } - for (i = 0; i < NUMBER_OF_VIN; i++) { - device_create_file(dev, &sda_in_input[i].dev_attr); - device_create_file(dev, &sda_in_min[i].dev_attr); - device_create_file(dev, &sda_in_max[i].dev_attr); - } - - for (i = 0; i < NUMBER_OF_FANIN; i++) { - device_create_file(dev, &sda_fan_input[i].dev_attr); - device_create_file(dev, &sda_fan_div[i].dev_attr); - device_create_file(dev, &sda_fan_min[i].dev_attr); - } - - for (i = 0; i < NUMBER_OF_TEMPIN; i++) { - device_create_file(dev, &sda_temp_input[i].dev_attr); - device_create_file(dev, &sda_temp_max[i].dev_attr); - device_create_file(dev, &sda_temp_max_hyst[i].dev_attr); - } - - device_create_file(dev, &dev_attr_alarms); - - for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) { - device_create_file(dev, &sda_beep_ctrl[i].dev_attr); - } - - device_create_file(dev, &dev_attr_cpu0_vid); - device_create_file(dev, &dev_attr_vrm); - return 0; +error4: + sysfs_remove_group(&client->dev.kobj, &w83791d_group); error3: if (data->lm75[0] != NULL) { i2c_detach_client(data->lm75[0]); @@ -1025,8 +1050,10 @@ static int w83791d_detach_client(struct i2c_client *client) int err; /* main client */ - if (data) + if (data) { hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &w83791d_group); + } if ((err = i2c_detach_client(client))) return err; -- GitLab From 2ca7b961c3c9f072d307293aad0f9705522e916a Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Sun, 8 Oct 2006 21:57:41 +0200 Subject: [PATCH 1469/1619] adm9240: Update Grant Coady's email address Replace a bouncing email that I cannot recover from Mr Google. Signed-off-by: Grant Coady Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/adm9240 | 2 +- drivers/hwmon/adm9240.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/hwmon/adm9240 b/Documentation/hwmon/adm9240 index 35f618f3289..2c6f1fed461 100644 --- a/Documentation/hwmon/adm9240 +++ b/Documentation/hwmon/adm9240 @@ -24,7 +24,7 @@ Authors: Frodo Looijaard , Philip Edelbrock , Michiel Rook , - Grant Coady with guidance + Grant Coady with guidance from Jean Delvare Interface diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 377961c4a41..aad594adf0c 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -5,7 +5,7 @@ * Copyright (C) 1999 Frodo Looijaard * Philip Edelbrock * Copyright (C) 2003 Michiel Rook - * Copyright (C) 2005 Grant Coady with valuable + * Copyright (C) 2005 Grant Coady with valuable * guidance from Jean Delvare * * Driver supports Analog Devices ADM9240 @@ -774,7 +774,7 @@ static void __exit sensors_adm9240_exit(void) } MODULE_AUTHOR("Michiel Rook , " - "Grant Coady and others"); + "Grant Coady and others"); MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); MODULE_LICENSE("GPL"); -- GitLab From 15fe25ca67234514d7cf41af28096c1330f44950 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 8 Oct 2006 21:59:54 +0200 Subject: [PATCH 1470/1619] hwmon: Fix documentation typos Fix typos in hardware monitoring documentation. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/f71805f | 2 +- Documentation/hwmon/w83627ehf | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f index 28c5b7d1eb9..2ca69df669c 100644 --- a/Documentation/hwmon/f71805f +++ b/Documentation/hwmon/f71805f @@ -17,7 +17,7 @@ Thanks to Kris Chen from Fintek for answering technical questions and providing additional documentation. Thanks to Chris Lin from Jetway for providing wiring schematics and -anwsering technical questions. +answering technical questions. Description diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index fae3b781d82..caa610a297e 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -26,7 +26,7 @@ fan control mode). Temperatures are measured in degrees Celsius and measurement resolution is 1 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when the temperature gets higher than high limit; it stays on until the temperature -falls below the Hysteresis value. +falls below the hysteresis value. Fan rotation speeds are reported in RPM (rotations per minute). An alarm is triggered if the rotation speed has dropped below a programmable limit. Fan @@ -67,9 +67,9 @@ Thermal Cruise mode If the temperature is in the range defined by: -pwm[1-4]_target - set target temperature, unit millidegree Celcius +pwm[1-4]_target - set target temperature, unit millidegree Celsius (range 0 - 127000) -pwm[1-4]_tolerance - tolerance, unit millidegree Celcius (range 0 - 15000) +pwm[1-4]_tolerance - tolerance, unit millidegree Celsius (range 0 - 15000) there are no changes to fan speed. Once the temperature leaves the interval, fan speed increases (temp is higher) or decreases if lower than desired. -- GitLab From 6091780eba5d195213747b515a62211ac97641f1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 8 Oct 2006 22:00:44 +0200 Subject: [PATCH 1471/1619] smsc47m1: List the SMSC LPC47M112 as supported The SMSC LPC47M112 Super-I/O chip appears to be compatible with the LPC47M10x and LPC47M13x as far as hardware monitoring is concerned. The device ID is even the same, so it's really only a documentation update. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/smsc47m1 | 4 +++- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/smsc47m1.c | 11 ++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1 index c15bbe68264..04a11124f66 100644 --- a/Documentation/hwmon/smsc47m1 +++ b/Documentation/hwmon/smsc47m1 @@ -2,12 +2,14 @@ Kernel driver smsc47m1 ====================== Supported chips: - * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 + * SMSC LPC47B27x, LPC47M112, LPC47M10x, LPC47M13x, LPC47M14x, + LPC47M15x and LPC47M192 Addresses scanned: none, address read from Super I/O config space Prefix: 'smsc47m1' Datasheets: http://www.smsc.com/main/datasheets/47b27x.pdf http://www.smsc.com/main/datasheets/47m10x.pdf + http://www.smsc.com/main/datasheets/47m112.pdf http://www.smsc.com/main/tools/discontinued/47m13x.pdf http://www.smsc.com/main/datasheets/47m14x.pdf http://www.smsc.com/main/tools/discontinued/47m15x.pdf diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9b88b25b6ed..e0dede7198c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -369,8 +369,8 @@ config SENSORS_SMSC47M1 help If you say yes here you get support for the integrated fan monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and - LPC47M997 chips. + LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x, + LPC47M192 and LPC47M997 chips. The temperature and voltage sensor features of the LPC47M192 and LPC47M997 are supported by another driver, select also diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 47132fd26b1..beb881c4b2e 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -2,8 +2,8 @@ smsc47m1.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, - LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, + LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. Copyright (C) 2002 Mark D. Studebaker Copyright (C) 2004 Jean Delvare @@ -380,8 +380,8 @@ static int __init smsc47m1_find(unsigned short *addr) val = superio_inb(SUPERIO_REG_DEVID); /* - * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id - * 0x5F) and LPC47B27x (device id 0x51) have fan control. + * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x + * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" * can do much more besides (device id 0x60). * The LPC47M997 is undocumented, but seems to be compatible with @@ -390,7 +390,8 @@ static int __init smsc47m1_find(unsigned short *addr) if (val == 0x51) printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC " + "LPC47M10x/LPC47M112/LPC47M13x\n"); else if (val == 0x5F) printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); else if (val == 0x60) -- GitLab From 4660cb354a1dacbbc9c96f94eceedc38fe542fe2 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Sun, 8 Oct 2006 22:01:26 +0200 Subject: [PATCH 1472/1619] k8temp: Documentation update Update the documentation for the k8temp driver. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/k8temp | 13 ++++++++----- MAINTAINERS | 6 ++++++ drivers/hwmon/Kconfig | 6 ++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Documentation/hwmon/k8temp b/Documentation/hwmon/k8temp index bab445ab0f5..30d123b8d92 100644 --- a/Documentation/hwmon/k8temp +++ b/Documentation/hwmon/k8temp @@ -2,7 +2,7 @@ Kernel driver k8temp ==================== Supported chips: - * AMD K8 CPU + * AMD Athlon64/FX or Opteron CPUs Prefix: 'k8temp' Addresses scanned: PCI space Datasheet: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf @@ -13,10 +13,13 @@ Contact: Rudolf Marek Description ----------- -This driver permits reading temperature sensor(s) embedded inside AMD K8 CPUs. -Official documentation says that it works from revision F of K8 core, but -in fact it seems to be implemented for all revisions of K8 except the first -two revisions (SH-B0 and SH-B3). +This driver permits reading temperature sensor(s) embedded inside AMD K8 +family CPUs (Athlon64/FX, Opteron). Official documentation says that it works +from revision F of K8 core, but in fact it seems to be implemented for all +revisions of K8 except the first two revisions (SH-B0 and SH-B3). + +Please note that you will need at least lm-sensors 2.10.1 for proper userspace +support. There can be up to four temperature sensors inside single CPU. The driver will auto-detect the sensors and will display only temperatures from diff --git a/MAINTAINERS b/MAINTAINERS index 5305dd69095..595b34c4f9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1668,6 +1668,12 @@ M: sct@redhat.com, akpm@osdl.org L: ext2-devel@lists.sourceforge.net S: Maintained +K8TEMP HARDWARE MONITORING DRIVER +P: Rudolf Marek +M: r.marek@assembler.cz +L: lm-sensors@lm-sensors.org +S: Maintained + KCONFIG P: Roman Zippel M: zippel@linux-m68k.org diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e0dede7198c..e76d91906c9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -95,11 +95,13 @@ config SENSORS_ADM9240 will be called adm9240. config SENSORS_K8TEMP - tristate "AMD K8 processor sensor" + tristate "AMD Athlon64/FX or Opteron temperature 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. + sensor(s) inside your CPU. Supported is whole AMD K8 + microarchitecture. Please note that you will need at least + lm-sensors 2.10.1 for proper userspace support. This driver can also be built as a module. If so, the module will be called k8temp. -- GitLab From 14992c7eff937bb12c8ebf2d91dbaa8c2f0cfc87 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Sun, 8 Oct 2006 22:02:09 +0200 Subject: [PATCH 1473/1619] w83627ehf: Fix the detection of fan5 Fix the detection of fan5 and preserve the bit between the register writes, because the bit is write only. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 833faa275ff..2257806d010 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -354,6 +354,8 @@ static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) case 0: reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) | ((data->fan_div[0] & 0x03) << 4); + /* fan5 input control bit is write only, compute the value */ + reg |= (data->has_fan & (1 << 4)) ? 1 : 0; w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) | ((data->fan_div[0] & 0x04) << 3); @@ -362,6 +364,8 @@ static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) case 1: reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) | ((data->fan_div[1] & 0x03) << 6); + /* fan5 input control bit is write only, compute the value */ + reg |= (data->has_fan & (1 << 4)) ? 1 : 0; w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) | ((data->fan_div[1] & 0x04) << 4); @@ -1216,13 +1220,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) superio_exit(); /* It looks like fan4 and fan5 pins can be alternatively used - as fan on/off switches */ + as fan on/off switches, but fan5 control is write only :/ + We assume that if the serial interface is disabled, designers + connected fan5 as input unless they are emitting log 1, which + is not the default. */ data->has_fan = 0x07; /* fan1, fan2 and fan3 */ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); if ((i & (1 << 2)) && (!fan4pin)) data->has_fan |= (1 << 3); - if ((i & (1 << 0)) && (!fan5pin)) + if (!(i & (1 << 1)) && (!fan5pin)) data->has_fan |= (1 << 4); /* Register sysfs hooks */ -- GitLab From e693810ce8495ce3e227dacaa83f501b3b8ab204 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 13 Oct 2006 16:56:28 +0200 Subject: [PATCH 1474/1619] hwmon: Let w83781d and lm78 load again Let the w83781d and lm78 hardware monitoring drivers load even when no chip was detected at the ISA address. There can still be supported chips connected to an I2C bus or SMBus. This fixes bug #7293. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm78.c | 12 ++++++------ drivers/hwmon/w83781d.c | 12 ++++++------ drivers/i2c/busses/i2c-isa.c | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index ac1b746df6d..73bc2ffc598 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -815,18 +815,18 @@ static int __init sm_lm78_init(void) if (res) return res; - res = i2c_isa_add_driver(&lm78_isa_driver); - if (res) { - i2c_del_driver(&lm78_driver); - return res; - } + /* Don't exit if this one fails, we still want the I2C variants + to work! */ + if (i2c_isa_add_driver(&lm78_isa_driver)) + isa_address = 0; return 0; } static void __exit sm_lm78_exit(void) { - i2c_isa_del_driver(&lm78_isa_driver); + if (isa_address) + i2c_isa_del_driver(&lm78_isa_driver); i2c_del_driver(&lm78_driver); } diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index a4584ec6984..fea92061f86 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1685,11 +1685,10 @@ sensors_w83781d_init(void) if (res) return res; - res = i2c_isa_add_driver(&w83781d_isa_driver); - if (res) { - i2c_del_driver(&w83781d_driver); - return res; - } + /* Don't exit if this one fails, we still want the I2C variants + to work! */ + if (i2c_isa_add_driver(&w83781d_isa_driver)) + isa_address = 0; return 0; } @@ -1697,7 +1696,8 @@ sensors_w83781d_init(void) static void __exit sensors_w83781d_exit(void) { - i2c_isa_del_driver(&w83781d_isa_driver); + if (isa_address) + i2c_isa_del_driver(&w83781d_isa_driver); i2c_del_driver(&w83781d_driver); } diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 4380653748a..8ed59a2dff5 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -91,7 +91,7 @@ int i2c_isa_add_driver(struct i2c_driver *driver) /* Now look for clients */ res = driver->attach_adapter(&isa_adapter); if (res) { - dev_err(&isa_adapter.dev, + dev_dbg(&isa_adapter.dev, "Driver %s failed to attach adapter, unregistering\n", driver->driver.name); driver_unregister(&driver->driver); -- GitLab From bd452e6f178a559408c54c2b4ca29191b812d47f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 13 Oct 2006 17:03:42 +0200 Subject: [PATCH 1475/1619] hwmon: Fix debug messages in w83781d Fix debug messages in w83781d at detection time. We can't use dev_dbg() on an i2c client's device before calling i2c_attach_client() on that client. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83781d.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index fea92061f86..1232171c3aa 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1099,7 +1099,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) bank. */ if (kind < 0) { if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) { - dev_dbg(dev, "Detection failed at step 3\n"); + dev_dbg(&adapter->dev, "Detection of w83781d chip " + "failed at step 3\n"); err = -ENODEV; goto ERROR2; } @@ -1109,7 +1110,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if ((!(val1 & 0x07)) && (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { - dev_dbg(dev, "Detection failed at step 4\n"); + dev_dbg(&adapter->dev, "Detection of w83781d chip " + "failed at step 4\n"); err = -ENODEV; goto ERROR2; } @@ -1119,7 +1121,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) ((val1 & 0x80) && (val2 == 0x5c)))) { if (w83781d_read_value (client, W83781D_REG_I2C_ADDR) != address) { - dev_dbg(dev, "Detection failed at step 5\n"); + dev_dbg(&adapter->dev, "Detection of w83781d " + "chip failed at step 5\n"); err = -ENODEV; goto ERROR2; } @@ -1141,8 +1144,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) else if (val2 == 0x12) vendid = asus; else { - dev_dbg(dev, "Chip was made by neither " - "Winbond nor Asus?\n"); + dev_dbg(&adapter->dev, "w83781d chip vendor is " + "neither Winbond nor Asus\n"); err = -ENODEV; goto ERROR2; } @@ -1161,10 +1164,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind = as99127f; else { if (kind == 0) - dev_warn(dev, "Ignoring 'force' " + dev_warn(&adapter->dev, "Ignoring 'force' " "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); + "address 0x%02x\n", address); err = -EINVAL; goto ERROR2; } -- GitLab From 065fd1772af2032bebdce006071df007c039734d Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:38:05 -0700 Subject: [PATCH 1476/1619] [TIPC]: Add missing unlock in port timeout code. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/port.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index b9c8c6b9e94..c1a1a76759b 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -505,8 +505,13 @@ static void port_timeout(unsigned long ref) struct port *p_ptr = tipc_port_lock(ref); struct sk_buff *buf = NULL; - if (!p_ptr || !p_ptr->publ.connected) + if (!p_ptr) + return; + + if (!p_ptr->publ.connected) { + tipc_port_unlock(p_ptr); return; + } /* Last probe answered ? */ if (p_ptr->probing_state == PROBING) { -- GitLab From 29ede244cc4cfb11432a0bffd158ba09e7b2c167 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:42:04 -0700 Subject: [PATCH 1477/1619] [TIPC]: Debug print buffer enhancements and fixes This change modifies TIPC's print buffer code as follows: 1) Now supports small print buffers (min. size reduced from 512 bytes to 64) 2) Now uses TIPC_NULL print buffer structure to indicate null device instead of NULL pointer (this simplified error handling) 3) Fixed misuse of console buffer structure by tipc_dump() 4) Added and corrected comments in various places Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/core.h | 16 +++--- net/tipc/dbg.c | 136 +++++++++++++++++++++++++++++++----------------- net/tipc/dbg.h | 15 +++++- 3 files changed, 110 insertions(+), 57 deletions(-) diff --git a/net/tipc/core.h b/net/tipc/core.h index 762aac2572b..47504ec15d8 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -65,7 +65,7 @@ #define assert(i) BUG_ON(!(i)) struct tipc_msg; -extern struct print_buf *TIPC_CONS, *TIPC_LOG; +extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG; extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *); void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*); void tipc_printf(struct print_buf *, const char *fmt, ...); @@ -94,11 +94,11 @@ void tipc_dump(struct print_buf*,const char *fmt, ...); * here, or on a per .c file basis, by redefining these symbols. The following * print buffer options are available: * - * NULL : Output to null print buffer (i.e. print nowhere) - * TIPC_CONS : Output to system console - * TIPC_LOG : Output to TIPC log buffer - * &buf : Output to user-defined buffer (struct print_buf *) - * TIPC_TEE(&buf_a,&buf_b) : Output to two print buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG) ) + * TIPC_NULL : null buffer (i.e. print nowhere) + * TIPC_CONS : system console + * TIPC_LOG : TIPC log buffer + * &buf : user-defined buffer (struct print_buf *) + * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG)) */ #ifndef TIPC_OUTPUT @@ -106,7 +106,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...); #endif #ifndef DBG_OUTPUT -#define DBG_OUTPUT NULL +#define DBG_OUTPUT TIPC_NULL #endif #else @@ -136,7 +136,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...); #define TIPC_OUTPUT TIPC_CONS #undef DBG_OUTPUT -#define DBG_OUTPUT NULL +#define DBG_OUTPUT TIPC_NULL #endif diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c index 55130655e1e..d8af4c28695 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/dbg.c @@ -1,8 +1,8 @@ /* - * net/tipc/dbg.c: TIPC print buffer routines for debuggign + * net/tipc/dbg.c: TIPC print buffer routines for debugging * * Copyright (c) 1996-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,11 +38,12 @@ #include "config.h" #include "dbg.h" -#define MAX_STRING 512 - -static char print_string[MAX_STRING]; +static char print_string[TIPC_PB_MAX_STR]; static DEFINE_SPINLOCK(print_lock); +static struct print_buf null_buf = { NULL, 0, NULL, NULL }; +struct print_buf *TIPC_NULL = &null_buf; + static struct print_buf cons_buf = { NULL, 0, NULL, NULL }; struct print_buf *TIPC_CONS = &cons_buf; @@ -62,68 +63,83 @@ struct print_buf *TIPC_LOG = &log_buf; /* * Locking policy when using print buffers. * - * 1) Routines of the form printbuf_XXX() rely on the caller to prevent - * simultaneous use of the print buffer(s) being manipulated. - * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of - * 'print_string' and to protect its print buffer(s). - * 3) TIPC_TEE() uses 'print_lock' to protect its print buffer(s). - * 4) Routines of the form log_XXX() uses 'print_lock' to protect TIPC_LOG. + * The following routines use 'print_lock' for protection: + * 1) tipc_printf() - to protect its print buffer(s) and 'print_string' + * 2) TIPC_TEE() - to protect its print buffer(s) + * 3) tipc_dump() - to protect its print buffer(s) and 'print_string' + * 4) tipc_log_XXX() - to protect TIPC_LOG + * + * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent + * simultaneous use of the print buffer(s) being manipulated. */ /** * tipc_printbuf_init - initialize print buffer to empty + * @pb: pointer to print buffer structure + * @raw: pointer to character array used by print buffer + * @size: size of character array + * + * Makes the print buffer a null device that discards anything written to it + * if the character array is too small (or absent). */ -void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz) +void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) { - if (!pb || !raw || (sz < (MAX_STRING + 1))) - return; - - pb->crs = pb->buf = raw; - pb->size = sz; + pb->buf = raw; + pb->crs = raw; + pb->size = size; pb->next = NULL; - pb->buf[0] = 0; - pb->buf[sz-1] = ~0; + + if (size < TIPC_PB_MIN_SIZE) { + pb->buf = NULL; + } else if (raw) { + pb->buf[0] = 0; + pb->buf[size-1] = ~0; + } } /** * tipc_printbuf_reset - reinitialize print buffer to empty state + * @pb: pointer to print buffer structure */ void tipc_printbuf_reset(struct print_buf *pb) { - if (pb && pb->buf) - tipc_printbuf_init(pb, pb->buf, pb->size); + tipc_printbuf_init(pb, pb->buf, pb->size); } /** * tipc_printbuf_empty - test if print buffer is in empty state + * @pb: pointer to print buffer structure + * + * Returns non-zero if print buffer is empty. */ int tipc_printbuf_empty(struct print_buf *pb) { - return (!pb || !pb->buf || (pb->crs == pb->buf)); + return (!pb->buf || (pb->crs == pb->buf)); } /** * tipc_printbuf_validate - check for print buffer overflow + * @pb: pointer to print buffer structure * * Verifies that a print buffer has captured all data written to it. * If data has been lost, linearize buffer and prepend an error message * - * Returns length of print buffer data string (including trailing NULL) + * Returns length of print buffer data string (including trailing NUL) */ int tipc_printbuf_validate(struct print_buf *pb) { - char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n"; + char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n"; char *cp_buf; struct print_buf cb; - if (!pb || !pb->buf) + if (!pb->buf) return 0; - if (pb->buf[pb->size - 1] == '\0') { + if (pb->buf[pb->size - 1] == 0) { cp_buf = kmalloc(pb->size, GFP_ATOMIC); if (cp_buf != NULL){ tipc_printbuf_init(&cb, cp_buf, pb->size); @@ -141,6 +157,8 @@ int tipc_printbuf_validate(struct print_buf *pb) /** * tipc_printbuf_move - move print buffer contents to another print buffer + * @pb_to: pointer to destination print buffer structure + * @pb_from: pointer to source print buffer structure * * Current contents of destination print buffer (if any) are discarded. * Source print buffer becomes empty if a successful move occurs. @@ -152,21 +170,22 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) /* Handle the cases where contents can't be moved */ - if (!pb_to || !pb_to->buf) + if (!pb_to->buf) return; - if (!pb_from || !pb_from->buf) { + if (!pb_from->buf) { tipc_printbuf_reset(pb_to); return; } if (pb_to->size < pb_from->size) { tipc_printbuf_reset(pb_to); - tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***"); + tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***"); return; } /* Copy data from char after cursor to end (if used) */ + len = pb_from->buf + pb_from->size - pb_from->crs - 2; if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) { strcpy(pb_to->buf, pb_from->crs + 1); @@ -175,6 +194,7 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) pb_to->crs = pb_to->buf; /* Copy data from start to cursor (always) */ + len = pb_from->crs - pb_from->buf; strcpy(pb_to->crs, pb_from->buf); pb_to->crs += len; @@ -184,6 +204,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) /** * tipc_printf - append formatted output to print buffer chain + * @pb: pointer to chain of print buffers (may be NULL) + * @fmt: formatted info to be printed */ void tipc_printf(struct print_buf *pb, const char *fmt, ...) @@ -195,8 +217,8 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) spin_lock_bh(&print_lock); FORMAT(print_string, chars_to_add, fmt); - if (chars_to_add >= MAX_STRING) - strcpy(print_string, "*** STRING TOO LONG ***"); + if (chars_to_add >= TIPC_PB_MAX_STR) + strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***"); while (pb) { if (pb == TIPC_CONS) @@ -206,6 +228,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) if (chars_to_add <= chars_left) { strcpy(pb->crs, print_string); pb->crs += chars_to_add; + } else if (chars_to_add >= (pb->size - 1)) { + strcpy(pb->buf, print_string + chars_to_add + 1 + - pb->size); + pb->crs = pb->buf + pb->size - 1; } else { strcpy(pb->buf, print_string + chars_left); save_char = print_string[chars_left]; @@ -224,6 +250,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) /** * TIPC_TEE - perform next output operation on both print buffers + * @b0: pointer to chain of print buffers (may be NULL) + * @b1: pointer to print buffer to add to chain + * + * Returns pointer to print buffer chain. */ struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1) @@ -232,8 +262,6 @@ struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1) if (!b0 || (b0 == b1)) return b1; - if (!b1) - return b0; spin_lock_bh(&print_lock); while (pb->next) { @@ -256,7 +284,7 @@ static void print_to_console(char *crs, int len) int rest = len; while (rest > 0) { - int sz = rest < MAX_STRING ? rest : MAX_STRING; + int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR; char c = crs[sz]; crs[sz] = 0; @@ -275,36 +303,48 @@ static void printbuf_dump(struct print_buf *pb) { int len; + if (!pb->buf) { + printk("*** PRINT BUFFER NOT ALLOCATED ***"); + return; + } + /* Dump print buffer from char after cursor to end (if used) */ + len = pb->buf + pb->size - pb->crs - 2; if ((pb->buf[pb->size - 1] == 0) && (len > 0)) print_to_console(pb->crs + 1, len); /* Dump print buffer from start to cursor (always) */ + len = pb->crs - pb->buf; print_to_console(pb->buf, len); } /** * tipc_dump - dump non-console print buffer(s) to console + * @pb: pointer to chain of print buffers */ void tipc_dump(struct print_buf *pb, const char *fmt, ...) { + struct print_buf *pb_next; int len; spin_lock_bh(&print_lock); - FORMAT(TIPC_CONS->buf, len, fmt); - printk(TIPC_CONS->buf); + FORMAT(print_string, len, fmt); + printk(print_string); for (; pb; pb = pb->next) { - if (pb == TIPC_CONS) - continue; - printk("\n---- Start of dump,%s log ----\n\n", - (pb == TIPC_LOG) ? "global" : "local"); - printbuf_dump(pb); - tipc_printbuf_reset(pb); - printk("\n-------- End of dump --------\n"); + if (pb != TIPC_CONS) { + printk("\n---- Start of %s log dump ----\n\n", + (pb == TIPC_LOG) ? "global" : "local"); + printbuf_dump(pb); + tipc_printbuf_reset(pb); + printk("\n---- End of dump ----\n"); + } + pb_next = pb->next; + pb->next = NULL; + pb = pb_next; } spin_unlock_bh(&print_lock); } @@ -324,7 +364,8 @@ void tipc_log_stop(void) } /** - * tipc_log_reinit - set TIPC log print buffer to specified size + * tipc_log_reinit - (re)initialize TIPC log print buffer + * @log_size: print buffer size to use */ void tipc_log_reinit(int log_size) @@ -332,10 +373,11 @@ void tipc_log_reinit(int log_size) tipc_log_stop(); if (log_size) { - if (log_size <= MAX_STRING) - log_size = MAX_STRING + 1; + if (log_size < TIPC_PB_MIN_SIZE) + log_size = TIPC_PB_MIN_SIZE; spin_lock_bh(&print_lock); - tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size); + tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), + log_size); spin_unlock_bh(&print_lock); } } diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h index 227f050d2a5..467c0bc78a7 100644 --- a/net/tipc/dbg.h +++ b/net/tipc/dbg.h @@ -2,7 +2,7 @@ * net/tipc/dbg.h: Include file for TIPC print buffer routines * * Copyright (c) 1997-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,14 @@ #ifndef _TIPC_DBG_H #define _TIPC_DBG_H +/** + * struct print_buf - TIPC print buffer structure + * @buf: pointer to character array containing print buffer contents + * @size: size of character array + * @crs: pointer to first unused space in character array (i.e. final NUL) + * @next: used to link print buffers when printing to more than one at a time + */ + struct print_buf { char *buf; u32 size; @@ -44,7 +52,10 @@ struct print_buf { struct print_buf *next; }; -void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 sz); +#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */ +#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */ + +void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size); void tipc_printbuf_reset(struct print_buf *pb); int tipc_printbuf_empty(struct print_buf *pb); int tipc_printbuf_validate(struct print_buf *pb); -- GitLab From eb5959c2bd290bf6c24ddf6d1f5ebcb496c54adb Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:43:54 -0700 Subject: [PATCH 1478/1619] [TIPC]: Stream socket can now send > 66000 bytes at a time The stream socket send code was not initializing some required fields of the temporary msghdr structure it was utilizing; this is now fixed. A check has also been added to detect if a user illegally specifies a destination address when sending on an established stream connection. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/socket.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index acfb852e7c9..ed900fe96bd 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2,7 +2,7 @@ * net/tipc/socket.c: TIPC socket API * * Copyright (c) 2001-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -629,6 +629,9 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, return -ENOTCONN; } + if (unlikely(m->msg_name)) + return -EISCONN; + /* * Send each iovec entry using one or more messages * @@ -641,6 +644,8 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, curr_iovlen = m->msg_iovlen; my_msg.msg_iov = &my_iov; my_msg.msg_iovlen = 1; + my_msg.msg_flags = m->msg_flags; + my_msg.msg_name = NULL; bytes_sent = 0; while (curr_iovlen--) { -- GitLab From e91ed0bcdfc4812c0342d64281ee985213df07c3 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:44:59 -0700 Subject: [PATCH 1479/1619] [TIPC]: Added duplicate node address detection capability TIPC now rejects and logs link setup requests from node if the receiving node already has a functional link to that node on the associated interface, or if the requestor is using the same as the receiver. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/bearer.c | 8 ++++---- net/tipc/discover.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 75a5968c213..39744a33bd3 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -2,7 +2,7 @@ * net/tipc/bearer.c: TIPC bearer code * * Copyright (c) 1996-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -191,14 +191,14 @@ void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a) if ((i < media_count) && (m_ptr->addr2str != NULL)) { char addr_str[MAX_ADDR_STR]; - tipc_printf(pb, "%s(%s) ", m_ptr->name, + tipc_printf(pb, "%s(%s)", m_ptr->name, m_ptr->addr2str(a, addr_str, sizeof(addr_str))); } else { unchar *addr = (unchar *)&a->dev_addr; - tipc_printf(pb, "UNKNOWN(%u):", media_type); + tipc_printf(pb, "UNKNOWN(%u)", media_type); for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) { - tipc_printf(pb, "%02x ", addr[i]); + tipc_printf(pb, "-%02x", addr[i]); } } } diff --git a/net/tipc/discover.c b/net/tipc/discover.c index ee94de92ae9..cc748d4d474 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -131,6 +131,28 @@ static struct sk_buff *tipc_disc_init_msg(u32 type, return buf; } +/** + * disc_dupl_alert - issue node address duplication alert + * @b_ptr: pointer to bearer detecting duplication + * @node_addr: duplicated node address + * @media_addr: media address advertised by duplicated node + */ + +static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr, + struct tipc_media_addr *media_addr) +{ + char node_addr_str[16]; + char media_addr_str[64]; + struct print_buf pb; + + addr_string_fill(node_addr_str, node_addr); + tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str)); + tipc_media_addr_printf(&pb, media_addr); + tipc_printbuf_validate(&pb); + warn("Duplicate %s using %s seen on <%s>\n", + node_addr_str, media_addr_str, b_ptr->publ.name); +} + /** * tipc_disc_recv_msg - handle incoming link setup message (request or response) * @buf: buffer containing message @@ -157,8 +179,11 @@ void tipc_disc_recv_msg(struct sk_buff *buf) return; if (!tipc_addr_node_valid(orig)) return; - if (orig == tipc_own_addr) + if (orig == tipc_own_addr) { + if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr))) + disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; + } if (!in_scope(dest, tipc_own_addr)) return; if (is_slave(tipc_own_addr) && is_slave(orig)) @@ -190,6 +215,11 @@ void tipc_disc_recv_msg(struct sk_buff *buf) } addr = &link->media_addr; if (memcmp(addr, &media_addr, sizeof(*addr))) { + if (tipc_link_is_up(link) || (!link->started)) { + disc_dupl_alert(b_ptr, orig, &media_addr); + spin_unlock_bh(&n_ptr->lock); + return; + } warn("Resetting link <%s>, peer interface address changed\n", link->name); memcpy(addr, &media_addr, sizeof(*addr)); -- GitLab From cfb0c0890b200364c0886c0d9f0dc615f8114c43 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:47:18 -0700 Subject: [PATCH 1480/1619] [TIPC]: Optimize wakeup logic when socket has no waiting processes This patch adds a simple test so TIPC doesn't try waking up processes waiting on a socket if there are none waiting. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/socket.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ed900fe96bd..2a6a5a6b4c1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1208,7 +1208,8 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) atomic_inc(&tipc_queue_size); skb_queue_tail(&sock->sk->sk_receive_queue, buf); - wake_up_interruptible(sock->sk->sk_sleep); + if (waitqueue_active(sock->sk->sk_sleep)) + wake_up_interruptible(sock->sk->sk_sleep); return TIPC_OK; } @@ -1223,7 +1224,8 @@ static void wakeupdispatch(struct tipc_port *tport) { struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle; - wake_up_interruptible(tsock->sk.sk_sleep); + if (waitqueue_active(tsock->sk.sk_sleep)) + wake_up_interruptible(tsock->sk.sk_sleep); } /** -- GitLab From a3df92c73b92970dc4211189b87eb4cf874f5685 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:49:03 -0700 Subject: [PATCH 1481/1619] [TIPC]: Remove code bloat introduced by print buffer rework This patch allows the compiler to optimize out any code that tries to send debugging output to the null print buffer (TIPC_NULL), a capability that was unintentionally broken during the recent print buffer rework. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/core.h | 6 +++--- net/tipc/link.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/net/tipc/core.h b/net/tipc/core.h index 47504ec15d8..d1c3948eb4e 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -83,9 +83,9 @@ void tipc_dump(struct print_buf*,const char *fmt, ...); #define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg) #define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg) -#define dbg(fmt, arg...) do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0) -#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0) -#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0) +#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0) +#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0) +#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0) /* diff --git a/net/tipc/link.c b/net/tipc/link.c index 53bc8cb5adb..1bb983c8130 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -132,7 +132,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, * allow the output from multiple links to be intermixed. For this reason * routines of the form "dbg_link_XXX()" have been created that will capture * debug info into a link's personal print buffer, which can then be dumped - * into the TIPC system log (LOG) upon request. + * into the TIPC system log (TIPC_LOG) upon request. * * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size * of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0, @@ -141,7 +141,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, * when there is only a single link in the system being debugged. * * Notes: - * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes) + * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE * - "l_ptr" must be valid when using dbg_link_XXX() macros */ @@ -159,13 +159,13 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, static void dbg_print_link(struct link *l_ptr, const char *str) { - if (DBG_OUTPUT) + if (DBG_OUTPUT != TIPC_NULL) link_print(l_ptr, DBG_OUTPUT, str); } static void dbg_print_buf_chain(struct sk_buff *root_buf) { - if (DBG_OUTPUT) { + if (DBG_OUTPUT != TIPC_NULL) { struct sk_buff *buf = root_buf; while (buf) { -- GitLab From 3a8d12142eab420ffcbbf3d1d2e637158e85aab8 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:50:20 -0700 Subject: [PATCH 1482/1619] [TIPC]: Add support for Ethernet VLANs This patch enhances TIPC's Ethernet support to include VLAN interfaces. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/core.c | 2 +- net/tipc/core.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/net/tipc/core.c b/net/tipc/core.c index 0539a836285..7f3f693e512 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -90,7 +90,7 @@ int tipc_random; atomic_t tipc_user_count = ATOMIC_INIT(0); const char tipc_alphabet[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."; /* configurable TIPC parameters */ diff --git a/net/tipc/core.h b/net/tipc/core.h index d1c3948eb4e..4638947c232 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -275,11 +275,15 @@ static inline void k_term_timer(struct timer_list *timer) /* * TIPC message buffer code * - * TIPC message buffer headroom leaves room for 14 byte Ethernet header, + * TIPC message buffer headroom reserves space for a link-level header + * (in case the message is sent off-node), * while ensuring TIPC header is word aligned for quicker access + * + * The largest header currently supported is 18 bytes, which is used when + * the standard 14 byte Ethernet header has 4 added bytes for VLAN info */ -#define BUF_HEADROOM 16u +#define BUF_HEADROOM 20u struct tipc_skb_cb { void *handle; -- GitLab From 08c31f7167b1bdc30cd0960b45d6f3076eb1f179 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:56:04 -0700 Subject: [PATCH 1483/1619] [TIPC]: Name publication events now delivered in chronological order This patch tivially re-orders the entries in TIPC's list of local publications so that applications will receive publication events in the order they were published. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/name_distr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index f0b063bcc2a..03bd659c43c 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -122,7 +122,7 @@ void tipc_named_publish(struct publication *publ) struct sk_buff *buf; struct distr_item *item; - list_add(&publ->local_list, &publ_root); + list_add_tail(&publ->local_list, &publ_root); publ_cnt++; buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0); -- GitLab From 2de07f6156fe664063207c010b3bd2500348884a Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:57:13 -0700 Subject: [PATCH 1484/1619] [TIPC]: Fixed slow link reactivation when link tolerance is large This patch corrects an issue wherein a previouly failed node could not reestablish a links to a non-failing node in the TIPC network until the latter node detected the link failure itself (which might be configured to take up to 30 seconds). The non-failing node now responds to link setup requests from a previously failed node in at most 1 second, allowing it to detect the link failure more quickly. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/discover.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/tipc/discover.c b/net/tipc/discover.c index cc748d4d474..3b0cd12f37d 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -195,7 +195,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf) struct sk_buff *rbuf; struct tipc_media_addr *addr; struct node *n_ptr = tipc_node_find(orig); - int link_up; + int link_fully_up; + dbg(" in own cluster\n"); if (n_ptr == NULL) { n_ptr = tipc_node_create(orig); @@ -225,9 +226,9 @@ void tipc_disc_recv_msg(struct sk_buff *buf) memcpy(addr, &media_addr, sizeof(*addr)); tipc_link_reset(link); } - link_up = tipc_link_is_up(link); + link_fully_up = (link->state == WORKING_WORKING); spin_unlock_bh(&n_ptr->lock); - if ((type == DSC_RESP_MSG) || link_up) + if ((type == DSC_RESP_MSG) || link_fully_up) return; rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); if (rbuf != NULL) { -- GitLab From fc144deec6403c17e6d3f6a6574f701420f166ed Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 21:57:56 -0700 Subject: [PATCH 1485/1619] [TIPC]: Can now list multicast link on an isolated network node This patch fixes a minor bug that prevents "tipc-config -l" from displaying the multicast link if a TIPC node has never successfully established at least one unicast link. Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index fc6d09630cc..886bda5e88d 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -648,7 +648,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); - if (!tipc_nodes) + if (tipc_mode != TIPC_NET_MODE) return tipc_cfg_reply_none(); /* Get space for all unicast links + multicast link */ -- GitLab From eb409460b1abec0e2a1f9c9d07019f4157a6d6bc Mon Sep 17 00:00:00 2001 From: Lijun Chen Date: Mon, 16 Oct 2006 21:59:42 -0700 Subject: [PATCH 1486/1619] [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(-) diff --git a/include/linux/tipc.h b/include/linux/tipc.h index 243a15f5400..bea469455a0 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 c51600ba5f4..7a918f12a5d 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); -- GitLab From 53cfd1e102c759c958f907ee40a58bec3fc5911a Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 22:00:56 -0700 Subject: [PATCH 1487/1619] [TIPC]: Unrecognized configuration command now returns error message This patch causes TIPC to return an error message when it receives an unrecognized configuration command. (Previously, the sender received no feedback.) Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/config.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/tipc/config.c b/net/tipc/config.c index 285e1bc2d88..ed1351ed05e 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -2,7 +2,7 @@ * net/tipc/config.c: TIPC configuration management code * * Copyright (c) 2002-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -613,7 +613,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); break; default: - rep_tlv_buf = NULL; + rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED + " (unknown command)"); break; } -- GitLab From 665d8669583e28c397d4333385d8f46ca5864048 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 16 Oct 2006 22:01:32 -0700 Subject: [PATCH 1488/1619] [TIPC]: Updated TIPC version number to 1.6.2 Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- net/tipc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/core.c b/net/tipc/core.c index 7f3f693e512..6f5b7ee3118 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -57,7 +57,7 @@ void tipc_socket_stop(void); int tipc_netlink_start(void); void tipc_netlink_stop(void); -#define TIPC_MOD_VER "1.6.1" +#define TIPC_MOD_VER "1.6.2" #ifndef CONFIG_TIPC_ZONES #define CONFIG_TIPC_ZONES 3 -- GitLab From e320af1df4c47305e829e8e1a40e5fad0e5e9fba Mon Sep 17 00:00:00 2001 From: Ville Nuorvala Date: Mon, 16 Oct 2006 22:05:55 -0700 Subject: [PATCH 1489/1619] [IPV6]: Remove struct pol_chain. Struct pol_chain has existed since at least the 2.2 kernel, but isn't used anymore. As the IPv6 policy routing is implemented in a totally different way in the current kernel, just get rid of it. Signed-off-by: Ville Nuorvala Signed-off-by: David S. Miller --- include/net/ip6_route.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 6ca6b71dfe0..c14b70ed4c5 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -36,13 +36,6 @@ struct route_info { #define RT6_LOOKUP_F_REACHABLE 0x2 #define RT6_LOOKUP_F_HAS_SADDR 0x4 -struct pol_chain { - int type; - int priority; - struct fib6_node *rules; - struct pol_chain *next; -}; - extern struct rt6_info ip6_null_entry; #ifdef CONFIG_IPV6_MULTIPLE_TABLES -- GitLab From 23c435f7ff884caded4a1391ba2b308d465423c0 Mon Sep 17 00:00:00 2001 From: Ville Nuorvala Date: Mon, 16 Oct 2006 22:08:28 -0700 Subject: [PATCH 1490/1619] [SCTP]: Fix minor typo Signed-off-by: Ville Nuorvala Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9deec439118..9f34dec6ff8 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -821,7 +821,7 @@ out: * addrs is a pointer to an array of one or more socket addresses. Each * address is contained in its appropriate structure (i.e. struct * sockaddr_in or struct sockaddr_in6) the family of the address type - * must be used to distengish the address length (note that this + * must be used to distinguish the address length (note that this * representation is termed a "packed array" of addresses). The caller * specifies the number of addresses in the array with addrcnt. * -- GitLab From 4251320fa2ef93207fbefeb2eda2d265b84fc116 Mon Sep 17 00:00:00 2001 From: Ville Nuorvala Date: Mon, 16 Oct 2006 22:10:05 -0700 Subject: [PATCH 1491/1619] [IPV6]: Make sure error handling is done when calling ip6_route_output(). As ip6_route_output() never returns NULL, error checking must be done by looking at dst->error in stead of comparing dst against NULL. Signed-off-by: Ville Nuorvala Signed-off-by: David S. Miller --- net/ipv6/xfrm6_policy.c | 12 +++++++----- net/sctp/ipv6.c | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 73cee2ec07e..d400f8fae12 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -25,12 +25,14 @@ static struct dst_ops xfrm6_dst_ops; static struct xfrm_policy_afinfo xfrm6_policy_afinfo; -static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) +static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl) { - int err = 0; - *dst = (struct xfrm_dst*)ip6_route_output(NULL, fl); - if (!*dst) - err = -ENETUNREACH; + struct dst_entry *dst = ip6_route_output(NULL, fl); + int err = dst->error; + if (!err) + *xdst = (struct xfrm_dst *) dst; + else + dst_release(dst); return err; } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 249e5033c1a..78071c6e6cf 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -215,17 +215,17 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, } dst = ip6_route_output(NULL, &fl); - if (dst) { + if (!dst->error) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK( "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n", NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr)); - } else { - SCTP_DEBUG_PRINTK("NO ROUTE\n"); + return dst; } - - return dst; + SCTP_DEBUG_PRINTK("NO ROUTE\n"); + dst_release(dst); + return NULL; } /* Returns the number of consecutive initial bits that match in the 2 ipv6 -- GitLab From e0eda7bbaae48ea56f1f1943ea90df72d459b9b0 Mon Sep 17 00:00:00 2001 From: Ville Nuorvala Date: Mon, 16 Oct 2006 22:11:11 -0700 Subject: [PATCH 1492/1619] [IPV6]: Clean up BACKTRACK(). The fn check is unnecessary as fn can never be NULL in BACKTRACK(). Signed-off-by: Ville Nuorvala Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a1b0f075462..263c057d17c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -484,7 +484,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, do { \ if (rt == &ip6_null_entry) { \ struct fib6_node *pn; \ - while (fn) { \ + while (1) { \ if (fn->fn_flags & RTN_TL_ROOT) \ goto out; \ pn = fn->parent; \ -- GitLab From 264e91b68aff1e39b558123498f28bf5aa68b4ee Mon Sep 17 00:00:00 2001 From: Ville Nuorvala Date: Mon, 16 Oct 2006 22:12:21 -0700 Subject: [PATCH 1493/1619] [IPV6]: Make IPV6_SUBTREES depend on IPV6_MULTIPLE_TABLES. As IPV6_SUBTREES can't work without IPV6_MULTIPLE_TABLES have IPV6_SUBTREES depend on it. Signed-off-by: Ville Nuorvala Signed-off-by: David S. Miller --- net/ipv6/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ef5eaad4485..6e48f52e197 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -175,9 +175,16 @@ config IPV6_TUNNEL If unsure, say N. +config IPV6_MULTIPLE_TABLES + bool "IPv6: Multiple Routing Tables" + depends on IPV6 && EXPERIMENTAL + select FIB_RULES + ---help--- + Support multiple routing tables. + config IPV6_SUBTREES bool "IPv6: source address based routing" - depends on IPV6 && EXPERIMENTAL + depends on IPV6_MULTIPLE_TABLES ---help--- Enable routing by source address or prefix. @@ -189,13 +196,6 @@ config IPV6_SUBTREES If unsure, say N. -config IPV6_MULTIPLE_TABLES - bool "IPv6: Multiple Routing Tables" - depends on IPV6 && EXPERIMENTAL - select FIB_RULES - ---help--- - Support multiple routing tables. - config IPV6_ROUTE_FWMARK bool "IPv6: use netfilter MARK value as routing key" depends on IPV6_MULTIPLE_TABLES && NETFILTER -- GitLab From 22e1e4d8dcb71762fcbe0c73d720aea8bb2013af Mon Sep 17 00:00:00 2001 From: Ville Nuorvala Date: Mon, 16 Oct 2006 22:14:26 -0700 Subject: [PATCH 1494/1619] [IPV6]: Always copy rt->u.dst.error when copying a rt6_info. Signed-off-by: Ville Nuorvala Signed-off-by: David S. Miller --- net/ipv6/route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 263c057d17c..aa96be860e9 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -618,8 +618,6 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); rt->rt6i_dst.plen = 128; rt->rt6i_flags |= RTF_CACHE; - if (rt->rt6i_flags & RTF_REJECT) - rt->u.dst.error = ort->u.dst.error; rt->u.dst.flags |= DST_HOST; rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); } @@ -1540,6 +1538,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) rt->u.dst.output = ort->u.dst.output; memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); + rt->u.dst.error = ort->u.dst.error; rt->u.dst.dev = ort->u.dst.dev; if (rt->u.dst.dev) dev_hold(rt->u.dst.dev); -- GitLab From b52f070c9c3c09ed3b7f699280193aae7e25d816 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 18 Oct 2006 20:26:36 -0700 Subject: [PATCH 1495/1619] [IPv4] fib: Remove unused fib_config members Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/ip_fib.h | 5 +---- net/ipv4/fib_frontend.c | 5 ----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 82229146bac..949b932d2f0 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -21,17 +21,14 @@ #include struct fib_config { - u8 fc_family; u8 fc_dst_len; - u8 fc_src_len; u8 fc_tos; u8 fc_protocol; u8 fc_scope; u8 fc_type; - /* 1 byte unused */ + /* 3 bytes unused */ u32 fc_table; __be32 fc_dst; - __be32 fc_src; __be32 fc_gw; int fc_oif; u32 fc_flags; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 9c399a70dd5..af0190d8b6c 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -482,9 +482,7 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, memset(cfg, 0, sizeof(*cfg)); rtm = nlmsg_data(nlh); - cfg->fc_family = rtm->rtm_family; cfg->fc_dst_len = rtm->rtm_dst_len; - cfg->fc_src_len = rtm->rtm_src_len; cfg->fc_tos = rtm->rtm_tos; cfg->fc_table = rtm->rtm_table; cfg->fc_protocol = rtm->rtm_protocol; @@ -501,9 +499,6 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, case RTA_DST: cfg->fc_dst = nla_get_be32(attr); break; - case RTA_SRC: - cfg->fc_src = nla_get_be32(attr); - break; case RTA_OIF: cfg->fc_oif = nla_get_u32(attr); break; -- GitLab From ae8064ac32d07f609114d73928cdef803be87134 Mon Sep 17 00:00:00 2001 From: John Heffner Date: Wed, 18 Oct 2006 20:36:48 -0700 Subject: [PATCH 1496/1619] [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(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0e058a2d1c6..2d36f6db370 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 f22536e32cb..ca406157724 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. -- GitLab From 3a31b9d2f2d98667832e87fa1853754ff062d6ef Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Oct 2006 20:45:22 -0700 Subject: [PATCH 1497/1619] [DECNET]: Fix input routing bug This patch fixes a silly bug that has been in the input routing code for some time. It results in trying to send to a node directly when the origin of the packet is via the default router. Its been tested by Alan Kemmerer who reported the bug and its a fairly obvious fix for a typo. Signed-off-by: Steven Whitehouse Signed-off-by: Patrick Caulfield Signed-off-by: David S. Miller --- net/decnet/dn_route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 491429ce939..23489f7232d 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1275,7 +1275,6 @@ static int dn_route_input_slow(struct sk_buff *skb) goto e_inval; res.type = RTN_LOCAL; - flags |= RTCF_DIRECTSRC; } else { __le16 src_map = fl.fld_src; free_res = 1; @@ -1346,7 +1345,7 @@ static int dn_route_input_slow(struct sk_buff *skb) goto make_route; /* Packet was intra-ethernet, so we know its on-link */ - if (cb->rt_flags | DN_RT_F_IE) { + if (cb->rt_flags & DN_RT_F_IE) { gateway = cb->src; flags |= RTCF_DIRECTSRC; goto make_route; -- GitLab From 9ce8ade015a3f82dbdf856df7a685878dd1cc0e1 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 18 Oct 2006 20:46:54 -0700 Subject: [PATCH 1498/1619] [IPv6] route: Fix prohibit and blackhole routing decision Lookups resolving to ip6_blk_hole_entry must result in silently discarding the packets whereas an ip6_pkt_prohibit_entry is supposed to cause an ICMPV6_ADM_PROHIBITED message to be sent. Thanks to Kim Nordlund for noticing this bug. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv6/route.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aa96be860e9..5c00ca4fa52 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -94,6 +94,9 @@ static int ip6_dst_gc(void); static int ip6_pkt_discard(struct sk_buff *skb); static int ip6_pkt_discard_out(struct sk_buff *skb); +static int ip6_pkt_prohibit(struct sk_buff *skb); +static int ip6_pkt_prohibit_out(struct sk_buff *skb); +static int ip6_pkt_blk_hole(struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); @@ -150,8 +153,8 @@ struct rt6_info ip6_prohibit_entry = { .obsolete = -1, .error = -EACCES, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, - .input = ip6_pkt_discard, - .output = ip6_pkt_discard_out, + .input = ip6_pkt_prohibit, + .output = ip6_pkt_prohibit_out, .ops = &ip6_dst_ops, .path = (struct dst_entry*)&ip6_prohibit_entry, } @@ -170,8 +173,8 @@ struct rt6_info ip6_blk_hole_entry = { .obsolete = -1, .error = -EINVAL, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, - .input = ip6_pkt_discard, - .output = ip6_pkt_discard_out, + .input = ip6_pkt_blk_hole, + .output = ip6_pkt_blk_hole, .ops = &ip6_dst_ops, .path = (struct dst_entry*)&ip6_blk_hole_entry, } @@ -1742,24 +1745,46 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) * Drop the packet on the floor */ -static int ip6_pkt_discard(struct sk_buff *skb) +static inline int ip6_pkt_drop(struct sk_buff *skb, int code) { int type = ipv6_addr_type(&skb->nh.ipv6h->daddr); if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS); IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev); + icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); kfree_skb(skb); return 0; } +static int ip6_pkt_discard(struct sk_buff *skb) +{ + return ip6_pkt_drop(skb, ICMPV6_NOROUTE); +} + static int ip6_pkt_discard_out(struct sk_buff *skb) { skb->dev = skb->dst->dev; return ip6_pkt_discard(skb); } +static int ip6_pkt_prohibit(struct sk_buff *skb) +{ + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED); +} + +static int ip6_pkt_prohibit_out(struct sk_buff *skb) +{ + skb->dev = skb->dst->dev; + return ip6_pkt_prohibit(skb); +} + +static int ip6_pkt_blk_hole(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + /* * Allocate a dst for local (unicast / anycast) address. */ -- GitLab From 5175c3786c244f8b689854db24c9e79b1c6a084f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Oct 2006 20:51:57 -0700 Subject: [PATCH 1499/1619] [NET]: reduce per cpu ram used for loopback stats We dont need a full struct net_device_stats (currently 23 long : 184 bytes on x86_64) per possible CPU, but only two counters : bytes and packets We save few CPU cycles too in loopback_xmit() not updating 4 fields, but 2. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/loopback.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 4178b4b1d2d..93fbea1c927 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -58,7 +58,11 @@ #include #include -static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); +struct pcpu_lstats { + unsigned long packets; + unsigned long bytes; +}; +static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats); #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) @@ -128,7 +132,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *lb_stats; + struct pcpu_lstats *lb_stats; skb_orphan(skb); @@ -149,11 +153,9 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; - lb_stats = &per_cpu(loopback_stats, get_cpu()); - lb_stats->rx_bytes += skb->len; - lb_stats->tx_bytes = lb_stats->rx_bytes; - lb_stats->rx_packets++; - lb_stats->tx_packets = lb_stats->rx_packets; + lb_stats = &per_cpu(pcpu_lstats, get_cpu()); + lb_stats->bytes += skb->len; + lb_stats->packets++; put_cpu(); netif_rx(skb); @@ -166,20 +168,21 @@ static struct net_device_stats loopback_stats; static struct net_device_stats *get_stats(struct net_device *dev) { struct net_device_stats *stats = &loopback_stats; + unsigned long bytes = 0; + unsigned long packets = 0; int i; - memset(stats, 0, sizeof(struct net_device_stats)); - for_each_possible_cpu(i) { - struct net_device_stats *lb_stats; + const struct pcpu_lstats *lb_stats; - lb_stats = &per_cpu(loopback_stats, i); - stats->rx_bytes += lb_stats->rx_bytes; - stats->tx_bytes += lb_stats->tx_bytes; - stats->rx_packets += lb_stats->rx_packets; - stats->tx_packets += lb_stats->tx_packets; + lb_stats = &per_cpu(pcpu_lstats, i); + bytes += lb_stats->bytes; + packets += lb_stats->packets; } - + stats->rx_packets = packets; + stats->tx_packets = packets; + stats->rx_bytes = bytes; + stats->tx_bytes = bytes; return stats; } -- GitLab From 42952231c6a8623117ee3cc89c82d382dc69ca30 Mon Sep 17 00:00:00 2001 From: Ranjit Manomohan Date: Wed, 18 Oct 2006 20:54:26 -0700 Subject: [PATCH 1500/1619] [TG3]: Fix set ring params tx ring size implementation Fixes the implementation of the ethtool set ring parameters for the tg3 transmit ring. The size of tx_pending is taken into account before doing a netif_wake_queue. This prevents the interface from locking up when smaller transmit ring sizes are used. Signed-off-by: Ranjit Manomohan Acked-by: Michael Chan Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/tg3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 327836b1014..39e483308a4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -129,7 +129,7 @@ #define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64) /* minimum number of free TX descriptors required to wake up TX process */ -#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4) +#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) @@ -3075,10 +3075,10 @@ static void tg3_tx(struct tg3 *tp) smp_mb(); if (unlikely(netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) { + (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) { netif_tx_lock(tp->dev); if (netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)) + (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))) netif_wake_queue(tp->dev); netif_tx_unlock(tp->dev); } @@ -3928,7 +3928,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tp->tx_prod = entry; if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH) + if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) netif_wake_queue(tp->dev); } @@ -4143,7 +4143,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) tp->tx_prod = entry; if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH) + if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) netif_wake_queue(tp->dev); } -- GitLab From bc3a9254a7925b6278f6d882746fe6a0bdf6f610 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 18 Oct 2006 20:55:18 -0700 Subject: [PATCH 1501/1619] [TG3]: Add lower bound checks for tx ring size. The minimum tx ring size must be greater than MAX_SKB_FRAGS or 3 times that on some chips with TSO bugs. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 39e483308a4..7ba9dd2b1f8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8106,7 +8106,10 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) || (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || - (ering->tx_pending > TG3_TX_RING_SIZE - 1)) + (ering->tx_pending > TG3_TX_RING_SIZE - 1) || + (ering->tx_pending <= MAX_SKB_FRAGS) || + ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) && + (ering->tx_pending <= (MAX_SKB_FRAGS * 3)))) return -EINVAL; if (netif_running(dev)) { -- GitLab From 6ba7511b7c8b71d5148f7516584d0b677acc384a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Oct 2006 20:56:06 -0700 Subject: [PATCH 1502/1619] [TG3]: Bump driver version and release date. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7ba9dd2b1f8..8e398499c04 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.66" -#define DRV_MODULE_RELDATE "September 23, 2006" +#define DRV_MODULE_VERSION "3.67" +#define DRV_MODULE_RELDATE "October 18, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- GitLab From 6723ab549df777742801716d7aeea397e6e97f2c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Oct 2006 21:20:57 -0700 Subject: [PATCH 1503/1619] [IPV6]: Fix route.c warnings when multiple tables are disabled. Signed-off-by: David S. Miller --- net/ipv6/route.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5c00ca4fa52..c953466b7af 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -94,9 +94,6 @@ static int ip6_dst_gc(void); static int ip6_pkt_discard(struct sk_buff *skb); static int ip6_pkt_discard_out(struct sk_buff *skb); -static int ip6_pkt_prohibit(struct sk_buff *skb); -static int ip6_pkt_prohibit_out(struct sk_buff *skb); -static int ip6_pkt_blk_hole(struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); @@ -144,6 +141,10 @@ struct rt6_info ip6_null_entry = { #ifdef CONFIG_IPV6_MULTIPLE_TABLES +static int ip6_pkt_prohibit(struct sk_buff *skb); +static int ip6_pkt_prohibit_out(struct sk_buff *skb); +static int ip6_pkt_blk_hole(struct sk_buff *skb); + struct rt6_info ip6_prohibit_entry = { .u = { .dst = { @@ -1768,6 +1769,8 @@ static int ip6_pkt_discard_out(struct sk_buff *skb) return ip6_pkt_discard(skb); } +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + static int ip6_pkt_prohibit(struct sk_buff *skb) { return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED); @@ -1785,6 +1788,8 @@ static int ip6_pkt_blk_hole(struct sk_buff *skb) return 0; } +#endif + /* * Allocate a dst for local (unicast / anycast) address. */ -- GitLab From 55b7428303d390c53d3a1bc587de8592ce65900e Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Fri, 13 Oct 2006 13:37:35 +0200 Subject: [PATCH 1504/1619] [MIPS] Use kallsyms_lookup_size_offset() instead of kallsyms_lookup() This new routine doesn't lookup for symbol names. So we needn't to pass any char buffers or pointer since we don't care about names. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 9f307eb1a31..ec8209f3a0c 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -358,10 +358,8 @@ static int __init frame_info_init(void) unsigned long size = 0; #ifdef CONFIG_KALLSYMS unsigned long ofs; - char *modname; - char namebuf[KSYM_NAME_LEN + 1]; - kallsyms_lookup((unsigned long)schedule, &size, &ofs, &modname, namebuf); + kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs); #endif schedule_mfi.func = schedule; schedule_mfi.func_size = size; @@ -403,8 +401,6 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, { unsigned long stack_page; struct mips_frame_info info; - char *modname; - char namebuf[KSYM_NAME_LEN + 1]; unsigned long size, ofs; int leaf; extern void ret_from_irq(void); @@ -433,7 +429,7 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, } return 0; } - if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) + if (!kallsyms_lookup_size_offset(pc, &size, &ofs)) return 0; /* * Return ra if an exception occured at the first instruction -- GitLab From 22c56c3a03b377d21d8363f737aa2a855d892458 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 15 Oct 2006 09:15:19 +0100 Subject: [PATCH 1505/1619] [MIPS] Delete unneeded pt_regs forward declaration. Signed-off-by: Ralf Baechle --- arch/mips/oprofile/op_impl.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h index 354e5449640..fa6b4aae752 100644 --- a/arch/mips/oprofile/op_impl.h +++ b/arch/mips/oprofile/op_impl.h @@ -10,8 +10,6 @@ #ifndef OP_IMPL_H #define OP_IMPL_H 1 -struct pt_regs; - extern int null_perf_irq(void); extern int (*perf_irq)(void); -- GitLab From ba38cdf94285a1fc6a01fd493bdc5304bc83f61e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 15 Oct 2006 09:17:43 +0100 Subject: [PATCH 1506/1619] [MIPS] Malta: Fix uninitialized regs pointer. Signed-off-by: Ralf Baechle --- arch/mips/mips-boards/malta/malta_int.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index 6244d0e2c7d..90ad5bf3e2f 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -131,7 +132,7 @@ static void corehi_irqdispatch(void) unsigned int intedge, intsteer, pcicmd, pcibadaddr; unsigned int pcimstat, intisr, inten, intpol; unsigned int intrcause,datalo,datahi; - struct pt_regs *regs; + struct pt_regs *regs = get_irq_regs(); printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n"); printk("epc : %08lx\nStatus: %08lx\n" -- GitLab From 36d98e79b798fb27e38b9be4f36c5a96025f9281 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 15 Oct 2006 09:19:58 +0100 Subject: [PATCH 1507/1619] [MIPS] A few more pt_regs fixups. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/dbdma.c | 2 +- arch/mips/oprofile/op_model_rm9000.c | 3 +-- arch/mips/sgi-ip32/ip32-reset.c | 2 +- arch/mips/sibyte/sb1250/bcm1250_tbprof.c | 4 ++-- arch/mips/sibyte/sb1250/bus_watcher.c | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c index c4fae8ff467..626de44bd88 100644 --- a/arch/mips/au1000/common/dbdma.c +++ b/arch/mips/au1000/common/dbdma.c @@ -849,7 +849,7 @@ au1xxx_dbdma_chan_free(u32 chanid) EXPORT_SYMBOL(au1xxx_dbdma_chan_free); static irqreturn_t -dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +dbdma_interrupt(int irq, void *dev_id) { u32 intstat; u32 chan_index; diff --git a/arch/mips/oprofile/op_model_rm9000.c b/arch/mips/oprofile/op_model_rm9000.c index b7063fefa65..7dc9bf6f132 100644 --- a/arch/mips/oprofile/op_model_rm9000.c +++ b/arch/mips/oprofile/op_model_rm9000.c @@ -80,8 +80,7 @@ static void rm9000_cpu_stop(void *args) write_c0_perfcontrol(0); } -static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id, - struct pt_regs *regs) +static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id) { unsigned int control = read_c0_perfcontrol(); uint32_t counter1, counter2; diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index fd0932b2d52..db808441153 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -135,7 +135,7 @@ static inline void ip32_power_button(void) add_timer(&power_timer); } -static irqreturn_t ip32_rtc_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ip32_rtc_int(int irq, void *dev_id) { volatile unsigned char reg_c; diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c index 992e0d8dbb6..d1a906e683b 100644 --- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c +++ b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c @@ -88,7 +88,7 @@ static void arm_tb(void) sbp.tb_armed = 1; } -static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sbprof_tb_intr(int irq, void *dev_id) { int i; DBG(printk(DEVNAME ": tb_intr\n")); @@ -138,7 +138,7 @@ static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t sbprof_pc_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sbprof_pc_intr(int irq, void *dev_id) { printk(DEVNAME ": unexpected pc_intr"); return IRQ_NONE; diff --git a/arch/mips/sibyte/sb1250/bus_watcher.c b/arch/mips/sibyte/sb1250/bus_watcher.c index bb90649fbc4..45274bd3cd8 100644 --- a/arch/mips/sibyte/sb1250/bus_watcher.c +++ b/arch/mips/sibyte/sb1250/bus_watcher.c @@ -171,7 +171,7 @@ static void create_proc_decoder(struct bw_stats_struct *stats) * notes: possible re-entry due to multiple sources * should check/indicate saturation */ -static irqreturn_t sibyte_bw_int(int irq, void *data, struct pt_regs *regs) +static irqreturn_t sibyte_bw_int(int irq, void *data) { struct bw_stats_struct *stats = data; unsigned long cntr; -- GitLab From 53571ce47010562f5e67782ea00206f379a5cd65 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Sun, 13 Aug 2006 00:53:29 +0100 Subject: [PATCH 1508/1619] [MIPS] Fix O32 personality(2) call with 0xffffffff argument. A sign extension bug did result in sys_personality being invoked with a 0xffffffffffffffffUL argument, so querying the current personality didn't work. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/linux32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 53f4171fc18..7a3ebbeba1f 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -1055,7 +1055,9 @@ asmlinkage long sys32_newuname(struct new_utsname __user * name) asmlinkage int sys32_personality(unsigned long personality) { int ret; - if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality &= 0xffffffff; + if (personality(current->personality) == PER_LINUX32 && + personality == PER_LINUX) personality = PER_LINUX32; ret = sys_personality(personality); if (ret == PER_LINUX32) -- GitLab From 089c7e7f2da7c3245de47377252683bd9edae738 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 16 Oct 2006 16:49:37 +0100 Subject: [PATCH 1509/1619] [MIPS] Use compat_sys_mount. This fixes mount problems with smbfs, ncpfs and NFSv4. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/scall64-o32.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 6d9f18727ac..8c453f8ffea 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -280,7 +280,7 @@ EXPORT(sysn32_call_table) PTR sys_sync PTR sys_acct PTR sys32_settimeofday - PTR sys_mount /* 6160 */ + PTR compat_sys_mount /* 6160 */ PTR sys_umount PTR sys_swapon PTR sys_swapoff diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 2e6d0673163..d105917d6d9 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -226,7 +226,7 @@ sys_call_table: PTR sys_ni_syscall /* was sys_stat */ PTR sys_lseek PTR sys_getpid /* 4020 */ - PTR sys_mount + PTR compat_sys_mount PTR sys_oldumount PTR sys_setuid PTR sys_getuid -- GitLab From eea32d4c6e272b6c324c8c22df4c28274fcb5a21 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 16 Oct 2006 22:48:49 +0900 Subject: [PATCH 1510/1619] [MIPS] save_context_stack fix CONFIG_KALLSYMS=n case is obviously wrong, though it is harmless since CONFIG_KALLSYMS is always enabled with CONFIG_STACKTRACE for now. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/stacktrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 4aabe526a68..a586aba337a 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -57,7 +57,7 @@ static void save_context_stack(struct stack_trace *trace, pc = unwind_stack(task, &sp, pc, &ra); } while (pc); #else - save_raw_context_stack(sp); + save_raw_context_stack(trace, sp); #endif } -- GitLab From 94399ea62fc1047eded76b45b972e7850a800a1b Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 18 Oct 2006 23:27:29 +0900 Subject: [PATCH 1511/1619] [MIPS] More vr41xx pt_regs fixups Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/vr41xx/vr41xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h index dd3eb3dc588..88b492f6ea9 100644 --- a/include/asm-mips/vr41xx/vr41xx.h +++ b/include/asm-mips/vr41xx/vr41xx.h @@ -75,7 +75,7 @@ extern void vr41xx_mask_clock(vr41xx_clock_t clock); * Interrupt Control Unit */ extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign); -extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *)); +extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int)); #define PIUINT_COMMAND 0x0040 #define PIUINT_DATA 0x0020 -- GitLab From 00ddf2be159e3b96ba8872b407240e1bb449b75e Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 18 Oct 2006 23:36:15 +0900 Subject: [PATCH 1512/1619] [MIPS] Update pnx8500-jbs_defconfig In the current pnx8550-jbs_defconfig CONFIG_SGI_IP22 has been selected. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/configs/pnx8550-jbs_defconfig | 384 ++++++++++++++++++++---- 1 file changed, 330 insertions(+), 54 deletions(-) diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 26b0b988349..280a8001eac 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:18 2006 +# Linux kernel version: 2.6.19-rc2 +# Sat Oct 14 23:01:16 2006 # CONFIG_MIPS=y @@ -25,8 +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_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 @@ -41,13 +39,13 @@ CONFIG_MIPS=y # 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_PNX8550_JBS=y # 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=y +# CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP32 is not set # CONFIG_SIBYTE_BIGSUR is not set @@ -67,25 +65,21 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_ARC=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_SWAP_IO_SPACE=y -CONFIG_ARC32=y -CONFIG_BOOT_ELF32=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_PNX8550=y +CONFIG_SOC_PNX8550=y CONFIG_MIPS_L1_CACHE_SHIFT=5 -# CONFIG_ARC_CONSOLE is not set -CONFIG_ARC_PROMLIB=y # # CPU selection # -# CONFIG_CPU_MIPS32_R1 is not set +CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set @@ -93,7 +87,7 @@ CONFIG_ARC_PROMLIB=y # CONFIG_CPU_TX39XX is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set -CONFIG_CPU_R4X00=y +# CONFIG_CPU_R4X00 is not set # CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set @@ -104,12 +98,11 @@ CONFIG_CPU_R4X00=y # CONFIG_CPU_RM7000 is not set # CONFIG_CPU_RM9000 is not set # CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R4X00=y -CONFIG_SYS_HAS_CPU_R5000=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=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 @@ -120,17 +113,17 @@ 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_IP22_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_MT_SMTC 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 @@ -144,12 +137,12 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 # 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_250=y # CONFIG_HZ_256 is not set -CONFIG_HZ_1000=y +# CONFIG_HZ_1000 is not set # CONFIG_HZ_1024 is not set CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_HZ=1000 +CONFIG_HZ=250 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set @@ -171,16 +164,20 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -189,12 +186,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -211,6 +208,7 @@ CONFIG_KMOD=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set @@ -231,8 +229,10 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # Bus options (PCI, PCMCIA, EISA, ISA, TC) # -CONFIG_HW_HAS_EISA=y -# CONFIG_EISA is not set +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set +# CONFIG_PCI_DEBUG is not set CONFIG_MMU=y # @@ -243,6 +243,7 @@ CONFIG_MMU=y # # PCI Hotplug Support # +# CONFIG_HOTPLUG_PCI is not set # # Executable file formats @@ -265,6 +266,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -283,16 +285,18 @@ CONFIG_IP_PNP_BOOTP=y # 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_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set -CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set # @@ -318,7 +322,6 @@ CONFIG_NETWORK_SECMARK=y # 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 @@ -371,13 +374,20 @@ CONFIG_FW_LOADER=y # # 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=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -386,6 +396,7 @@ CONFIG_BLK_DEV_INITRD=y # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -404,8 +415,39 @@ CONFIG_BLK_DEV_IDESCSI=y # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_OFFBOARD=y +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_ARM is not set -# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_BLK_DEV_HD is not set @@ -414,6 +456,7 @@ CONFIG_IDE_GENERIC=y # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -434,21 +477,53 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_ISCSI_ATTRS=m # CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # CONFIG_ISCSI_TCP=m -# CONFIG_SGIWD93_SCSI is not set -# CONFIG_SCSI_SATA is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + # # Multi-device support (RAID and LVM) # @@ -458,14 +533,19 @@ CONFIG_ISCSI_TCP=m # Fusion MPT device support # # CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support # +# CONFIG_IEEE1394 is not set # # I2O device support # +# CONFIG_I2O is not set # # Network device support @@ -476,6 +556,11 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + # # PHY device support # @@ -486,20 +571,73 @@ CONFIG_NETDEVICES=y # CONFIG_NET_ETHERNET=y CONFIG_MII=y +# 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 -# CONFIG_SGISEEQ is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +# CONFIG_8139TOO_PIO is not set +CONFIG_8139TOO_TUNE_TWISTER=y +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_LAN_SAA9730 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_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX 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) @@ -510,8 +648,11 @@ CONFIG_MII=y # 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_NET_FC is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set @@ -531,6 +672,7 @@ CONFIG_MII=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -556,6 +698,7 @@ CONFIG_INPUT=y CONFIG_SERIO=y # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set @@ -566,7 +709,7 @@ CONFIG_SERIO_LIBPS2=y CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -577,7 +720,8 @@ CONFIG_VT_HW_CONSOLE_BINDING=y # # Non-8250 serial port support # -# CONFIG_SERIAL_IP22_ZILOG is not set +# CONFIG_SERIAL_IP3106 is not set +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -591,16 +735,17 @@ CONFIG_LEGACY_PTY_COUNT=256 # Watchdog Cards # # CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_SGI_DS1286 is not set # CONFIG_GEN_RTC is not set # 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 # @@ -631,35 +776,37 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set # CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices # # CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set # # Graphics support # -# CONFIG_FIRMWARE_EDID is not set +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set # # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_SGI_NEWPORT_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -669,14 +816,130 @@ CONFIG_DUMMY_CONSOLE=y # # 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 +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set + +# +# USB DSL modem support +# + # # USB Gadget Support # @@ -703,6 +966,7 @@ CONFIG_DUMMY_CONSOLE=y # # InfiniBand support # +# CONFIG_INFINIBAND is not set # # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) @@ -733,10 +997,12 @@ 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_EXT4DEV_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_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -769,8 +1035,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y # CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set @@ -813,7 +1081,6 @@ CONFIG_SUNRPC=y # 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 @@ -824,7 +1091,6 @@ CONFIG_SUNRPC=y # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_SGI_PARTITION=y # # Native Language Support @@ -880,6 +1146,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y @@ -893,13 +1160,17 @@ CONFIG_DEBUG_SLAB=y # CONFIG_DEBUG_SPINLOCK is not set CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set CONFIG_FORCED_INLINING=y +# CONFIG_HEADERS_CHECK is not set # CONFIG_RCU_TORTURE_TEST is not set CONFIG_CROSSCOMPILE=y CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" @@ -918,6 +1189,9 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_MANAGER=m # CONFIG_CRYPTO_HMAC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set @@ -927,6 +1201,8 @@ CONFIG_CRYPTO_MD5=m # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set -- GitLab From 0895b19ebdbb44d6d2eee0d7a138f07b2ddb04ec Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 18 Oct 2006 23:38:12 +0900 Subject: [PATCH 1513/1619] [MIPS] Update pnx8550-v2pci_defconfig In the current pnx8550-v2pci_defconfig CONFIG_SGI_IP22 has been selected. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/configs/pnx8550-v2pci_defconfig | 441 +++++++++++++++++++--- 1 file changed, 382 insertions(+), 59 deletions(-) diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index e93266b37dd..64b9fbf44a6 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:18 2006 +# Linux kernel version: 2.6.19-rc2 +# Sat Oct 14 23:12:15 2006 # CONFIG_MIPS=y @@ -25,8 +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_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 @@ -40,14 +38,14 @@ CONFIG_MIPS=y # 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_V2PCI=y # 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=y +# CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP32 is not set # CONFIG_SIBYTE_BIGSUR is not set @@ -67,25 +65,21 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_ARC=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_SWAP_IO_SPACE=y -CONFIG_ARC32=y -CONFIG_BOOT_ELF32=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_PNX8550=y +CONFIG_SOC_PNX8550=y CONFIG_MIPS_L1_CACHE_SHIFT=5 -# CONFIG_ARC_CONSOLE is not set -CONFIG_ARC_PROMLIB=y # # CPU selection # -# CONFIG_CPU_MIPS32_R1 is not set +CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set @@ -93,7 +87,7 @@ CONFIG_ARC_PROMLIB=y # CONFIG_CPU_TX39XX is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set -CONFIG_CPU_R4X00=y +# CONFIG_CPU_R4X00 is not set # CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set @@ -104,12 +98,11 @@ CONFIG_CPU_R4X00=y # CONFIG_CPU_RM7000 is not set # CONFIG_CPU_RM9000 is not set # CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R4X00=y -CONFIG_SYS_HAS_CPU_R5000=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=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 @@ -120,17 +113,17 @@ 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_IP22_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_MT_SMTC 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 @@ -144,12 +137,12 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 # 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_250=y # CONFIG_HZ_256 is not set -CONFIG_HZ_1000=y +# CONFIG_HZ_1000 is not set # CONFIG_HZ_1024 is not set CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_HZ=1000 +CONFIG_HZ=250 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set @@ -171,16 +164,20 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_HOTPLUG=y @@ -188,12 +185,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -210,6 +207,7 @@ CONFIG_KMOD=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set @@ -230,8 +228,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # Bus options (PCI, PCMCIA, EISA, ISA, TC) # -CONFIG_HW_HAS_EISA=y -# CONFIG_EISA is not set +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set CONFIG_MMU=y # @@ -242,6 +241,7 @@ CONFIG_MMU=y # # PCI Hotplug Support # +# CONFIG_HOTPLUG_PCI is not set # # Executable file formats @@ -264,6 +264,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -282,12 +283,14 @@ CONFIG_IP_PNP=y # 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_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" # # IP: Virtual Server Configuration @@ -300,12 +303,18 @@ CONFIG_IPV6_ROUTE_INFO=y # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set CONFIG_INET6_XFRM_MODE_TRANSPORT=m CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m # CONFIG_IPV6_TUNNEL is not set -CONFIG_NETWORK_SECMARK=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -318,9 +327,9 @@ CONFIG_NETFILTER_XTABLES=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m CONFIG_NETFILTER_XT_MATCH_DCCP=m +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set CONFIG_NETFILTER_XT_MATCH_ESP=m CONFIG_NETFILTER_XT_MATCH_LENGTH=m CONFIG_NETFILTER_XT_MATCH_LIMIT=m @@ -329,10 +338,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=m # CONFIG_NETFILTER_XT_MATCH_POLICY is not set CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set CONFIG_NETFILTER_XT_MATCH_REALM=m CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set CONFIG_NETFILTER_XT_MATCH_STRING=m CONFIG_NETFILTER_XT_MATCH_TCPMSS=m @@ -373,7 +382,6 @@ CONFIG_NETFILTER_XT_MATCH_TCPMSS=m # 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 @@ -426,13 +434,20 @@ CONFIG_FW_LOADER=y # # 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=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -441,6 +456,7 @@ CONFIG_BLK_DEV_INITRD=y # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -459,9 +475,41 @@ CONFIG_IDEDISK_MULTI_MODE=y # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX 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_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y # CONFIG_BLK_DEV_HD is not set # @@ -469,6 +517,7 @@ CONFIG_IDE_GENERIC=y # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -489,21 +538,58 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # CONFIG_SCSI_SPI_ATTRS=m CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_ISCSI_ATTRS=m # CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # CONFIG_ISCSI_TCP=m -# CONFIG_SGIWD93_SCSI is not set -# CONFIG_SCSI_SATA is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + # # Multi-device support (RAID and LVM) # @@ -513,14 +599,19 @@ CONFIG_ISCSI_TCP=m # Fusion MPT device support # # CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support # +# CONFIG_IEEE1394 is not set # # I2O device support # +# CONFIG_I2O is not set # # Network device support @@ -531,6 +622,11 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set CONFIG_TUN=m +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + # # PHY device support # @@ -541,20 +637,73 @@ CONFIG_TUN=m # CONFIG_NET_ETHERNET=y CONFIG_MII=y +# 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 -# CONFIG_SGISEEQ is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +CONFIG_NATSEMI=y +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_LAN_SAA9730 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_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX 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) @@ -565,6 +714,8 @@ CONFIG_MII=y # Wan interfaces # # CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set CONFIG_PPP=m # CONFIG_PPP_MULTILINK is not set # CONFIG_PPP_FILTER is not set @@ -575,6 +726,8 @@ CONFIG_PPP_DEFLATE=m CONFIG_PPP_MPPE=m # CONFIG_PPPOE is not set # CONFIG_SLIP is not set +CONFIG_SLHC=m +# CONFIG_NET_FC is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set @@ -594,6 +747,7 @@ CONFIG_PPP_MPPE=m # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -616,6 +770,7 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set @@ -630,6 +785,7 @@ CONFIG_MOUSE_PS2=y CONFIG_SERIO=y CONFIG_SERIO_I8042=y CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set @@ -640,7 +796,7 @@ CONFIG_SERIO_LIBPS2=y CONFIG_VT=y # CONFIG_VT_CONSOLE is not set CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set CONFIG_SERIAL_NONSTANDARD=y # CONFIG_COMPUTONE is not set # CONFIG_ROCKETPORT is not set @@ -650,6 +806,7 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_MOXA_SMARTIO is not set # CONFIG_ISI is not set # CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set # CONFIG_N_HDLC is not set # CONFIG_RISCOM8 is not set # CONFIG_SPECIALIX is not set @@ -665,7 +822,8 @@ CONFIG_SERIAL_NONSTANDARD=y # # Non-8250 serial port support # -# CONFIG_SERIAL_IP22_ZILOG is not set +# CONFIG_SERIAL_IP3106 is not set +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -679,16 +837,17 @@ CONFIG_LEGACY_PTY_COUNT=256 # Watchdog Cards # # CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_SGI_DS1286 is not set # CONFIG_GEN_RTC is not set # 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 # @@ -709,14 +868,30 @@ CONFIG_I2C_CHARDEV=m CONFIG_I2C_ALGOBIT=m # CONFIG_I2C_ALGOPCF is not set # CONFIG_I2C_ALGOPCA is not set -# CONFIG_I2C_ALGO_SGI is not set # # I2C Hardware Bus support # +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set # CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set # @@ -776,9 +951,13 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83791D is not set # CONFIG_SENSORS_W83792D is not set @@ -790,23 +969,25 @@ CONFIG_HWMON=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices # # CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set # # Graphics support # -# CONFIG_FIRMWARE_EDID is not set +CONFIG_FIRMWARE_EDID=y CONFIG_FB=y +# CONFIG_FB_DDC is not set # CONFIG_FB_CFB_FILLRECT is not set # CONFIG_FB_CFB_COPYAREA is not set # CONFIG_FB_CFB_IMAGEBLIT is not set @@ -814,14 +995,32 @@ CONFIG_FB=y # CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set # CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_SMIVGX is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set # # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_SGI_NEWPORT_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # CONFIG_FRAMEBUFFER_CONSOLE is not set @@ -839,14 +1038,128 @@ CONFIG_DUMMY_CONSOLE=y # # 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 +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + # # USB Gadget Support # @@ -873,6 +1186,7 @@ CONFIG_DUMMY_CONSOLE=y # # InfiniBand support # +# CONFIG_INFINIBAND is not set # # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) @@ -906,6 +1220,7 @@ CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y @@ -917,6 +1232,7 @@ CONFIG_XFS_FS=m # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set # CONFIG_XFS_RT is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -949,8 +1265,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y # CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set @@ -994,7 +1312,6 @@ CONFIG_SUNRPC=y CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT 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 @@ -1005,7 +1322,6 @@ CONFIG_SMB_FS=m # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_SGI_PARTITION=y # # Native Language Support @@ -1061,11 +1377,13 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y # 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_HEADERS_CHECK is not set CONFIG_CROSSCOMPILE=y CONFIG_CMDLINE="" @@ -1079,6 +1397,9 @@ CONFIG_CMDLINE="" # Cryptographic options # CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_MANAGER=m # CONFIG_CRYPTO_HMAC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set @@ -1088,6 +1409,8 @@ CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set -- GitLab From e7a6f9c1f4e46f7fd776c6ee38bdb8f8ae131a82 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 18 Oct 2006 23:48:31 +0900 Subject: [PATCH 1514/1619] [MIPS] Update tb0287_defconfig Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/configs/tb0287_defconfig | 182 ++++++++++++++++------------- 1 file changed, 99 insertions(+), 83 deletions(-) diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index ad7271b3f26..f7e8194809a 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:21 2006 +# Linux kernel version: 2.6.19-rc2 +# Wed Oct 18 12:57:11 2006 # CONFIG_MIPS=y @@ -25,8 +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_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 @@ -72,11 +70,11 @@ CONFIG_TANBAC_TB0287=y # CONFIG_VICTOR_MPC30X is not set # CONFIG_ZAO_CAPCELLA is not set CONFIG_PCI_VR41XX=y -# CONFIG_VRC4173 is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_NONCOHERENT=y CONFIG_DMA_NEED_PCI_MAP_STATE=y @@ -123,8 +121,8 @@ CONFIG_PAGE_SIZE_4KB=y # 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_MT_SMTC is not set # CONFIG_MIPS_VPE_LOADER is not set CONFIG_CPU_HAS_SYNC=y CONFIG_GENERIC_HARDIRQS=y @@ -169,15 +167,19 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_EXTRA_PASS is not set # CONFIG_HOTPLUG is not set @@ -185,12 +187,12 @@ 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_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -208,6 +210,7 @@ CONFIG_KMOD=y # # Block layer # +CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set @@ -230,17 +233,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_HW_HAS_PCI=y CONFIG_PCI=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set CONFIG_MMU=y # # PCCARD (PCMCIA/CardBus) support # -# CONFIG_PCCARD is not set # # PCI Hotplug Support # -# CONFIG_HOTPLUG_PCI is not set # # Executable file formats @@ -263,6 +265,7 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -291,13 +294,10 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_TUNNEL=m CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y CONFIG_TCP_CONG_ADVANCED=y - -# -# TCP congestion control -# CONFIG_TCP_CONG_BIC=y CONFIG_TCP_CONG_CUBIC=m CONFIG_TCP_CONG_WESTWOOD=m @@ -308,7 +308,13 @@ CONFIG_TCP_CONG_HTCP=m # CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_TCP_CONG_LP is not set # CONFIG_TCP_CONG_VENO is not set -# CONFIG_TCP_CONG_COMPOUND is not set +CONFIG_DEFAULT_BIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="bic" # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -338,7 +344,6 @@ CONFIG_NETWORK_SECMARK=y # 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 @@ -355,6 +360,7 @@ CONFIG_NETWORK_SECMARK=y # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_IEEE80211 is not set +CONFIG_FIB_RULES=y # # Device Drivers @@ -365,7 +371,6 @@ CONFIG_NETWORK_SECMARK=y # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -403,6 +408,7 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -410,65 +416,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # 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_BLK_DEV_IDESCSI is not set -# CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_BLK_DEV_GENERIC is not set -# CONFIG_BLK_DEV_OPTI621 is not set -CONFIG_BLK_DEV_IDEDMA_PCI=y -# CONFIG_BLK_DEV_IDEDMA_FORCED is not set -# CONFIG_IDEDMA_PCI_AUTO is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD74XX is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_BLK_DEV_TRIFLEX is not set -# CONFIG_BLK_DEV_CY82C693 is not set -# CONFIG_BLK_DEV_CS5520 is not set -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_SC1200 is not set -# CONFIG_BLK_DEV_PIIX is not set -# CONFIG_BLK_DEV_IT821X is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_PDC202XX_OLD is not set -# CONFIG_BLK_DEV_PDC202XX_NEW is not set -# CONFIG_BLK_DEV_SVWKS is not set -CONFIG_BLK_DEV_SIIMAGE=y -# CONFIG_BLK_DEV_SLC90E66 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_IDE_ARM is not set -CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_IDEDMA_IVB is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_BLK_DEV_HD is not set +# CONFIG_IDE is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +# CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y # @@ -489,12 +444,13 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers @@ -507,27 +463,83 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set # CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set -# CONFIG_SCSI_SATA is not set # CONFIG_SCSI_HPTIOP is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +CONFIG_PATA_SIL680=y +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set + # # Multi-device support (RAID and LVM) # @@ -632,6 +644,7 @@ CONFIG_R8169=y # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set # # Ethernet (10000 Mbit) @@ -679,6 +692,7 @@ CONFIG_R8169=y # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -758,7 +772,6 @@ CONFIG_GPIO_VR41XX=y # TPM devices # # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set # # I2C support @@ -784,12 +797,12 @@ CONFIG_GPIO_VR41XX=y # # Misc devices # +# CONFIG_TIFM_CORE is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -897,13 +910,13 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_LIBUSUAL is not set # @@ -932,6 +945,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_TRANCEVIBRATOR is not set # # USB Imaging devices @@ -963,16 +977,17 @@ CONFIG_USB_MON=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set -# CONFIG_USB_CY7C63 is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGETKIT is not set -# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set @@ -1041,6 +1056,7 @@ CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y @@ -1052,6 +1068,7 @@ CONFIG_XFS_QUOTA=y # CONFIG_XFS_SECURITY is not set CONFIG_XFS_POSIX_ACL=y # CONFIG_XFS_RT is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=m @@ -1082,8 +1099,10 @@ CONFIG_AUTOFS4_FS=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set @@ -1123,7 +1142,6 @@ CONFIG_SUNRPC=y # 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 @@ -1150,11 +1168,13 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y # 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_HEADERS_CHECK is not set CONFIG_CROSSCOMPILE=y CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs" @@ -1169,10 +1189,6 @@ CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs" # # CONFIG_CRYPTO is not set -# -# Hardware crypto devices -# - # # Library routines # -- GitLab From d2bcf87d0fcdc10d1be65b03fd032bec05efe49f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 18 Oct 2006 23:52:17 +0100 Subject: [PATCH 1515/1619] [MIPS] Reserve syscall numbers for kexec_load. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 3 ++- arch/mips/kernel/scall64-64.S | 1 + arch/mips/kernel/scall64-n32.S | 1 + arch/mips/kernel/scall64-o32.S | 1 + include/asm-mips/unistd.h | 15 +++++++++------ 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 61362e6fa9e..720fac3435d 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -652,7 +652,8 @@ einval: li v0, -EINVAL sys sys_vmsplice 4 sys sys_move_pages 6 sys sys_set_robust_list 2 - sys sys_get_robust_list 3 + sys sys_get_robust_list 3 /* 4310 */ + sys sys_ni_syscall 0 .endm /* We pre-compute the number of _instruction_ bytes needed to diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 6c7b5ed0ea6..3a34f62c8b1 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -468,3 +468,4 @@ sys_call_table: PTR sys_move_pages PTR sys_set_robust_list PTR sys_get_robust_list + PTR sys_ni_syscall /* 5270 */ diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 8c453f8ffea..67b92a1d6c7 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -394,3 +394,4 @@ EXPORT(sysn32_call_table) PTR sys_move_pages PTR compat_sys_set_robust_list PTR compat_sys_get_robust_list + PTR sys_ni_syscall diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index d105917d6d9..2875c4a3fa5 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -516,4 +516,5 @@ 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 .size sys_call_table,.-sys_call_table diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index 685c91467e6..30240a445db 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -331,16 +331,17 @@ #define __NR_move_pages (__NR_Linux + 308) #define __NR_set_robust_list (__NR_Linux + 309) #define __NR_get_robust_list (__NR_Linux + 310) +#define __NR_kexec_load (__NR_Linux + 311) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 310 +#define __NR_Linux_syscalls 311 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 310 +#define __NR_O32_Linux_syscalls 311 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -618,16 +619,17 @@ #define __NR_move_pages (__NR_Linux + 267) #define __NR_set_robust_list (__NR_Linux + 268) #define __NR_get_robust_list (__NR_Linux + 269) +#define __NR_kexec_load (__NR_Linux + 270) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 269 +#define __NR_Linux_syscalls 270 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 269 +#define __NR_64_Linux_syscalls 270 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -909,16 +911,17 @@ #define __NR_move_pages (__NR_Linux + 271) #define __NR_set_robust_list (__NR_Linux + 272) #define __NR_get_robust_list (__NR_Linux + 273) +#define __NR_kexec_load (__NR_Linux + 274) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 273 +#define __NR_Linux_syscalls 274 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 273 +#define __NR_N32_Linux_syscalls 274 #ifdef __KERNEL__ -- GitLab From d89e36d8df547fde2beaea82211954868da2282d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 Oct 2006 14:21:47 +0100 Subject: [PATCH 1516/1619] [MIPS] Fix iounmap argument to const volatile. With the existing prototype the following code: const void __iomem *io = ioremap(); x = readb(io); iounmap(io); did result in a warning. Signed-off-by: Ralf Baechle --- arch/mips/mm/ioremap.c | 2 +- include/asm-mips/io.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c index 3101d1db559..cea7d0ea36e 100644 --- a/arch/mips/mm/ioremap.c +++ b/arch/mips/mm/ioremap.c @@ -176,7 +176,7 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags) #define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1) -void __iounmap(volatile void __iomem *addr) +void __iounmap(const volatile void __iomem *addr) { struct vm_struct *p; diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index c2d124badbe..bc5f3c53155 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -172,7 +172,7 @@ extern unsigned long isa_slot_offset; #define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) extern void __iomem * __ioremap(phys_t offset, phys_t size, unsigned long flags); -extern void __iounmap(volatile void __iomem *addr); +extern void __iounmap(const volatile void __iomem *addr); static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size, unsigned long flags) @@ -279,7 +279,7 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size, #define ioremap_uncached_accelerated(offset, size) \ __ioremap_mode((offset), (size), _CACHE_UNCACHED_ACCELERATED) -static inline void iounmap(volatile void __iomem *addr) +static inline void iounmap(const volatile void __iomem *addr) { #define __IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1) -- GitLab From e83f214e45a80459d2931ae1259ab5fae82c8a8e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Oct 2006 12:48:35 -0700 Subject: [PATCH 1517/1619] [SPARC64]: Compute dma_end argument to sabre_pbm_init() correctly. virtual-dma property layout is [start, size] not [start, end]. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_sabre.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index de7f7850a84..94bb681f232 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1465,5 +1465,5 @@ void sabre_init(struct device_node *dp, char *model_name) /* * Look for APB underneath. */ - sabre_pbm_init(p, dp, vdma[0], vdma[1]); + sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]); } -- GitLab From 6bda57365a5fda4743d83a5987c6aab66e90771c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Oct 2006 23:00:35 -0700 Subject: [PATCH 1518/1619] [SPARC64]: Fix of_ioremap(). Use request_mem_region() if IORESOURCE_MEM. Signed-off-by: David S. Miller --- arch/sparc64/kernel/of_device.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index d822c7c18e1..d3dfb2a36d4 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -131,8 +131,13 @@ static int of_device_resume(struct device * dev) void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) { unsigned long ret = res->start + offset; + struct resource *r; - if (!request_region(ret, size, name)) + if (res->flags & IORESOURCE_MEM) + r = request_mem_region(ret, size, name); + else + r = request_region(ret, size, name); + if (!r) ret = 0; return (void __iomem *) ret; -- GitLab From 206daaf77f68ce0f103164e6406336068c87a4a5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 19 Oct 2006 23:58:23 -0700 Subject: [PATCH 1519/1619] [NETPOLL]: initialize skb for UDP Need to fully initialize skb to keep lower layers and queueing happy. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/core/netpoll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index ead5920c26d..9308af060b4 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -335,13 +335,13 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) memcpy(skb->data, msg, len); skb->len += len; - udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); + skb->h.uh = udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); udph->source = htons(np->local_port); udph->dest = htons(np->remote_port); udph->len = htons(udp_len); udph->check = 0; - iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); + skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); /* iph->version = 4; iph->ihl = 5; */ put_unaligned(0x45, (unsigned char *)iph); @@ -357,8 +357,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); - - eth->h_proto = htons(ETH_P_IP); + skb->mac.raw = skb->data; + skb->protocol = eth->h_proto = htons(ETH_P_IP); memcpy(eth->h_source, np->local_mac, 6); memcpy(eth->h_dest, np->remote_mac, 6); -- GitLab From 82fac0542e11c0d3316cc8fdafd2a990d2aab692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 20 Oct 2006 00:21:10 -0700 Subject: [PATCH 1520/1619] [NETFILTER]: Missing check for CAP_NET_ADMIN in iptables compat layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 32bit compatibility layer has no CAP_NET_ADMIN check in compat_do_ipt_get_ctl, which for example allows to list the current iptables rules even without having that capability (the non-compat version requires it). Other capabilities might be required to exploit the bug (eg. CAP_NET_RAW to get the nfnetlink socket?), so a plain user can't exploit it, but a setup actually using the posix capability system might very well hit such a constellation of granted capabilities. Signed-off-by: Björn Steinbrink Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_tables.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 78a44b01c03..4b90927619b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1932,6 +1932,9 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) { int ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch (cmd) { case IPT_SO_GET_INFO: ret = get_info(user, len, 1); -- GitLab From 06ca719faddaf5ea46c6356b12847663c3ed8806 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 20 Oct 2006 00:22:25 -0700 Subject: [PATCH 1521/1619] [TCP]: One NET_INC_STATS() could be NET_INC_STATS_BH in tcp_v4_err() I believe this NET_INC_STATS() call can be replaced by NET_INC_STATS_BH(), a little bit cheaper. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6bbd9857517..22ef8bd2662 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -373,7 +373,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) seq = ntohl(th->seq); if (sk->sk_state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { - NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS); + NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS); goto out; } -- GitLab From 78d79423179c0efc7ec34b55d287e7be4ca07da6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 20 Oct 2006 00:28:35 -0700 Subject: [PATCH 1522/1619] [IPV4] inet_peer: Group together avl_left, avl_right, v4daddr to speedup lookups on some CPUS Lot of routers/embedded devices still use CPUS with 16/32 bytes cache lines. (486, Pentium, ... PIII) It makes sense to group together fields used at lookup time so they fit in one cache line. This reduce cache footprint and speedup lookups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inetpeer.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index f13cc0c2b16..aa10a8178e7 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -17,14 +17,15 @@ struct inet_peer { + /* group together avl_left,avl_right,v4daddr to speedup lookups */ struct inet_peer *avl_left, *avl_right; + __be32 v4daddr; /* peer's address */ + __u16 avl_height; + __u16 ip_id_count; /* IP ID for the next packet */ struct inet_peer *unused_next, **unused_prevp; __u32 dtime; /* the time of last use of not * referenced entries */ atomic_t refcnt; - __be32 v4daddr; /* peer's address */ - __u16 avl_height; - __u16 ip_id_count; /* IP ID for the next packet */ atomic_t rid; /* Frag reception counter */ __u32 tcp_ts; unsigned long tcp_ts_stamp; -- GitLab From 6cf431d77c3e917399a847e3a7ec239d5163056b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 20 Oct 2006 00:29:33 -0700 Subject: [PATCH 1523/1619] [SPARC]: Clean up asm-sparc/elf.h pollution in userspace. We don't need to export sparc_elf_hwcap() to userspace, and it doesn't build there. Remove it by moving it inside #ifdef __KERNEL__, along with some other things which don't need to be exported. Signed-off-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/asm-sparc/elf.h | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h index 83a3dd15a6e..aaf6ef40ee2 100644 --- a/include/asm-sparc/elf.h +++ b/include/asm-sparc/elf.h @@ -8,11 +8,6 @@ #include -#ifdef __KERNEL__ -#include -#include -#endif - /* * Sparc section types */ @@ -77,6 +72,23 @@ typedef unsigned long elf_greg_t; #define ELF_NGREG 38 typedef elf_greg_t elf_gregset_t[ELF_NGREG]; +typedef struct { + union { + unsigned long pr_regs[32]; + double pr_dregs[16]; + } pr_fr; + unsigned long __unused; + unsigned long pr_fsr; + unsigned char pr_qcnt; + unsigned char pr_q_entrysize; + unsigned char pr_en; + unsigned int pr_q[64]; +} elf_fpregset_t; + +#ifdef __KERNEL__ +#include +#include + /* Format is: * G0 --> G7 * O0 --> O7 @@ -99,20 +111,7 @@ do { unsigned long *dest = &(__elf_regs[0]); \ dest[34] = src->npc; \ dest[35] = src->y; \ dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); /* Janitors: Don't touch this colon. */ - -typedef struct { - union { - unsigned long pr_regs[32]; - double pr_dregs[16]; - } pr_fr; - unsigned long __unused; - unsigned long pr_fsr; - unsigned char pr_qcnt; - unsigned char pr_q_entrysize; - unsigned char pr_en; - unsigned int pr_q[64]; -} elf_fpregset_t; +} while(0); /* Janitors: Don't touch this semicolon. */ #define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \ ({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; }) @@ -165,8 +164,8 @@ typedef struct { #define ELF_PLATFORM (NULL) -#ifdef __KERNEL__ #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) -#endif + +#endif /* __KERNEL__ */ #endif /* !(__ASMSPARC_ELF_H) */ -- GitLab From 58f539740b1ccfc5ef4e509ec2efe82621b546e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 20 Oct 2006 00:32:41 -0700 Subject: [PATCH 1524/1619] [NET]: Can use __get_cpu_var() instead of per_cpu() in loopback driver. As BHs are off in loopback_xmit(), preemption cannot occurs, so we can use __get_cpu_var() instead of per_cpu() (and avoid a preempt_enable()/preempt_disable() pair) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 93fbea1c927..82c10dec1b5 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -153,14 +153,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; - lb_stats = &per_cpu(pcpu_lstats, get_cpu()); + /* it's OK to use __get_cpu_var() because BHs are off */ + lb_stats = &__get_cpu_var(pcpu_lstats); lb_stats->bytes += skb->len; lb_stats->packets++; - put_cpu(); netif_rx(skb); - return(0); + return 0; } static struct net_device_stats loopback_stats; -- GitLab From 0eab934f4b9668669cffebfa8a9542fedf9082af Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 20 Oct 2006 08:55:29 +0200 Subject: [PATCH 1525/1619] [Bluetooth] Add support for newer ANYCOM USB dongles This patch adds the vendor and product id of the ANYCOM Bluetooth USB-200 and USB-250 dongles and sets a flag to send HCI_Reset as the first command. Signed-off-by: Marcel Holtmann Date: Fri, 20 Oct 2006 08:55:34 +0200 Subject: [PATCH 1526/1619] [Bluetooth] Add missing entry for Nokia DTL-4 PCMCIA card The device id for the Nokia DTL-4 PCMCIA card was missing. This patch adds it back to the list of supported devices. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index e7c800f4c3a..07eafbc5dc3 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -711,6 +711,7 @@ static void dtl1_release(struct pcmcia_device *link) static struct pcmcia_device_id dtl1_ids[] = { PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d), + PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82), PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863), PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3), PCMCIA_DEVICE_NULL -- GitLab From 7b19ffc40b0247fcfe083644fdb621fdb3c05ef6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 20 Oct 2006 08:55:48 +0200 Subject: [PATCH 1527/1619] [Bluetooth] Fix HID disconnect NULL pointer dereference The latest HID disconnect sequence change introduced a NULL pointer dereference. For the quirk to handle buggy remote HID implementations, it is enough to wait for a potential control channel disconnect from the remote side and it is also enough to wait only 500 msecs. Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 9a562cf7406..66782010f82 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -507,12 +507,10 @@ static int hidp_session(void *arg) hidp_del_timer(session); - if (intr_sk->sk_state != BT_CONNECTED) - wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ); - fput(session->intr_sock->file); - wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ); + wait_event_timeout(*(ctrl_sk->sk_sleep), + (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500)); fput(session->ctrl_sock->file); -- GitLab From 42fb00838a644d03f9a2a5fbbe0b668a5ff5df4d Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Fri, 13 Oct 2006 17:12:05 +0100 Subject: [PATCH 1528/1619] [DLM] fix iovec length in recvmsg I didn't spot that the msg_iovlen was set to 2 if there were two elements in the iovec but left at zero if not :( I think this might be why bob was still seeing trouble. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 867f93d0417..6da6b14d5a6 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -519,6 +519,7 @@ static int receive_from_sock(void) msg.msg_flags = 0; msg.msg_control = incmsg; msg.msg_controllen = sizeof(incmsg); + msg.msg_iovlen = 1; /* 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 -- GitLab From 23591256d61354e20f12e98d7a496ad5c23de74c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 13 Oct 2006 17:25:45 -0400 Subject: [PATCH 1529/1619] [GFS2] Fix bmap to map extents properly This fix means that bmap will map extents of the length requested by the VFS rather than guessing at it, or just mapping one block at a time. The other callers of gfs2_block_map are audited to ensure they send the correct max extent lengths (i.e. set bh->b_size correctly). Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 13 +++++++------ fs/gfs2/bmap.h | 2 +- fs/gfs2/log.c | 6 ++++-- fs/gfs2/ops_address.c | 6 +++--- fs/gfs2/quota.c | 5 +++-- fs/gfs2/recovery.c | 5 +++-- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cc57f2ecd21..06e9a8cb45e 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -434,8 +434,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, */ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, - struct buffer_head *bh_map, struct metapath *mp, - unsigned int maxlen) + struct buffer_head *bh_map, struct metapath *mp) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -448,6 +447,7 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, int new = 0; u64 dblock = 0; int boundary; + unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; BUG_ON(maxlen == 0); @@ -541,13 +541,13 @@ static inline void bmap_unlock(struct inode *inode, int create) } int gfs2_block_map(struct inode *inode, u64 lblock, int create, - struct buffer_head *bh, unsigned int maxlen) + struct buffer_head *bh) { struct metapath mp; int ret; bmap_lock(inode, create); - ret = gfs2_block_pointers(inode, lblock, create, bh, &mp, maxlen); + ret = gfs2_block_pointers(inode, lblock, create, bh, &mp); bmap_unlock(inode, create); return ret; } @@ -555,7 +555,7 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create, int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) { struct metapath mp; - struct buffer_head bh = { .b_state = 0, .b_blocknr = 0, .b_size = 0 }; + struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 }; int ret; int create = *new; @@ -563,8 +563,9 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!dblock); BUG_ON(!new); + bh.b_size = 1 << (inode->i_blkbits + 5); bmap_lock(inode, create); - ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, 32); + ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp); bmap_unlock(inode, create); *extlen = bh.b_size >> inode->i_blkbits; *dblock = bh.b_blocknr; diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 0fd379b4cd9..ac2fd04370d 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -15,7 +15,7 @@ struct gfs2_inode; struct page; int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); -int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh, unsigned int maxlen); +int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh); int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); int gfs2_truncatei(struct gfs2_inode *ip, u64 size); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 72eec6542d6..0cace3da9db 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -312,10 +312,12 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) { + struct inode *inode = sdp->sd_jdesc->jd_inode; int error; - struct buffer_head bh_map; + struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; - error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, 0, &bh_map, 1); + bh_map.b_size = 1 << inode->i_blkbits; + error = gfs2_block_map(inode, lbn, 0, &bh_map); if (error || !bh_map.b_blocknr) printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, bh_map.b_blocknr, lbn); gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index e0599fed99c..8d5963c7e12 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -65,7 +65,7 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, create, bh_result, 32); + return gfs2_block_map(inode, lblock, create, bh_result); } /** @@ -83,7 +83,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, { int error; - error = gfs2_block_map(inode, lblock, 0, bh_result, 1); + error = gfs2_block_map(inode, lblock, 0, bh_result); if (error) return error; if (bh_result->b_blocknr == 0) @@ -94,7 +94,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, static int gfs2_get_block_direct(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, 0, bh_result, 32); + return gfs2_block_map(inode, lblock, 0, bh_result); } /** diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c69b94a5558..a3deae7416c 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -251,7 +251,7 @@ static int bh_get(struct gfs2_quota_data *qd) unsigned int block, offset; struct buffer_head *bh; int error; - struct buffer_head bh_map; + struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; mutex_lock(&sdp->sd_quota_mutex); @@ -263,7 +263,8 @@ 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_inode, block, 0, &bh_map, 1); + bh_map.b_size = 1 << ip->i_inode.i_blkbits; + error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map); if (error) goto fail; error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 0a8a4b87dcc..62cd223819b 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -372,11 +372,12 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) u32 hash; struct buffer_head *bh; int error; - struct buffer_head bh_map; + struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; lblock = head->lh_blkno; gfs2_replay_incr_blk(sdp, &lblock); - error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map, 1); + bh_map.b_size = 1 << ip->i_inode.i_blkbits; + error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map); if (error) return error; if (!bh_map.b_blocknr) { -- GitLab From a2d7d021d78dbc00d24d9c809c64a7f3e61fa773 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2006 16:49:30 +0100 Subject: [PATCH 1530/1619] [GFS2] gfs2 endianness bug: be16 assigned to be32 field Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 459498cac93..d43caf04bb6 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -815,7 +815,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, leaf = (struct gfs2_leaf *)bh->b_data; leaf->lf_depth = cpu_to_be16(depth); leaf->lf_entries = 0; - leaf->lf_dirent_format = cpu_to_be16(GFS2_FORMAT_DE); + leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); leaf->lf_next = 0; memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); dent = (struct gfs2_dirent *)(leaf+1); -- GitLab From abbdbd2065e74411dc2c401501c2c85a82f60e06 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 19 Oct 2006 15:12:24 +0200 Subject: [PATCH 1531/1619] [GFS2] fs/gfs2/dir.c:gfs2_dir_write_data(): remove dead code The Coverity checker spotted this obviously dead code. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index d43caf04bb6..ce52bd954df 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -212,8 +212,6 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, gfs2_trans_add_bh(ip->i_gl, bh, 1); memcpy(bh->b_data + o, buf, amount); brelse(bh); - if (error) - goto fail; buf += amount; copied += amount; -- GitLab From b0cb66955f4bf7a72b544096ceef48a829361a3c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 19 Oct 2006 15:13:26 +0200 Subject: [PATCH 1532/1619] [GFS2] fs/gfs2/ops_fstype.c:gfs2_get_sb_meta(): remove unused variable The Coverity checker spotted this unused variable. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 178b3391184..e99444dffeb 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -854,7 +854,6 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, int error = 0; struct super_block *sb = NULL, *new; struct gfs2_sbd *sdp; - char *gfs2mnt = NULL; sb = get_gfs2_sb(dev_name); if (!sb) { @@ -892,8 +891,6 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, atomic_inc(&sdp->sd_gfs2mnt->mnt_count); return simple_set_mnt(mnt, new); error: - if (gfs2mnt) - kfree(gfs2mnt); return error; } -- GitLab From 348acd48f050f5ba7fa917b1421ae34443be97dd Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 19 Oct 2006 15:20:04 +0200 Subject: [PATCH 1533/1619] [GFS2] fs/gfs2/dir.c:gfs2_dir_write_data(): don't use an uninitialized variable In the "if (extlen)" case, "new" might be used uninitialized. Looking at the code, it should be initialized to 0. Spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ce52bd954df..ead7df06685 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -184,7 +184,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, while (copied < size) { unsigned int amount; struct buffer_head *bh; - int new; + int new = 0; amount = size - copied; if (amount > sdp->sd_sb.sb_bsize - o) -- GitLab From bbbe4512735eb0f15f09ffd14876091a8e91bc69 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 19 Oct 2006 15:27:00 +0200 Subject: [PATCH 1534/1619] [GFS2] fs/gfs2/ops_fstype.c:fill_super_meta(): fix NULL dereference Don't dereference new->s_root when we do know it's NULL. Spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index e99444dffeb..882873a6bd6 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -794,8 +794,8 @@ static int fill_super_meta(struct super_block *sb, struct super_block *new, fs_err(sdp, "can't get root dentry\n"); error = -ENOMEM; iput(inode); - } - new->s_root->d_op = &gfs2_dops; + } else + new->s_root->d_op = &gfs2_dops; return error; } -- GitLab From b7d8ac3e1779c30ddef0a8f38042076c5007a23d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 19 Oct 2006 16:02:07 +0200 Subject: [PATCH 1535/1619] [GFS2] gfs2_dir_read_data(): fix uninitialized variable usage In the "if (extlen)" case, "bh" was used uninitialized. This patch changes the code to what seems to have been intended. Spotted by the Coverity checker. This patch also removes a pointless "bh = NULL" asignment (the variable is never accessed again after this point). Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ead7df06685..e24af28b1a1 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -315,8 +315,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, if (!ra) extlen = 1; bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); - } - if (!bh) { + } else { error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); if (error) goto fail; @@ -330,7 +329,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, extlen--; memcpy(buf, bh->b_data + o, amount); brelse(bh); - bh = NULL; buf += amount; copied += amount; lblock++; -- GitLab From e8e82b76e0312827f5ae04b573a05b02854a447e Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 19 Oct 2006 23:28:12 -0700 Subject: [PATCH 1536/1619] [PATCH] e100: fix reboot -f with netconsole enabled When rebooting with netconsole over e100, the driver shutdown code would deadlock with netpoll. Reduce shutdown code to a bare minimum while retaining WoL and suspend functionality. Signed-off-by: Auke Kok Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/e100.c | 50 ++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 27d5d2f0253..a3a08a5dd18 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2039,7 +2039,6 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu) return 0; } -#ifdef CONFIG_PM static int e100_asf(struct nic *nic) { /* ASF can be enabled from eeprom */ @@ -2048,7 +2047,6 @@ static int e100_asf(struct nic *nic) !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); } -#endif static int e100_up(struct nic *nic) { @@ -2715,34 +2713,32 @@ static void __devexit e100_remove(struct pci_dev *pdev) } } +#ifdef CONFIG_PM static int e100_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); - if (netif_running(netdev)) - e100_down(nic); - e100_hw_reset(nic); - netif_device_detach(netdev); + netif_poll_disable(nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); -#ifdef CONFIG_PM pci_save_state(pdev); - if (nic->flags & (wol_magic | e100_asf(nic))) -#else - if (nic->flags & (wol_magic)) -#endif - pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); - else - /* disable PME */ - pci_enable_wake(pdev, 0, 0); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pci_set_power_state(pdev, PCI_D3hot); return 0; } -#ifdef CONFIG_PM static int e100_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -2764,7 +2760,23 @@ static int e100_resume(struct pci_dev *pdev) static void e100_shutdown(struct pci_dev *pdev) { - e100_suspend(pdev, PMSG_SUSPEND); + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + netif_poll_disable(nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); } /* ------------------ PCI Error Recovery infrastructure -------------- */ @@ -2848,9 +2860,9 @@ static struct pci_driver e100_driver = { .id_table = e100_id_table, .probe = e100_probe, .remove = __devexit_p(e100_remove), +#ifdef CONFIG_PM /* Power Management hooks */ .suspend = e100_suspend, -#ifdef CONFIG_PM .resume = e100_resume, #endif .shutdown = e100_shutdown, -- GitLab From fb5527e68d495650a7658fec9a7246bf922db212 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Thu, 19 Oct 2006 23:28:13 -0700 Subject: [PATCH 1537/1619] [PATCH] direct-io: sync and invalidate file region when falling back to buffered write When direct-io falls back to buffered write, it will just leave the dirty data floating about in pagecache, pending regular writeback. But normal direct-io semantics are that IO is synchronous, and that it leaves no pagecache behind. So change the fallback-to-buffered-write code to sync the file region and to then strip away the pagecache, just as a regular direct-io write would do. Acked-by: Jeff Moyer Cc: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/filemap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 3464b681f84..57faa8d1209 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2222,7 +2222,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { struct file *file = iocb->ki_filp; - const struct address_space * mapping = file->f_mapping; + struct address_space * mapping = file->f_mapping; size_t ocount; /* original count */ size_t count; /* after file limit checks */ struct inode *inode = mapping->host; @@ -2275,8 +2275,11 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (unlikely(file->f_flags & O_DIRECT)) { - written = generic_file_direct_write(iocb, iov, - &nr_segs, pos, ppos, count, ocount); + loff_t endbyte; + ssize_t written_buffered; + + written = generic_file_direct_write(iocb, iov, &nr_segs, pos, + ppos, count, ocount); if (written < 0 || written == count) goto out; /* @@ -2285,10 +2288,46 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, */ pos += written; count -= written; - } + written_buffered = generic_file_buffered_write(iocb, iov, + nr_segs, pos, ppos, count, + written); + /* + * If generic_file_buffered_write() retuned a synchronous error + * then we want to return the number of bytes which were + * direct-written, or the error code if that was zero. Note + * that this differs from normal direct-io semantics, which + * will return -EFOO even if some bytes were written. + */ + if (written_buffered < 0) { + err = written_buffered; + goto out; + } - written = generic_file_buffered_write(iocb, iov, nr_segs, - pos, ppos, count, written); + /* + * We need to ensure that the page cache pages are written to + * disk and invalidated to preserve the expected O_DIRECT + * semantics. + */ + endbyte = pos + written_buffered - written - 1; + err = do_sync_file_range(file, pos, endbyte, + SYNC_FILE_RANGE_WAIT_BEFORE| + SYNC_FILE_RANGE_WRITE| + SYNC_FILE_RANGE_WAIT_AFTER); + if (err == 0) { + written = written_buffered; + invalidate_mapping_pages(mapping, + pos >> PAGE_CACHE_SHIFT, + endbyte >> PAGE_CACHE_SHIFT); + } else { + /* + * We don't know how much we wrote, so just return + * the number of bytes which were direct-written + */ + } + } else { + written = generic_file_buffered_write(iocb, iov, nr_segs, + pos, ppos, count, written); + } out: current->backing_dev_info = NULL; return written ? written : err; -- GitLab From 26da82058e62ea173559a26881b16d10089645ba Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 19 Oct 2006 23:28:14 -0700 Subject: [PATCH 1538/1619] [PATCH] ecryptfs: use special_file() Use the special_file() macro to check whether an inode is special instead of open-coding it. Acked-by: Mike Halcrow Cc: Phillip Hellewell Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 7a11b8ae664..5938a232d11 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -104,10 +104,7 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, inode->i_op = &ecryptfs_dir_iops; if (S_ISDIR(lower_inode->i_mode)) inode->i_fop = &ecryptfs_dir_fops; - /* TODO: Is there a better way to identify if the inode is - * special? */ - if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || - S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) + if (special_file(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); dentry->d_op = &ecryptfs_dops; -- GitLab From 79e2de4bc53d7ca2a8eedee49e4a92479b4b530e Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Thu, 19 Oct 2006 23:28:15 -0700 Subject: [PATCH 1539/1619] [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(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c847e17e5ca..132a858ce2c 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 d370d2cfe13..9575e3a5ff2 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); -- GitLab From 3fcfab16c5b86eaa3db3a9a31adba550c5b67141 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Oct 2006 23:28:16 -0700 Subject: [PATCH 1540/1619] [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 diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 258df6b4d7d..d22cfc9d656 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 132a858ce2c..136066583c6 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 655d816760e..a625576fdee 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 f4b8f8b3fbd..8337451e789 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 f6675d2c386..ca92ac36fe9 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 ad8cbc49883..85ce2326830 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 d5973758981..004baf60061 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 9bbadafdcb0..db5f5a3608c 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 f7a1390d67f..7011d625559 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 9575e3a5ff2..7bfcde2d557 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 a341c803286..fc35e6bdfb9 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 12b3a4eee88..f3c077eb0b8 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 00000000000..f50a2811f9d --- /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 a0f33905744..8d9b19f239c 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 40db96a655d..afee38f04d8 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 b378f66cf2f..4959535fc14 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 af73c14f9d8..f05527bf792 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; -- GitLab From 34e856e6a522a8fc0feba7497f5b05aeaa13d473 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 Oct 2006 23:28:17 -0700 Subject: [PATCH 1541/1619] [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(+) diff --git a/include/linux/personality.h b/include/linux/personality.h index 80d780e5a8f..bf4cf2080e5 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 */ -- GitLab From 1a3e9ad163b77a3c7504f58f2780b5a62238c0ac Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 19 Oct 2006 23:28:18 -0700 Subject: [PATCH 1542/1619] [PATCH] uml: MODE_TT is bust arch/um/sys-x86_64/ptrace.c:20:1: warning: "SC_SS" redefined In file included from arch/um/include/sysdep/ptrace.h:18, from include/asm/ptrace-generic.h:12, from include/asm/ptrace.h:15, from arch/um/sys-x86_64/ptrace.c:8: arch/um/include/sysdep/sc.h:38:1: warning: this is the location of the previous definition arch/um/sys-x86_64/ptrace.c: In function 'putreg': arch/um/sys-x86_64/ptrace.c:63: warning: implicit declaration of function 'SC_FS_BASE' arch/um/sys-x86_64/ptrace.c:63: error: invalid lvalue in unary '&' arch/um/sys-x86_64/ptrace.c:63: warning: implicit declaration of function 'SC_GS_BASE' arch/um/sys-x86_64/ptrace.c:63: error: invalid lvalue in unary '&' arch/um/sys-x86_64/ptrace.c: In function 'getreg': arch/um/sys-x86_64/ptrace.c:101: error: invalid lvalue in unary '&' arch/um/sys-x86_64/ptrace.c:101: error: invalid lvalue in unary '&' I'd have to say that the fix for this, for now, is this: Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 78fb619bdb7..50fb89e3d95 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -52,6 +52,7 @@ menu "UML-specific options" config MODE_TT bool "Tracing thread support (DEPRECATED)" default n + depends on BROKEN help This option controls whether tracing thread support is compiled into UML. This option is largely obsolete, given that skas0 provides -- GitLab From 3fda982c501c6a8baa3fa79aaea1bfa7bb2a5def Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:19 -0700 Subject: [PATCH 1543/1619] [PATCH] fix typo in memory barrier docs Fix cut'n'paste typo - &a and &b are used in other examples, in this one the doc uses &u and &v. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/memory-barriers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 994355b0cd1..7f790f66ec6 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1898,7 +1898,7 @@ queue before processing any further requests: smp_wmb(); - p = &b; q = p; + p = &v; q = p; -- GitLab From 02a5323d8060d7259277e9e2936fd02129dc0984 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:20 -0700 Subject: [PATCH 1544/1619] [PATCH] uml: remove some leftover PPC code I happened to notice that this code is a leftover and it should be removed - since there are sporadical efforts to revive the PPC port doing such cleanups is not useless. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-um/archparam-ppc.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/asm-um/archparam-ppc.h b/include/asm-um/archparam-ppc.h index 172cd6ffacc..4269d8a37b4 100644 --- a/include/asm-um/archparam-ppc.h +++ b/include/asm-um/archparam-ppc.h @@ -1,15 +1,6 @@ #ifndef __UM_ARCHPARAM_PPC_H #define __UM_ARCHPARAM_PPC_H -/********* Bits for asm-um/hw_irq.h **********/ - -struct hw_interrupt_type; - -/********* Bits for asm-um/hardirq.h **********/ - -#define irq_enter(cpu, irq) hardirq_enter(cpu) -#define irq_exit(cpu, irq) hardirq_exit(cpu) - /********* Bits for asm-um/string.h **********/ #define __HAVE_ARCH_STRRCHR -- GitLab From c13e569073b89eb75216a2551e89ae93ad1f9951 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:20 -0700 Subject: [PATCH 1545/1619] [PATCH] uml: split memory allocation prototypes out of user.h user.h is too generic a header name. I've split out allocation routines from it. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/cow_sys.h | 1 + arch/um/drivers/daemon_user.c | 1 + arch/um/drivers/fd.c | 1 + arch/um/drivers/mcast_user.c | 1 + arch/um/drivers/net_user.c | 1 + arch/um/drivers/pcap_user.c | 1 + arch/um/drivers/port_user.c | 1 + arch/um/drivers/pty.c | 1 + arch/um/drivers/slip_user.c | 1 + arch/um/drivers/tty.c | 1 + arch/um/include/um_malloc.h | 17 +++++++++++++++++ arch/um/include/user.h | 6 ------ arch/um/include/user_util.h | 1 - arch/um/kernel/irq.c | 1 + arch/um/kernel/process.c | 1 + arch/um/os-Linux/drivers/ethertap_user.c | 1 + arch/um/os-Linux/irq.c | 1 + arch/um/os-Linux/main.c | 1 + arch/um/os-Linux/sigio.c | 1 + 19 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 arch/um/include/um_malloc.h diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index 7a5b4afde69..c6a308464ac 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h @@ -5,6 +5,7 @@ #include "user_util.h" #include "os.h" #include "user.h" +#include "um_malloc.h" static inline void *cow_malloc(int size) { diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index 77954ea7704..310af0f1e49 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -17,6 +17,7 @@ #include "user_util.h" #include "user.h" #include "os.h" +#include "um_malloc.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index 108b7dafbd0..218aa0e9b79 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -12,6 +12,7 @@ #include "user_util.h" #include "chan_user.h" #include "os.h" +#include "um_malloc.h" struct fd_chan { int fd; diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index 4d2bd39a85b..8138f5ea1bf 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -23,6 +23,7 @@ #include "user_util.h" #include "user.h" #include "os.h" +#include "um_malloc.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index f3a3f8a29c7..0ffd7ac295d 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -18,6 +18,7 @@ #include "kern_util.h" #include "net_user.h" #include "os.h" +#include "um_malloc.h" int tap_open_common(void *dev, char *gate_addr) { diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c index 2ef641ded96..11921a7baa7 100644 --- a/arch/um/drivers/pcap_user.c +++ b/arch/um/drivers/pcap_user.c @@ -12,6 +12,7 @@ #include "net_user.h" #include "pcap_user.h" #include "user.h" +#include "um_malloc.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index f2e8fc42ecc..bc6afaf74c1 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -19,6 +19,7 @@ #include "chan_user.h" #include "port.h" #include "os.h" +#include "um_malloc.h" struct port_chan { int raw; diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index abec620e838..829a5eca8c0 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -13,6 +13,7 @@ #include "user_util.h" #include "kern_util.h" #include "os.h" +#include "um_malloc.h" struct pty_chan { void (*announce)(char *dev_name, int dev); diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 8460285c69a..7eddacc53b6 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -15,6 +15,7 @@ #include "slip.h" #include "slip_common.h" #include "os.h" +#include "um_malloc.h" void slip_user_init(void *data, void *dev) { diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index 11de3ac1eb5..d95d64309ea 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -11,6 +11,7 @@ #include "user_util.h" #include "user.h" #include "os.h" +#include "um_malloc.h" struct tty_chan { char *dev; diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h new file mode 100644 index 00000000000..0363a9b53f8 --- /dev/null +++ b/arch/um/include/um_malloc.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso + * Licensed under the GPL + */ + +#ifndef __UM_MALLOC_H__ +#define __UM_MALLOC_H__ + +extern void *um_kmalloc(int size); +extern void *um_kmalloc_atomic(int size); +extern void kfree(const void *ptr); + +extern void *um_vmalloc(int size); +extern void *um_vmalloc_atomic(int size); +extern void vfree(void *ptr); + +#endif /* __UM_MALLOC_H__ */ diff --git a/arch/um/include/user.h b/arch/um/include/user.h index 39f8c880107..acadce3f271 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h @@ -11,17 +11,11 @@ extern void panic(const char *fmt, ...) extern int printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void schedule(void); -extern void *um_kmalloc(int size); -extern void *um_kmalloc_atomic(int size); -extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); /* These use size_t, however unsigned long is correct on both i386 and x86_64. */ extern unsigned long strlcpy(char *, const char *, unsigned long); extern unsigned long strlcat(char *, const char *, unsigned long); -extern void *um_vmalloc(int size); -extern void *um_vmalloc_atomic(int size); -extern void vfree(void *ptr); #endif diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 802d7842514..06625fefef3 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -52,7 +52,6 @@ extern int linux_main(int argc, char **argv); extern void set_cmdline(char *cmd); extern void input_cb(void (*proc)(void *), void *arg, int arg_len); extern int get_pty(void); -extern void *um_kmalloc(int size); extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...) diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index ef259569fd8..5c1e611f628 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -31,6 +31,7 @@ #include "irq_kern.h" #include "os.h" #include "sigio.h" +#include "um_malloc.h" #include "misc_constants.h" /* diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index fe6c64abda5..348b272bb76 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -46,6 +46,7 @@ #include "mode.h" #include "mode_kern.h" #include "choose-mode.h" +#include "um_malloc.h" /* This is a per-cpu array. A processor only modifies its entry and it only * cares about its entry, so it's OK if another processor is modifying its diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index f559bdf746e..863981ba146 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -20,6 +20,7 @@ #include "net_user.h" #include "etap.h" #include "os.h" +#include "um_malloc.h" #define MAX_PACKET ETH_MAX_PACKET diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index a97206df5b5..d46b818c131 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -18,6 +18,7 @@ #include "sigio.h" #include "irq_user.h" #include "os.h" +#include "um_malloc.h" static struct pollfd *pollfds = NULL; static int pollfds_num = 0; diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index d1c5670787d..685feaab65d 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -23,6 +23,7 @@ #include "choose-mode.h" #include "uml-config.h" #include "os.h" +#include "um_malloc.h" /* Set in set_stklim, which is called from main and __wrap_malloc. * __wrap_malloc only calls it if main hasn't started. diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index f6457765b17..925a65240cf 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -19,6 +19,7 @@ #include "user_util.h" #include "sigio.h" #include "os.h" +#include "um_malloc.h" /* Protected by sigio_lock(), also used by sigio_cleanup, which is an * exitcall. -- GitLab From 8b028bcd0e746ae0f2f218b911032232a32dedd5 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:21 -0700 Subject: [PATCH 1546/1619] [PATCH] uml: code convention cleanup of a file Fix coding conventions violations is arch/um/os-Linux/helper.c. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/helper.c | 53 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index cd15b9df5b5..8a78bf03b46 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -35,18 +35,18 @@ static int helper_child(void *arg) char **argv = data->argv; int errval; - if(helper_pause){ + if (helper_pause){ signal(SIGHUP, helper_hup); pause(); } - if(data->pre_exec != NULL) + if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); errval = -errno; printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno); os_write_file(data->fd, &errval, sizeof(errval)); kill(os_getpid(), SIGKILL); - return(0); + return 0; } /* Returns either the pid of the child process we run or -E* on failure. @@ -58,20 +58,21 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, unsigned long stack, sp; int pid, fds[2], ret, n; - if((stack_out != NULL) && (*stack_out != 0)) + if ((stack_out != NULL) && (*stack_out != 0)) stack = *stack_out; - else stack = alloc_stack(0, __cant_sleep()); - if(stack == 0) + else + stack = alloc_stack(0, __cant_sleep()); + if (stack == 0) return -ENOMEM; ret = os_pipe(fds, 1, 0); - if(ret < 0){ + if (ret < 0) { printk("run_helper : pipe failed, ret = %d\n", -ret); goto out_free; } ret = os_set_exec_close(fds[1], 1); - if(ret < 0){ + if (ret < 0) { printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n", -ret); goto out_close; @@ -83,7 +84,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, data.argv = argv; data.fd = fds[1]; pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); - if(pid < 0){ + if (pid < 0) { ret = -errno; printk("run_helper : clone failed, errno = %d\n", errno); goto out_close; @@ -95,10 +96,10 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, /* Read the errno value from the child, if the exec failed, or get 0 if * the exec succeeded because the pipe fd was set as close-on-exec. */ n = os_read_file(fds[0], &ret, sizeof(ret)); - if(n == 0) + if (n == 0) { ret = pid; - else { - if(n < 0){ + } else { + if (n < 0) { printk("run_helper : read on pipe failed, ret = %d\n", -n); ret = n; @@ -112,10 +113,11 @@ out_close: close(fds[1]); close(fds[0]); out_free: - if(stack_out == NULL) + if (stack_out == NULL) free_stack(stack, 0); - else *stack_out = stack; - return(ret); + else + *stack_out = stack; + return ret; } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, @@ -125,31 +127,32 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, int pid, status, err; stack = alloc_stack(stack_order, __cant_sleep()); - if(stack == 0) return(-ENOMEM); + if (stack == 0) + return -ENOMEM; sp = stack + (page_size() << stack_order) - sizeof(void *); pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); - if(pid < 0){ + if (pid < 0) { err = -errno; printk("run_helper_thread : clone failed, errno = %d\n", errno); return err; } - if(stack_out == NULL){ + if (stack_out == NULL) { CATCH_EINTR(pid = waitpid(pid, &status, 0)); - if(pid < 0){ + if (pid < 0) { err = -errno; printk("run_helper_thread - wait failed, errno = %d\n", errno); pid = err; } - if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) + if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " "0x%x\n", status); free_stack(stack, stack_order); - } - else *stack_out = stack; - return(pid); + } else + *stack_out = stack; + return pid; } int helper_wait(int pid) @@ -157,9 +160,9 @@ int helper_wait(int pid) int ret; CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); - if(ret < 0){ + if (ret < 0) { ret = -errno; printk("helper_wait : waitpid failed, errno = %d\n", errno); } - return(ret); + return ret; } -- GitLab From 493e3758be1d5628b4d799fe21d68969edbe32aa Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:22 -0700 Subject: [PATCH 1547/1619] [PATCH] uml: reenable compilation of enable_timer, disabled by mistake CONFIG_MODE_TT does not work there, the UML_ prefixed version must be used - this causes a link-time failure when CONFIG_MODE_TT is enabled (i.e. always here, never by Jeff). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 38be096e750..2115b8beb54 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -16,6 +16,7 @@ #include "process.h" #include "kern_constants.h" #include "os.h" +#include "uml-config.h" int set_interval(int is_virtual) { @@ -30,7 +31,7 @@ int set_interval(int is_virtual) return 0; } -#ifdef CONFIG_MODE_TT +#ifdef UML_CONFIG_MODE_TT void enable_timer(void) { set_interval(1); -- GitLab From b2670eacfb013169b8bf151a5078a9ef8ef86466 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:23 -0700 Subject: [PATCH 1548/1619] [PATCH] uml: use DEFCONFIG_LIST to avoid reading host's config This should make sure that, for UML, host's configuration files are not considered, which avoids various pains to the user. Our dependency are such that the obtained Kconfig will be valid and will lead to successful compilation - however they cannot prevent an user from disabling any boot device, and if an option is not set in the read .config (say /boot/config-XXX), with make menuconfig ARCH=um, it is not set. This always disables UBD and all console I/O channels, which leads to non-working UML kernels, so this bothers users - especially now, since it will happen on almost every machine (/boot/config-`uname -r` exists almost on every machine). It can be workarounded with make defconfig ARCH=um, but it is non-obvious and can be avoided, so please _do_ merge this patch. Given the existence of options, it could be interesting to implement (additionally) "option required" - with it, Kconfig will refuse reading a .config file (from wherever it comes) if the given option is not set. With this, one could mark with it the option characteristic of the given architecture (it was an old proposal of Roman Zippel, when I pointed out our problem): config UML option required default y However this should be further discussed: *) for x86, it must support constructs like: ==arch/i386/Kconfig== config 64BIT option required default n where Kconfig must require that CONFIG_64BIT is disabled or not present in the read .config. *) do we want to do such checks only for the starting defconfig or also for .config? Which leads to: *) I may want to port a x86_64 .config to x86 and viceversa, or even among more different archs. Should that be allowed, and in which measure (the user may force skipping the check for a .config or it is only given a warning by default)? Cc: Roman Zippel Cc: Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig | 5 +++++ init/Kconfig | 1 + 2 files changed, 6 insertions(+) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 50fb89e3d95..5ac1f2963ae 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -1,3 +1,8 @@ +config DEFCONFIG_LIST + string + option defconfig_list + default "arch/$ARCH/defconfig" + # UML uses the generic IRQ sugsystem config GENERIC_HARDIRQS bool diff --git a/init/Kconfig b/init/Kconfig index 10382931eea..c8b2624af17 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1,5 +1,6 @@ config DEFCONFIG_LIST string + depends on !UML option defconfig_list default "/lib/modules/$UNAME_RELEASE/.config" default "/etc/kernel-config" -- GitLab From d9d645f06a8f50659bbae2be64ed8367ba068fc0 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:24 -0700 Subject: [PATCH 1549/1619] [PATCH] uml: cleanup run_helper() API to fix a leak Freeing the stack is left uselessly to the caller of run_helper in some cases - this is taken from run_helper_thread, but here it is useless, so no caller needs it and the only place where this happens has a potential leak - in case of error neither run_helper() nor xterm_open() call free_stack(). At this point passing a pointer is not needed - the stack pointer should be passed directly, but this change is not done here. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/xterm.c | 2 -- arch/um/os-Linux/helper.c | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 386f8b95298..850221d9b4c 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -136,8 +136,6 @@ int xterm_open(int input, int output, int primary, void *d, return(pid); } - if(data->stack == 0) free_stack(stack, 0); - if (data->direct_rcv) { new = os_rcv_fd(fd, &data->helper_pid); } else { diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 8a78bf03b46..d13299cfa31 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -50,7 +50,8 @@ static int helper_child(void *arg) } /* Returns either the pid of the child process we run or -E* on failure. - * XXX The alloc_stack here breaks if this is called in the tracing thread */ + * XXX The alloc_stack here breaks if this is called in the tracing thread, so + * we need to receive a preallocated stack (a local buffer is ok). */ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, unsigned long *stack_out) { @@ -113,10 +114,8 @@ out_close: close(fds[1]); close(fds[0]); out_free: - if (stack_out == NULL) + if ((stack_out == NULL) || (*stack_out == 0)) free_stack(stack, 0); - else - *stack_out = stack; return ret; } -- GitLab From f43e6a5a72566675da3581dc0d7076042e6701f7 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:25 -0700 Subject: [PATCH 1550/1619] [PATCH] uml: kconfig - silence warning Silence useless warning about undefined symbol in Kconfig. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig.char | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char index 62d87b71179..e03e40c7aac 100644 --- a/arch/um/Kconfig.char +++ b/arch/um/Kconfig.char @@ -190,6 +190,11 @@ config HOSTAUDIO tristate default UML_SOUND +#It is selected elsewhere, so kconfig would warn without this. +config HW_RANDOM + tristate + default n + config UML_RANDOM tristate "Hardware random number generator" help -- GitLab From 1ba0ce6f9c19a8573832e14b418dc835dc6f3bbd Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Thu, 19 Oct 2006 23:28:26 -0700 Subject: [PATCH 1551/1619] [PATCH] uml: mmapper - remove just added but wrong "const" attribute When enabling the mmapper driver I got warnings because this "const" miscdevice structure is passed to function as non-const pointer; unlike struct tty_operations, however, I verified that misc_{de,}register _do_ modify their parameter, so this const attribute must be removed. Since the purpose of the change was to guarantee that no lock was needed, add a comment to prove this differently. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/mmapper_kern.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index 9a3b5daf625..df3516e47d4 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -95,7 +95,8 @@ static const struct file_operations mmapper_fops = { .release = mmapper_release, }; -static const struct miscdevice mmapper_dev = { +/* No locking needed - only used (and modified) by below initcall and exitcall. */ +static struct miscdevice mmapper_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "mmapper", .fops = &mmapper_fops -- GitLab From 74e8b51d254865b8abe4a94b5eb82b1940ec820c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 Oct 2006 23:28:26 -0700 Subject: [PATCH 1552/1619] [PATCH] Kconfig serial typos Fix typo (repeated) in serial Kconfig. Signed-off-by: Randy Dunlap Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b0d502622d9..0b71e7d1890 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -767,37 +767,37 @@ config SERIAL_CPM_SCC1 bool "Support for SCC1 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC1 as a serial port + Select this option to use SCC1 as a serial port config SERIAL_CPM_SCC2 bool "Support for SCC2 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC2 as a serial port + Select this option to use SCC2 as a serial port config SERIAL_CPM_SCC3 bool "Support for SCC3 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC3 as a serial port + Select this option to use SCC3 as a serial port config SERIAL_CPM_SCC4 bool "Support for SCC4 serial port" depends on SERIAL_CPM=y help - Select the is option to use SCC4 as a serial port + Select this option to use SCC4 as a serial port config SERIAL_CPM_SMC1 bool "Support for SMC1 serial port" depends on SERIAL_CPM=y help - Select the is option to use SMC1 as a serial port + Select this option to use SMC1 as a serial port config SERIAL_CPM_SMC2 bool "Support for SMC2 serial port" depends on SERIAL_CPM=y help - Select the is option to use SMC2 as a serial port + Select this option to use SMC2 as a serial port config SERIAL_SGI_L1_CONSOLE bool "SGI Altix L1 serial console support" -- GitLab From c5a114f1fb2d3c54be62779a705e088471063b47 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 19 Oct 2006 23:28:28 -0700 Subject: [PATCH 1553/1619] [PATCH] fix "ACPI: Processor native C-states using MWAIT" This patch breaks C-state discovery on my IBM IntelliStation Z30 because the return value of acpi_processor_get_power_info_fadt is not assigned to "result" in the case that acpi_processor_get_power_info_cst returns -ENODEV. Thus, if ACPI provides C-state data via the FADT and not _CST (as is the case on this machine), we incorrectly exit the function with -ENODEV after reading the FADT. The attached patch sets the value of result so that we don't exit early. Signed-off-by: Darrick J. Wong Acked-by: "Pallipadi, Venkatesh" Acked-by: "Brown, Len" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/processor_idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index e67144cf3c8..65b3f056ad8 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -962,7 +962,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) result = acpi_processor_get_power_info_cst(pr); if (result == -ENODEV) - acpi_processor_get_power_info_fadt(pr); + result = acpi_processor_get_power_info_fadt(pr); if (result) return result; -- GitLab From 145fc655a1ceabda76cf2ad74f7cf96863c65b65 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 19 Oct 2006 23:28:28 -0700 Subject: [PATCH 1554/1619] [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(+) diff --git a/include/linux/irq.h b/include/linux/irq.h index 775f5a7da49..52fc4052a0a 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); -- GitLab From 91fcdd4e0314145d7d4fa52dba2f9c2da25346fd Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 19 Oct 2006 23:28:29 -0700 Subject: [PATCH 1555/1619] [PATCH] readjust comments of task_timeslice for kernel doc Signed-off-by: Borislav Petkov Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 094b5687eef..3399701c680 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -160,15 +160,6 @@ #define TASK_PREEMPTS_CURR(p, rq) \ ((p)->prio < (rq)->curr->prio) -/* - * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ] - * to time slice values: [800ms ... 100ms ... 5ms] - * - * The higher a thread's priority, the bigger timeslices - * it gets during one round of execution. But even the lowest - * priority thread gets MIN_TIMESLICE worth of execution time. - */ - #define SCALE_PRIO(x, prio) \ max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE) @@ -180,6 +171,15 @@ static unsigned int static_prio_timeslice(int static_prio) return SCALE_PRIO(DEF_TIMESLICE, static_prio); } +/* + * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ] + * to time slice values: [800ms ... 100ms ... 5ms] + * + * The higher a thread's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority thread gets MIN_TIMESLICE worth of execution time. + */ + static inline unsigned int task_timeslice(struct task_struct *p) { return static_prio_timeslice(p->static_prio); -- GitLab From 6cbe44cd8d48a92856295f445183f52bf42a544d Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Thu, 19 Oct 2006 23:28:30 -0700 Subject: [PATCH 1556/1619] [PATCH] Change log level of a message of acpi_memhotplug to KERN_DEBUG I suppose this message seems quite useless except debugging. It just shows "Hotplug Mem Device". System admin can't know anything by this message. So, I would like to change it to KERN_DEBUG. Signed-off-by: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/acpi_memhotplug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 98099de59b4..9090b5acc5e 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -414,7 +414,7 @@ static int acpi_memory_device_add(struct acpi_device *device) /* Set the device state */ mem_device->state = MEMORY_POWER_ON_STATE; - printk(KERN_INFO "%s \n", acpi_device_name(device)); + printk(KERN_DEBUG "%s \n", acpi_device_name(device)); return result; } -- GitLab From 887b95931b4072e60e3bf4253ff7bffe372bca46 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Thu, 19 Oct 2006 23:28:31 -0700 Subject: [PATCH 1557/1619] [PATCH] acpi memory hotplug: remove strange add_memory fail message I wrote a patch to avoid redundant memory hot-add call at boot time. This was cause of strange fail message of memory hotplug like "ACPI: add_memory failed". Memory is recognized by early boot code with EFI/E820. But, if DSDT describes memory devices for them, then hot-add code is called for already recognized memory, and it shows fail messages with -EEXIST. So, sys admin will misunderstand this message as something wrong by it. This patch avoids them by preventing redundant hot-add call until completion of driver initialization. [akpm@osdl.org: cleanups] Signed-off-by: Yasunori Goto Cc: "Brown, Len" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/acpi_memhotplug.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 9090b5acc5e..6bcd9e8e7bc 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -85,6 +85,8 @@ struct acpi_memory_device { struct list_head res_list; }; +static int acpi_hotmem_initialized; + static acpi_status acpi_memory_get_resource(struct acpi_resource *resource, void *context) { @@ -438,6 +440,15 @@ static int acpi_memory_device_start (struct acpi_device *device) struct acpi_memory_device *mem_device; int result = 0; + /* + * Early boot code has recognized memory area by EFI/E820. + * If DSDT shows these memory devices on boot, hotplug is not necessary + * for them. So, it just returns until completion of this driver's + * start up. + */ + if (!acpi_hotmem_initialized) + return 0; + mem_device = acpi_driver_data(device); if (!acpi_memory_check_device(mem_device)) { @@ -537,6 +548,7 @@ static int __init acpi_memory_device_init(void) return -ENODEV; } + acpi_hotmem_initialized = 1; return 0; } -- GitLab From 8ac773b4f73afa6fd66695131103944b975d5d5c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 19 Oct 2006 23:28:32 -0700 Subject: [PATCH 1558/1619] [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 diff --git a/fs/proc/base.c b/fs/proc/base.c index 26a8f8416b7..8df27401d29 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 5114ff18101..a1155a2beb3 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 5a6068ff555..d538de90196 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 00000000000..ad76463629a --- /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 20f41b082e1..2e3ce3a928b 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 -- GitLab From a31baca58cc16fe0584685f54c6d17494a231c92 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 19 Oct 2006 23:28:33 -0700 Subject: [PATCH 1559/1619] [PATCH] irq updates: make eata_pio compile Signed-off-by: Alan Cox Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/eata_pio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 811d8840707..2dbb66d2f0a 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -203,7 +203,7 @@ static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id) irqreturn_t ret; spin_lock_irqsave(dev->host_lock, flags); - ret = eata_pio_int_handler(irq, dev_id, regs); + ret = eata_pio_int_handler(irq, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return ret; } -- GitLab From 8c7c7c9bf39470c9689ad43cae3142cf948f4cfb Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 Oct 2006 23:28:34 -0700 Subject: [PATCH 1560/1619] [PATCH] Fix warnings for WARN_ON if CONFIG_BUG is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In most cases the return value of WARN_ON() is ignored. If the generic definition for the !CONFIG_BUG case is used this will result in a warning: CC kernel/sched.o In file included from include/linux/bio.h:25, from include/linux/blkdev.h:14, from kernel/sched.c:39: include/linux/ioprio.h: In function ‘task_ioprio’: include/linux/ioprio.h:50: warning: statement with no effect kernel/sched.c: In function ‘context_switch’: kernel/sched.c:1834: warning: statement with no effect Signed-off-by: Ralf Baechle Cc: Jeremy Fitzhardinge Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/bug.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index 1d9573cf4a0..c92ae0f166f 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -37,7 +37,10 @@ #endif #ifndef HAVE_ARCH_WARN_ON -#define WARN_ON(condition) unlikely((condition)) +#define WARN_ON(condition) ({ \ + typeof(condition) __ret_warn_on = (condition); \ + unlikely(__ret_warn_on); \ +}) #endif #endif -- GitLab From d6f8ff7381501887233666b508b9eac70143303d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 Oct 2006 23:28:34 -0700 Subject: [PATCH 1561/1619] [PATCH] cad_pid sysctl with PROC_FS=n If CONFIG_PROC_FS=n: kernel/sysctl.c:148: warning: 'proc_do_cad_pid' used but never defined kernel/built-in.o:(.data+0x1228): undefined reference to `proc_do_cad_pid' make: *** [.tmp_vmlinux1] Error 1 Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sysctl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8020fb273c4..8bff2c18fb5 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -136,8 +136,10 @@ 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); +#ifdef CONFIG_PROC_SYSCTL static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos); +#endif static ctl_table root_table[]; static struct ctl_table_header root_table_header = @@ -542,6 +544,7 @@ static ctl_table kern_table[] = { .proc_handler = &proc_dointvec, }, #endif +#ifdef CONFIG_PROC_SYSCTL { .ctl_name = KERN_CADPID, .procname = "cad_pid", @@ -550,6 +553,7 @@ static ctl_table kern_table[] = { .mode = 0600, .proc_handler = &proc_do_cad_pid, }, +#endif { .ctl_name = KERN_MAX_THREADS, .procname = "threads-max", -- GitLab From f2fbc6c2dad7bbcbf226c094749534f1e84d3be2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 Oct 2006 23:28:35 -0700 Subject: [PATCH 1562/1619] [PATCH] fs/Kconfig: move GENERIC_ACL, fix acl() call errors GENERIC_ACL shouldn't be under Network File Systems (which made it depend on NET) as far as I can tell. Having it there and having many (FS) config symbols disabled gives this (which the patch fixes): mm/built-in.o: In function `shmem_check_acl': shmem_acl.c:(.text.shmem_check_acl+0x33): undefined reference to `posix_acl_permission' fs/built-in.o: In function `generic_acl_get': (.text.generic_acl_get+0x30): undefined reference to `posix_acl_to_xattr' fs/built-in.o: In function `generic_acl_set': (.text.generic_acl_set+0x75): undefined reference to `posix_acl_from_xattr' fs/built-in.o: In function `generic_acl_set': (.text.generic_acl_set+0x94): undefined reference to `posix_acl_valid' fs/built-in.o: In function `generic_acl_set': (.text.generic_acl_set+0xc1): undefined reference to `posix_acl_equiv_mode' fs/built-in.o: In function `generic_acl_init': (.text.generic_acl_init+0x7a): undefined reference to `posix_acl_clone' fs/built-in.o: In function `generic_acl_init': (.text.generic_acl_init+0xb4): undefined reference to `posix_acl_clone' fs/built-in.o: In function `generic_acl_init': (.text.generic_acl_init+0xc8): undefined reference to `posix_acl_create_masq' fs/built-in.o: In function `generic_acl_chmod': (.text.generic_acl_chmod+0x49): undefined reference to `posix_acl_clone' fs/built-in.o: In function `generic_acl_chmod': (.text.generic_acl_chmod+0x76): undefined reference to `posix_acl_chmod_masq' Signed-off-by: Randy Dunlap Acked-by: Andreas Gruenbacher Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/Kconfig b/fs/Kconfig index 6a3df055280..fee318e6f4b 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -634,6 +634,10 @@ 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. +config GENERIC_ACL + bool + select FS_POSIX_ACL + if BLOCK menu "CD-ROM/DVD Filesystems" @@ -2080,10 +2084,6 @@ config 9P_FS If unsure, say N. -config GENERIC_ACL - bool - select FS_POSIX_ACL - endmenu if BLOCK -- GitLab From 0e7d73824e6b0024100701da246fec769dd8f087 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 19 Oct 2006 23:28:36 -0700 Subject: [PATCH 1563/1619] [PATCH] autofs3: Make sure all dentries refs are released before calling kill_anon_super() Make sure all dentries refs are released before calling kill_anon_super() so that the assumption that generic_shutdown_super() can completely destroy the dentry tree for there will be no external references holds true. What was being done in the put_super() superblock op, is now done in the kill_sb() filesystem op instead, prior to calling kill_anon_super(). The call to shrink_dcache_sb() is removed as it is redundant since shrink_dcache_for_umount() will now be called after the cleanup routine. Signed-off-by: David Howells Acked-by: Ian Kent Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/autofs/autofs_i.h | 1 + fs/autofs/dirhash.c | 1 - fs/autofs/init.c | 2 +- fs/autofs/inode.c | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index c7700d9b3f9..906ba5ce226 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h @@ -149,6 +149,7 @@ extern const struct file_operations autofs_root_operations; /* Initializing function */ int autofs_fill_super(struct super_block *, void *, int); +void autofs_kill_sb(struct super_block *sb); /* Queue management functions */ diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index 3fded389d06..bf8c8af9800 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c @@ -246,5 +246,4 @@ void autofs_hash_nuke(struct autofs_sb_info *sbi) kfree(ent); } } - shrink_dcache_sb(sbi->sb); } diff --git a/fs/autofs/init.c b/fs/autofs/init.c index aca12375240..cea5219b4f3 100644 --- a/fs/autofs/init.c +++ b/fs/autofs/init.c @@ -24,7 +24,7 @@ static struct file_system_type autofs_fs_type = { .owner = THIS_MODULE, .name = "autofs", .get_sb = autofs_get_sb, - .kill_sb = kill_anon_super, + .kill_sb = autofs_kill_sb, }; static int __init init_autofs_fs(void) diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index 2c9759baad6..54c518c89e4 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -20,7 +20,7 @@ #include "autofs_i.h" #include -static void autofs_put_super(struct super_block *sb) +void autofs_kill_sb(struct super_block *sb) { struct autofs_sb_info *sbi = autofs_sbi(sb); unsigned int n; @@ -37,13 +37,13 @@ static void autofs_put_super(struct super_block *sb) kfree(sb->s_fs_info); DPRINTK(("autofs: shutting down\n")); + kill_anon_super(sb); } static void autofs_read_inode(struct inode *inode); static struct super_operations autofs_sops = { .read_inode = autofs_read_inode, - .put_super = autofs_put_super, .statfs = simple_statfs, }; -- GitLab From 575b5c7870c940326a11614e0279b74356c1d44f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:37 -0700 Subject: [PATCH 1564/1619] [PATCH] NFSv4: Fix thinko in fs/nfs/super.c Duh. addr.sin_port should be in network byte order. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 28659a919d6..28108c82b88 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -834,7 +834,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, } /* RFC3530: The default port for NFS is 2049 */ if (addr.sin_port == 0) - addr.sin_port = NFS_PORT; + addr.sin_port = htons(NFS_PORT); /* Grab the authentication type */ authflavour = RPC_AUTH_UNIX; -- GitLab From b6dff26a08189932eeb0fa4261e09e733b0fc540 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:38 -0700 Subject: [PATCH 1565/1619] [PATCH] NFS: Fix oops in nfs_cancel_commit_list Fix two bugs: - nfs_inode_remove_request will call nfs_clear_request, so we cannot reference req->wb_page after it. Move the call to dec_zone_page_state so that it occurs while req->wb_page is still valid. - Calling nfs_clear_page_writeback is unnecessary since the radix tree tags will have been cleared by the call to nfs_inode_remove_request. Replace with a simple call to nfs_unlock_request. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index ca92ac36fe9..883dd4a1c15 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -590,10 +590,10 @@ static void nfs_cancel_commit_list(struct list_head *head) while(!list_empty(head)) { req = nfs_list_entry(head->next); + dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); nfs_list_remove_request(req); nfs_inode_remove_request(req); - dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); - nfs_clear_page_writeback(req); + nfs_unlock_request(req); } } -- GitLab From eda3cef8dd2b83875affe82595db9d0c278879b2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:38 -0700 Subject: [PATCH 1566/1619] [PATCH] NFS: Fix error handling in nfs_direct_write_result() If the RPC call tanked, we should not be checking the return value of data->res.verf->committed, since it is unlikely to even be initialised. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/direct.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 9f7f8b9ea1e..1e873fcab94 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -532,10 +532,12 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) spin_lock(&dreq->lock); - if (likely(status >= 0)) - dreq->count += data->res.count; - else - dreq->error = task->tk_status; + if (unlikely(status < 0)) { + dreq->error = status; + goto out_unlock; + } + + dreq->count += data->res.count; if (data->res.verf->committed != NFS_FILE_SYNC) { switch (dreq->flags) { @@ -550,7 +552,7 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) } } } - +out_unlock: spin_unlock(&dreq->lock); } -- GitLab From 7d9ac06f26fe8d477c813405f1a8c7c90eecef2d Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 19 Oct 2006 23:28:39 -0700 Subject: [PATCH 1567/1619] [PATCH] nfs4: initialize cl_ipaddr David forgot to do this. I'm not sure if this is the right place to put it.... Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 34c3996bd0f..8b123f6a7d0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -849,6 +849,7 @@ error: */ static int nfs4_init_client(struct nfs_client *clp, int proto, int timeo, int retrans, + const char *ip_addr, rpc_authflavor_t authflavour) { int error; @@ -865,6 +866,7 @@ static int nfs4_init_client(struct nfs_client *clp, error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour); if (error < 0) goto error; + memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); error = nfs_idmap_new(clp); if (error < 0) { @@ -888,6 +890,7 @@ error: */ static int nfs4_set_client(struct nfs_server *server, const char *hostname, const struct sockaddr_in *addr, + const char *ip_addr, rpc_authflavor_t authflavour, int proto, int timeo, int retrans) { @@ -902,7 +905,7 @@ static int nfs4_set_client(struct nfs_server *server, error = PTR_ERR(clp); goto error; } - error = nfs4_init_client(clp, proto, timeo, retrans, authflavour); + error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour); if (error < 0) goto error_put; @@ -971,7 +974,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, return ERR_PTR(-ENOMEM); /* Get a client record */ - error = nfs4_set_client(server, hostname, addr, authflavour, + error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour, data->proto, data->timeo, data->retrans); if (error < 0) goto error; @@ -1041,6 +1044,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, /* Get a client representation. * Note: NFSv4 always uses TCP, */ error = nfs4_set_client(server, data->hostname, data->addr, + parent_client->cl_ipaddr, data->authflavor, parent_server->client->cl_xprt->prot, parent_client->retrans_timeo, -- GitLab From 13bbc06af8a5f65df0f888b442e557c617cadba7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:40 -0700 Subject: [PATCH 1568/1619] [PATCH] NFS: Fix NFSv4 callback regression The change in semantics for nfs_find_client() introduced by David breaks the NFSv4 callback channel. Also, replace another completely broken BUG_ON() in nfs_find_client(). In initialised clients, clp->cl_cons_state == 0, and callers of that function should in any case never want to see clients that are uninitialised. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/client.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8b123f6a7d0..5fea638743e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -232,11 +232,15 @@ void nfs_put_client(struct nfs_client *clp) * Find a client by address * - caller must hold nfs_client_lock */ -static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion) +static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port) { struct nfs_client *clp; list_for_each_entry(clp, &nfs_client_list, cl_share_link) { + /* Don't match clients that failed to initialise properly */ + if (clp->cl_cons_state < 0) + continue; + /* Different NFS versions cannot share the same nfs_client */ if (clp->cl_nfsversion != nfsversion) continue; @@ -245,7 +249,7 @@ static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int sizeof(clp->cl_addr.sin_addr)) != 0) continue; - if (clp->cl_addr.sin_port == addr->sin_port) + if (!match_port || clp->cl_addr.sin_port == addr->sin_port) goto found; } @@ -265,11 +269,12 @@ struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversio struct nfs_client *clp; spin_lock(&nfs_client_lock); - clp = __nfs_find_client(addr, nfsversion); + clp = __nfs_find_client(addr, nfsversion, 0); spin_unlock(&nfs_client_lock); - - BUG_ON(clp && clp->cl_cons_state == 0); - + if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) { + nfs_put_client(clp); + clp = NULL; + } return clp; } @@ -292,7 +297,7 @@ static struct nfs_client *nfs_get_client(const char *hostname, do { spin_lock(&nfs_client_lock); - clp = __nfs_find_client(addr, nfsversion); + clp = __nfs_find_client(addr, nfsversion, 1); if (clp) goto found_client; if (new) -- GitLab From cd9ae2b6a75bb1fa0d370929c2d7a7da1ed719d9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:40 -0700 Subject: [PATCH 1569/1619] [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(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 481f8892a91..58d44057813 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 1e873fcab94..bdfabf854a5 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 bc9376ca86c..9979ad1cf8e 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 76ff54846ad..6b2de1be581 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 *); -- GitLab From 39cf8a1374dc51fea169190674d5e4996a7d7ea2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 19 Oct 2006 23:28:41 -0700 Subject: [PATCH 1570/1619] [PATCH] NFS: fix minor bug in new NFS symlink code The original code confused a zero return code from pagevec_add() as success. Test plan: None. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 58d44057813..c86a1ead477 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1519,8 +1519,8 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym pagevec_init(&lru_pvec, 0); if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0, GFP_KERNEL)) { - if (!pagevec_add(&lru_pvec, page)) - __pagevec_lru_add(&lru_pvec); + pagevec_add(&lru_pvec, page); + pagevec_lru_add(&lru_pvec); SetPageUptodate(page); unlock_page(page); } else -- GitLab From 85233a7a436a48a0b98e7976a66797e5da79c9d6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 19 Oct 2006 23:28:42 -0700 Subject: [PATCH 1571/1619] [PATCH] NFS: __nfs_revalidate_inode() can use "inode" before checking it is non-NULL The "!inode" check in __nfs_revalidate_inode() occurs well after the first time it is dereferenced, so get rid of it. Coverity: #cid 1372, 1373 Test plan: Code review; recheck with Coverity. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 9979ad1cf8e..08cc4c5919a 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -583,7 +583,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); lock_kernel(); - if (!inode || is_bad_inode(inode)) + if (is_bad_inode(inode)) goto out_nowait; if (NFS_STALE(inode)) goto out_nowait; -- GitLab From b87c0adfeaaf8d8310c4f790d76072a5961b3518 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 19 Oct 2006 23:28:42 -0700 Subject: [PATCH 1572/1619] [PATCH] NFS: remove unused check in nfs4_open_revalidate Coverity spotted a superfluous error check in nfs4_open_revalidate(). Remove it. Coverity: #cid 847 Test plan: Code inspection; another pass through Coverity. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/nfs4proc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 47c7e6e3910..7421bcb3b72 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1314,11 +1314,9 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st case -EROFS: lookup_instantiate_filp(nd, (struct dentry *)state, NULL); return 1; - case -ENOENT: - if (dentry->d_inode == NULL) - return 1; + default: + goto out_drop; } - goto out_drop; } if (state->inode == dentry->d_inode) { nfs4_intent_set_file(nd, dentry, state); -- GitLab From 71bdcf8056f910dc57ea3d0def80a9329e7dc52d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 19 Oct 2006 23:28:43 -0700 Subject: [PATCH 1573/1619] [PATCH] SUNRPC: fix race in in-kernel RPC portmapper client When submitting a request to a fast portmapper (such as the local rpcbind daemon), the request can complete before the parent task is even queued up on xprt->binding. Fix this by queuing before submitting the rpcbind request. Test plan: Connectathon locking test with UDP. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/pmap_clnt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 919d5ba7ca0..e52afab413d 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -101,11 +101,13 @@ void rpc_getport(struct rpc_task *task) /* Autobind on cloned rpc clients is discouraged */ BUG_ON(clnt->cl_parent != clnt); - if (xprt_test_and_set_binding(xprt)) { - task->tk_status = -EACCES; /* tell caller to check again */ - rpc_sleep_on(&xprt->binding, task, NULL, NULL); - return; - } + /* Put self on queue before sending rpcbind request, in case + * pmap_getport_done completes before we return from rpc_run_task */ + rpc_sleep_on(&xprt->binding, task, NULL, NULL); + + status = -EACCES; /* tell caller to check again */ + if (xprt_test_and_set_binding(xprt)) + goto bailout_nofree; /* Someone else may have bound if we slept */ status = 0; @@ -134,8 +136,6 @@ void rpc_getport(struct rpc_task *task) goto bailout; rpc_release_task(child); - rpc_sleep_on(&xprt->binding, task, NULL, NULL); - task->tk_xprt->stat.bind_count++; return; -- GitLab From b7766da7f7395b74dec9e52005b7dac0d09391a4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 19 Oct 2006 23:28:44 -0700 Subject: [PATCH 1574/1619] [PATCH] SUNRPC: fix a typo Yes, this actually passed tests the way it was. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/xprtsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 28100e01922..757fc91ef25 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1366,7 +1366,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) if (xprt->slot == NULL) return -ENOMEM; - if (ntohs(addr->sin_port != 0)) + if (ntohs(addr->sin_port) != 0) xprt_set_bound(xprt); xprt->port = xs_get_random_port(); -- GitLab From cc45f0175088e000ac7493e5e3f05579b6f7d240 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:44 -0700 Subject: [PATCH 1575/1619] [PATCH] bug: nfsd/nfs4xdr.c misuse of ERR_PTR() a) ERR_PTR(nfserr_something) is a bad idea; IS_ERR() will be false for it. b) mixing nfserr_.... with -EOPNOTSUPP is even worse idea. nfsd4_path() does both; caller expects to get NFS protocol error out it if anything goes wrong, but if it does we either do not notice (see (a)) or get host-endian negative (see (b)). IOW, that's a case when we can't use ERR_PTR() to return error, even though we return a pointer in case of success. 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/nfs4xdr.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 41fc241b729..77be0c4785e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1292,16 +1292,15 @@ 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) +static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *stat) { 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); + *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle); + if (*stat) + return NULL; rootpath = tmp_fh.fh_export->ex_path; path = exp->ex_path; @@ -1309,7 +1308,8 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp) if (strncmp(path, rootpath, strlen(rootpath))) { printk("nfsd: fs_locations failed;" "%s is not contained in %s\n", path, rootpath); - return ERR_PTR(-EOPNOTSUPP); + *stat = nfserr_notsupp; + return NULL; } return path + strlen(rootpath); @@ -1322,13 +1322,14 @@ static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, struct svc_export *exp, u32 **pp, int *buflen) { - int status, i; + u32 status; + int i; u32 *p = *pp; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; - char *root = nfsd4_path(rqstp, exp); + char *root = nfsd4_path(rqstp, exp, &status); - if (IS_ERR(root)) - return PTR_ERR(root); + if (status) + return status; status = nfsd4_encode_components('/', root, &p, buflen); if (status) return status; -- GitLab From 7111c66e4e70588c9602035a4996c9cdc2087d2d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:45 -0700 Subject: [PATCH 1576/1619] [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(-) diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 399ad11b97b..4e719860b4b 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 6a931f4ab75..db8d85c32d2 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 29f93219205..5998d0c7175 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 9187755661d..8d48616882c 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 d4bdc00c116..ed6e2c27b5e 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 a5ebc7dbb38..a12663fdfe1 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 d1fac6872c4..795ad6c5cb2 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 9ee1dab5d44..09030afd724 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 9c9a8ad9247..965d6c20086 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 */ -- GitLab From 52921e02a4f4163a7b1f4b5dde71e1debc71de4a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:46 -0700 Subject: [PATCH 1577/1619] [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(-) diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index e8c7765419e..b85a0ad2cfb 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 e0179f8c327..eb243edf893 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 4e719860b4b..0ce5c81ff50 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 814c6064c9e..7e219b93855 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 db8d85c32d2..32e99a6e8dc 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 b9926ce8782..6220dc2a3f2 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 7dac96e6c82..e83024e1604 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 61c46facf25..b7c949256e5 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 36eb175ec33..f4c0b2b9f75 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 2909619c029..862d9730a60 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 cd7816e74c0..630c5bf69b0 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 66fdae3b490..29e7d9fc9da 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 3cc1ae25009..dd12b4c9e61 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 *); -- GitLab From 9d787a75a00679c3ebcb88236a7af7b38a0b5932 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:47 -0700 Subject: [PATCH 1578/1619] [PATCH] xdr annotations: NFSv2 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/nfs2xdr.c | 74 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index b49501fc0a7..1d801e30c40 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -66,15 +66,15 @@ /* * Common NFS XDR functions as inlines */ -static inline u32 * -xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle) +static inline __be32 * +xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle) { memcpy(p, fhandle->data, NFS2_FHSIZE); return p + XDR_QUADLEN(NFS2_FHSIZE); } -static inline u32 * -xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle) +static inline __be32 * +xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle) { /* NFSv2 handles have a fixed length */ fhandle->size = NFS2_FHSIZE; @@ -82,8 +82,8 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle) return p + XDR_QUADLEN(NFS2_FHSIZE); } -static inline u32* -xdr_encode_time(u32 *p, struct timespec *timep) +static inline __be32* +xdr_encode_time(__be32 *p, struct timespec *timep) { *p++ = htonl(timep->tv_sec); /* Convert nanoseconds into microseconds */ @@ -91,8 +91,8 @@ xdr_encode_time(u32 *p, struct timespec *timep) return p; } -static inline u32* -xdr_encode_current_server_time(u32 *p, struct timespec *timep) +static inline __be32* +xdr_encode_current_server_time(__be32 *p, struct timespec *timep) { /* * Passing the invalid value useconds=1000000 is a @@ -108,8 +108,8 @@ xdr_encode_current_server_time(u32 *p, struct timespec *timep) return p; } -static inline u32* -xdr_decode_time(u32 *p, struct timespec *timep) +static inline __be32* +xdr_decode_time(__be32 *p, struct timespec *timep) { timep->tv_sec = ntohl(*p++); /* Convert microseconds into nanoseconds */ @@ -117,8 +117,8 @@ xdr_decode_time(u32 *p, struct timespec *timep) return p; } -static u32 * -xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) +static __be32 * +xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) { u32 rdev; fattr->type = (enum nfs_ftype) ntohl(*p++); @@ -146,10 +146,10 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) return p; } -static inline u32 * -xdr_encode_sattr(u32 *p, struct iattr *attr) +static inline __be32 * +xdr_encode_sattr(__be32 *p, struct iattr *attr) { - const u32 not_set = __constant_htonl(0xFFFFFFFF); + const __be32 not_set = __constant_htonl(0xFFFFFFFF); *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set; *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set; @@ -184,7 +184,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr) * GETATTR, READLINK, STATFS */ static int -nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh) +nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh) { p = xdr_encode_fhandle(p, fh); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -195,7 +195,7 @@ nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh) * Encode SETATTR arguments */ static int -nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args) +nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_sattr(p, args->sattr); @@ -208,7 +208,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args) * LOOKUP, REMOVE, RMDIR */ static int -nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args) +nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); @@ -222,7 +222,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args) * exactly to the page we want to fetch. */ static int -nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) +nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; @@ -246,7 +246,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) * Decode READ reply */ static int -nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) +nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) { struct kvec *iov = req->rq_rcv_buf.head; int status, count, recvd, hdrlen; @@ -286,7 +286,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) * Write arguments. Splice the buffer to be written into the iovec. */ static int -nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) +nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) { struct xdr_buf *sndbuf = &req->rq_snd_buf; u32 offset = (u32)args->offset; @@ -309,7 +309,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) * CREATE, MKDIR */ static int -nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args) +nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); @@ -322,7 +322,7 @@ nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args) * Encode RENAME arguments */ static int -nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args) +nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args) { p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_array(p, args->fromname, args->fromlen); @@ -336,7 +336,7 @@ nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args) * Encode LINK arguments */ static int -nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) +nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args) { p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_fhandle(p, args->tofh); @@ -349,7 +349,7 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) * Encode SYMLINK arguments */ static int -nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) +nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args) { struct xdr_buf *sndbuf = &req->rq_snd_buf; size_t pad; @@ -378,7 +378,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) * Encode arguments to readdir call */ static int -nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args) +nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) { struct rpc_task *task = req->rq_task; struct rpc_auth *auth = task->tk_auth; @@ -404,7 +404,7 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args) * from nfs_readdir for each entry. */ static int -nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) +nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct kvec *iov = rcvbuf->head; @@ -412,7 +412,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) int hdrlen, recvd; int status, nr; unsigned int len, pglen; - u32 *end, *entry, *kaddr; + __be32 *end, *entry, *kaddr; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); @@ -432,8 +432,8 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; - kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0); - end = (u32 *)((char *)p + pglen); + kaddr = p = kmap_atomic(*page, KM_USER0); + end = (__be32 *)((char *)p + pglen); entry = p; for (nr = 0; *p++; nr++) { if (p + 2 > end) @@ -496,7 +496,7 @@ nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) * Decode simple status reply */ static int -nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy) +nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy) { int status; @@ -510,7 +510,7 @@ nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy) * GETATTR, SETATTR, WRITE */ static int -nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) +nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) { int status; @@ -525,7 +525,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) * LOOKUP, CREATE, MKDIR */ static int -nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res) +nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) { int status; @@ -540,7 +540,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res) * Encode READLINK args */ static int -nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args) +nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; @@ -558,7 +558,7 @@ nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args * Decode READLINK reply */ static int -nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) +nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct kvec *iov = rcvbuf->head; @@ -601,7 +601,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) * Decode WRITE reply */ static int -nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) +nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) { res->verf->committed = NFS_FILE_SYNC; return nfs_xdr_attrstat(req, p, res->fattr); @@ -611,7 +611,7 @@ nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) * Decode STATFS reply */ static int -nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res) +nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res) { int status; -- GitLab From d61005a6855160091dca44b718db93fe7aa9876f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:48 -0700 Subject: [PATCH 1579/1619] [PATCH] xdr annotations: NFSv3 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/nfs3xdr.c | 114 +++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 16556fa4eff..b4e740e4494 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -105,14 +105,14 @@ static struct { /* * Common NFS XDR functions as inlines */ -static inline u32 * -xdr_encode_fhandle(u32 *p, struct nfs_fh *fh) +static inline __be32 * +xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh) { return xdr_encode_array(p, fh->data, fh->size); } -static inline u32 * -xdr_decode_fhandle(u32 *p, struct nfs_fh *fh) +static inline __be32 * +xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh) { if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) { memcpy(fh->data, p, fh->size); @@ -124,24 +124,24 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh *fh) /* * Encode/decode time. */ -static inline u32 * -xdr_encode_time3(u32 *p, struct timespec *timep) +static inline __be32 * +xdr_encode_time3(__be32 *p, struct timespec *timep) { *p++ = htonl(timep->tv_sec); *p++ = htonl(timep->tv_nsec); return p; } -static inline u32 * -xdr_decode_time3(u32 *p, struct timespec *timep) +static inline __be32 * +xdr_decode_time3(__be32 *p, struct timespec *timep) { timep->tv_sec = ntohl(*p++); timep->tv_nsec = ntohl(*p++); return p; } -static u32 * -xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) +static __be32 * +xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) { unsigned int type, major, minor; int fmode; @@ -177,8 +177,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) return p; } -static inline u32 * -xdr_encode_sattr(u32 *p, struct iattr *attr) +static inline __be32 * +xdr_encode_sattr(__be32 *p, struct iattr *attr) { if (attr->ia_valid & ATTR_MODE) { *p++ = xdr_one; @@ -223,8 +223,8 @@ xdr_encode_sattr(u32 *p, struct iattr *attr) return p; } -static inline u32 * -xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr) +static inline __be32 * +xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr) { p = xdr_decode_hyper(p, &fattr->pre_size); p = xdr_decode_time3(p, &fattr->pre_mtime); @@ -233,16 +233,16 @@ xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr) return p; } -static inline u32 * -xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr) +static inline __be32 * +xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr) { if (*p++) p = xdr_decode_fattr(p, fattr); return p; } -static inline u32 * -xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr) +static inline __be32 * +xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr) { if (*p++) return xdr_decode_wcc_attr(p, fattr); @@ -250,8 +250,8 @@ xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr) } -static inline u32 * -xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr) +static inline __be32 * +xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr) { p = xdr_decode_pre_op_attr(p, fattr); return xdr_decode_post_op_attr(p, fattr); @@ -265,7 +265,7 @@ xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr) * Encode file handle argument */ static int -nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh) +nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh) { p = xdr_encode_fhandle(p, fh); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -276,7 +276,7 @@ nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh) * Encode SETATTR arguments */ static int -nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args) +nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_sattr(p, args->sattr); @@ -291,7 +291,7 @@ nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args) * Encode directory ops argument */ static int -nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args) +nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); @@ -303,7 +303,7 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args) * Encode access() argument */ static int -nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args) +nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args) { p = xdr_encode_fhandle(p, args->fh); *p++ = htonl(args->access); @@ -317,7 +317,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args) * exactly to the page we want to fetch. */ static int -nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) +nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; @@ -339,7 +339,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) * Write arguments. Splice the buffer to be written into the iovec. */ static int -nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) +nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) { struct xdr_buf *sndbuf = &req->rq_snd_buf; u32 count = args->count; @@ -360,7 +360,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) * Encode CREATE arguments */ static int -nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args) +nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); @@ -380,7 +380,7 @@ nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args) * Encode MKDIR arguments */ static int -nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args) +nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); @@ -393,7 +393,7 @@ nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args) * Encode SYMLINK arguments */ static int -nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args) +nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args) { p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_array(p, args->fromname, args->fromlen); @@ -410,7 +410,7 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args * Encode MKNOD arguments */ static int -nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args) +nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); @@ -429,7 +429,7 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args) * Encode RENAME arguments */ static int -nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args) +nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args) { p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_array(p, args->fromname, args->fromlen); @@ -443,7 +443,7 @@ nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args) * Encode LINK arguments */ static int -nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args) +nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) { p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_fhandle(p, args->tofh); @@ -456,7 +456,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args) * Encode arguments to readdir call */ static int -nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args) +nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; @@ -485,7 +485,7 @@ nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args * We just check for syntactical correctness. */ static int -nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) +nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct kvec *iov = rcvbuf->head; @@ -493,7 +493,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) int hdrlen, recvd; int status, nr; unsigned int len, pglen; - u32 *entry, *end, *kaddr; + __be32 *entry, *end, *kaddr; status = ntohl(*p++); /* Decode post_op_attrs */ @@ -523,8 +523,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; - kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0); - end = (u32 *)((char *)p + pglen); + kaddr = p = kmap_atomic(*page, KM_USER0); + end = (__be32 *)((char *)p + pglen); entry = p; for (nr = 0; *p++; nr++) { if (p + 3 > end) @@ -626,7 +626,7 @@ nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) * Encode COMMIT arguments */ static int -nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) +nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_hyper(p, args->offset); @@ -640,7 +640,7 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) * Encode GETACL arguments */ static int -nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p, +nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, struct nfs3_getaclargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; @@ -664,7 +664,7 @@ nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p, * Encode SETACL arguments */ static int -nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, +nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p, struct nfs3_setaclargs *args) { struct xdr_buf *buf = &req->rq_snd_buf; @@ -711,7 +711,7 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, * Decode attrstat reply. */ static int -nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) +nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) { int status; @@ -726,7 +726,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) * SATTR, REMOVE, RMDIR */ static int -nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) +nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) { int status; @@ -740,7 +740,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) * Decode LOOKUP reply */ static int -nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res) +nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) { int status; @@ -759,7 +759,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res) * Decode ACCESS reply */ static int -nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res) +nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) { int status = ntohl(*p++); @@ -771,7 +771,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res) } static int -nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args) +nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; @@ -789,7 +789,7 @@ nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *ar * Decode READLINK reply */ static int -nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) +nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct kvec *iov = rcvbuf->head; @@ -837,7 +837,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) * Decode READ reply */ static int -nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) +nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) { struct kvec *iov = req->rq_rcv_buf.head; int status, count, ocount, recvd, hdrlen; @@ -888,7 +888,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) * Decode WRITE response */ static int -nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) +nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) { int status; @@ -910,7 +910,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) * Decode a CREATE response */ static int -nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res) +nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) { int status; @@ -937,7 +937,7 @@ nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res) * Decode RENAME reply */ static int -nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res) +nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res) { int status; @@ -952,7 +952,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res) * Decode LINK reply */ static int -nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res) +nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) { int status; @@ -967,7 +967,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res) * Decode FSSTAT reply */ static int -nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res) +nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) { int status; @@ -992,7 +992,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res) * Decode FSINFO reply */ static int -nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) +nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) { int status; @@ -1020,7 +1020,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) * Decode PATHCONF reply */ static int -nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res) +nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) { int status; @@ -1040,7 +1040,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res) * Decode COMMIT reply */ static int -nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) +nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) { int status; @@ -1059,7 +1059,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) * Decode GETACL reply */ static int -nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p, +nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, struct nfs3_getaclres *res) { struct xdr_buf *buf = &req->rq_rcv_buf; @@ -1091,7 +1091,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p, * Decode setacl reply. */ static int -nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) +nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) { int status = ntohl(*p++); -- GitLab From 8687b63afbe42103730bff4d3f7bfff3463c303e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:48 -0700 Subject: [PATCH 1580/1619] [PATCH] xdr annotations: NFSv4 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/nfs4xdr.c | 358 ++++++++++++++++++++++++----------------------- 1 file changed, 181 insertions(+), 177 deletions(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 3dd413f52da..e284123b977 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -471,7 +471,7 @@ struct compound_hdr { static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) { - uint32_t *p; + __be32 *p; p = xdr_reserve_space(xdr, 4 + len); BUG_ON(p == NULL); @@ -480,7 +480,7 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { - uint32_t *p; + __be32 *p; dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); @@ -494,7 +494,7 @@ static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf) { - uint32_t *p; + __be32 *p; p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); BUG_ON(p == NULL); @@ -507,8 +507,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s char owner_group[IDMAP_NAMESZ]; int owner_namelen = 0; int owner_grouplen = 0; - uint32_t *p; - uint32_t *q; + __be32 *p; + __be32 *q; int len; uint32_t bmval0 = 0; uint32_t bmval1 = 0; @@ -630,7 +630,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s static int encode_access(struct xdr_stream *xdr, u32 access) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8); WRITE32(OP_ACCESS); @@ -641,7 +641,7 @@ static int encode_access(struct xdr_stream *xdr, u32 access) static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8+sizeof(arg->stateid->data)); WRITE32(OP_CLOSE); @@ -653,7 +653,7 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(16); WRITE32(OP_COMMIT); @@ -665,7 +665,7 @@ static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *arg static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8); WRITE32(OP_CREATE); @@ -697,7 +697,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(12); WRITE32(OP_GETATTR); @@ -708,7 +708,7 @@ static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(16); WRITE32(OP_GETATTR); @@ -740,7 +740,7 @@ static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask) static int encode_getfh(struct xdr_stream *xdr) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_GETFH); @@ -750,7 +750,7 @@ static int encode_getfh(struct xdr_stream *xdr) static int encode_link(struct xdr_stream *xdr, const struct qstr *name) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8 + name->len); WRITE32(OP_LINK); @@ -780,7 +780,7 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl) */ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(32); WRITE32(OP_LOCK); @@ -809,7 +809,7 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(40); WRITE32(OP_LOCKT); @@ -825,7 +825,7 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(44); WRITE32(OP_LOCKU); @@ -841,7 +841,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *arg static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) { int len = name->len; - uint32_t *p; + __be32 *p; RESERVE_SPACE(8 + len); WRITE32(OP_LOOKUP); @@ -853,7 +853,7 @@ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) static void encode_share_access(struct xdr_stream *xdr, int open_flags) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8); switch (open_flags & (FMODE_READ|FMODE_WRITE)) { @@ -874,7 +874,7 @@ static void encode_share_access(struct xdr_stream *xdr, int open_flags) static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg) { - uint32_t *p; + __be32 *p; /* * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, * owner 4 = 32 @@ -891,7 +891,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); switch(arg->open_flags & O_EXCL) { @@ -907,7 +907,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); switch (arg->open_flags & O_CREAT) { @@ -923,7 +923,7 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); switch (delegation_type) { @@ -943,7 +943,7 @@ static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(NFS4_OPEN_CLAIM_NULL); @@ -952,7 +952,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr * static inline void encode_claim_previous(struct xdr_stream *xdr, int type) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(NFS4_OPEN_CLAIM_PREVIOUS); @@ -961,7 +961,7 @@ static inline void encode_claim_previous(struct xdr_stream *xdr, int type) static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4+sizeof(stateid->data)); WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR); @@ -991,7 +991,7 @@ static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg) static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8+sizeof(arg->stateid->data)); WRITE32(OP_OPEN_CONFIRM); @@ -1003,7 +1003,7 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8+sizeof(arg->stateid->data)); WRITE32(OP_OPEN_DOWNGRADE); @@ -1017,7 +1017,7 @@ static int encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) { int len = fh->size; - uint32_t *p; + __be32 *p; RESERVE_SPACE(8 + len); WRITE32(OP_PUTFH); @@ -1029,7 +1029,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) static int encode_putrootfh(struct xdr_stream *xdr) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_PUTROOTFH); @@ -1040,7 +1040,7 @@ static int encode_putrootfh(struct xdr_stream *xdr) static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) { nfs4_stateid stateid; - uint32_t *p; + __be32 *p; RESERVE_SPACE(16); if (ctx->state != NULL) { @@ -1052,7 +1052,7 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_READ); @@ -1074,7 +1074,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg FATTR4_WORD1_MOUNTED_ON_FILEID, }; int replen; - uint32_t *p; + __be32 *p; RESERVE_SPACE(32+sizeof(nfs4_verifier)); WRITE32(OP_READDIR); @@ -1116,7 +1116,7 @@ static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *r { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_READLINK); @@ -1134,7 +1134,7 @@ static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *r static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8 + name->len); WRITE32(OP_REMOVE); @@ -1146,7 +1146,7 @@ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(8 + oldname->len); WRITE32(OP_RENAME); @@ -1162,7 +1162,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(12); WRITE32(OP_RENEW); @@ -1174,7 +1174,7 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_ static int encode_restorefh(struct xdr_stream *xdr) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_RESTOREFH); @@ -1185,7 +1185,7 @@ encode_restorefh(struct xdr_stream *xdr) static int encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4+sizeof(zero_stateid.data)); WRITE32(OP_SETATTR); @@ -1204,7 +1204,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) static int encode_savefh(struct xdr_stream *xdr) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_SAVEFH); @@ -1215,7 +1215,7 @@ encode_savefh(struct xdr_stream *xdr) static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server) { int status; - uint32_t *p; + __be32 *p; RESERVE_SPACE(4+sizeof(arg->stateid.data)); WRITE32(OP_SETATTR); @@ -1229,7 +1229,7 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs * static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data)); WRITE32(OP_SETCLIENTID); @@ -1248,7 +1248,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data)); WRITE32(OP_SETCLIENTID_CONFIRM); @@ -1260,7 +1260,7 @@ static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_c static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(4); WRITE32(OP_WRITE); @@ -1279,7 +1279,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid) { - uint32_t *p; + __be32 *p; RESERVE_SPACE(20); @@ -1295,7 +1295,7 @@ static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *statei /* * Encode an ACCESS request */ -static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args) +static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1313,7 +1313,7 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct n /* * Encode LOOKUP request */ -static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args) +static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1337,7 +1337,7 @@ out: /* * Encode LOOKUP_ROOT request */ -static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args) +static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1358,7 +1358,7 @@ out: /* * Encode REMOVE request */ -static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args) +static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1380,7 +1380,7 @@ out: /* * Encode RENAME request */ -static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args) +static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1410,7 +1410,7 @@ out: /* * Encode LINK request */ -static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args) +static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1440,7 +1440,7 @@ out: /* * Encode CREATE request */ -static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args) +static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1470,7 +1470,7 @@ out: /* * Encode SYMLINK request */ -static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args) +static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args) { return nfs4_xdr_enc_create(req, p, args); } @@ -1478,7 +1478,7 @@ static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct /* * Encode GETATTR request */ -static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args) +static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1496,7 +1496,7 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct /* * Encode a CLOSE request */ -static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1520,7 +1520,7 @@ out: /* * Encode an OPEN request */ -static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) +static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1556,7 +1556,7 @@ out: /* * Encode an OPEN_CONFIRM request */ -static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args) +static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1577,7 +1577,7 @@ out: /* * Encode an OPEN request with no attributes. */ -static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) +static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1601,7 +1601,7 @@ out: /* * Encode an OPEN_DOWNGRADE request */ -static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1625,7 +1625,7 @@ out: /* * Encode a LOCK request */ -static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args) +static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1646,7 +1646,7 @@ out: /* * Encode a LOCKT request */ -static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args) +static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1667,7 +1667,7 @@ out: /* * Encode a LOCKU request */ -static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args) +static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1688,7 +1688,7 @@ out: /* * Encode a READLINK request */ -static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args) +static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1709,7 +1709,7 @@ out: /* * Encode a READDIR request */ -static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args) +static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1730,7 +1730,7 @@ out: /* * Encode a READ request */ -static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args) +static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; struct xdr_stream xdr; @@ -1762,7 +1762,7 @@ out: /* * Encode an SETATTR request */ -static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) +static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args) { struct xdr_stream xdr; @@ -1788,7 +1788,7 @@ out: * Encode a GETACL request */ static int -nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p, +nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, struct nfs_getaclargs *args) { struct xdr_stream xdr; @@ -1815,7 +1815,7 @@ out: /* * Encode a WRITE request */ -static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) +static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1839,7 +1839,7 @@ out: /* * a COMMIT request */ -static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) +static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1863,7 +1863,7 @@ out: /* * FSINFO request */ -static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args) +static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1882,7 +1882,7 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs /* * a PATHCONF request */ -static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) +static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1902,7 +1902,7 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct /* * a STATFS request */ -static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) +static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1923,7 +1923,7 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct n /* * GETATTR_BITMAP request */ -static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle) +static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str /* * a RENEW request */ -static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp) +static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1960,7 +1960,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_clie /* * a SETCLIENTID request */ -static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc) +static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf /* * a SETCLIENTID_CONFIRM request */ -static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp) +static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1997,7 +1997,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s /* * DELEGRETURN request */ -static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args) +static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -2021,7 +2021,7 @@ out: /* * Encode FS_LOCATIONS request */ -static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args) +static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -2086,7 +2086,7 @@ out: static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string) { - uint32_t *p; + __be32 *p; READ_BUF(4); READ32(*len); @@ -2097,7 +2097,7 @@ static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { - uint32_t *p; + __be32 *p; READ_BUF(8); READ32(hdr->status); @@ -2112,7 +2112,7 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) { - uint32_t *p; + __be32 *p; uint32_t opnum; int32_t nfserr; @@ -2134,7 +2134,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) /* Dummy routine */ static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp) { - uint32_t *p; + __be32 *p; unsigned int strlen; char *str; @@ -2144,7 +2144,8 @@ static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp) static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) { - uint32_t bmlen, *p; + uint32_t bmlen; + __be32 *p; READ_BUF(4); READ32(bmlen); @@ -2159,9 +2160,9 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) return 0; } -static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep) +static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep) { - uint32_t *p; + __be32 *p; READ_BUF(4); READ32(*attrlen); @@ -2182,7 +2183,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3 static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type) { - uint32_t *p; + __be32 *p; *type = 0; if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U))) @@ -2202,7 +2203,7 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) { - uint32_t *p; + __be32 *p; *change = 0; if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U))) @@ -2219,7 +2220,7 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size) { - uint32_t *p; + __be32 *p; *size = 0; if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U))) @@ -2235,7 +2236,7 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) { - uint32_t *p; + __be32 *p; *res = 0; if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U))) @@ -2251,7 +2252,7 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) { - uint32_t *p; + __be32 *p; *res = 0; if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U))) @@ -2267,7 +2268,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid) { - uint32_t *p; + __be32 *p; fsid->major = 0; fsid->minor = 0; @@ -2287,7 +2288,7 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) { - uint32_t *p; + __be32 *p; *res = 60; if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U))) @@ -2303,7 +2304,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) { - uint32_t *p; + __be32 *p; *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL; if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) @@ -2319,7 +2320,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) { - uint32_t *p; + __be32 *p; *fileid = 0; if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U))) @@ -2335,7 +2336,7 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) { - uint32_t *p; + __be32 *p; *fileid = 0; if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U))) @@ -2351,7 +2352,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2368,7 +2369,7 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2385,7 +2386,7 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2403,7 +2404,7 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) { int n; - uint32_t *p; + __be32 *p; int status = 0; READ_BUF(4); @@ -2448,7 +2449,7 @@ out_eio: static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res) { int n; - uint32_t *p; + __be32 *p; int status = -EIO; if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U))) @@ -2512,7 +2513,7 @@ out_eio: static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2529,7 +2530,7 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) { - uint32_t *p; + __be32 *p; int status = 0; *maxlink = 1; @@ -2546,7 +2547,7 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname) { - uint32_t *p; + __be32 *p; int status = 0; *maxname = 1024; @@ -2563,7 +2564,7 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 1024; @@ -2584,7 +2585,7 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 1024; @@ -2605,7 +2606,7 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode) { - uint32_t *p; + __be32 *p; *mode = 0; if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U))) @@ -2622,7 +2623,7 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink) { - uint32_t *p; + __be32 *p; *nlink = 1; if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U))) @@ -2638,7 +2639,8 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid) { - uint32_t len, *p; + uint32_t len; + __be32 *p; *uid = -2; if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U))) @@ -2662,7 +2664,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid) { - uint32_t len, *p; + uint32_t len; + __be32 *p; *gid = -2; if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U))) @@ -2686,7 +2689,8 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev) { - uint32_t major = 0, minor = 0, *p; + uint32_t major = 0, minor = 0; + __be32 *p; *rdev = MKDEV(0,0); if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U))) @@ -2708,7 +2712,7 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2725,7 +2729,7 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2742,7 +2746,7 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) { - uint32_t *p; + __be32 *p; int status = 0; *res = 0; @@ -2759,7 +2763,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) { - uint32_t *p; + __be32 *p; *used = 0; if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U))) @@ -2776,7 +2780,7 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) { - uint32_t *p; + __be32 *p; uint64_t sec; uint32_t nsec; @@ -2836,7 +2840,7 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str return status; } -static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen) +static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen) { unsigned int attrwords = XDR_QUADLEN(attrlen); unsigned int nwords = xdr->p - savep; @@ -2854,7 +2858,7 @@ static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t att static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { - uint32_t *p; + __be32 *p; READ_BUF(20); READ32(cinfo->atomic); @@ -2865,7 +2869,7 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) { - uint32_t *p; + __be32 *p; uint32_t supp, acc; int status; @@ -2882,7 +2886,7 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_CLOSE); @@ -2895,7 +2899,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_COMMIT); @@ -2908,7 +2912,7 @@ static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { - uint32_t *p; + __be32 *p; uint32_t bmlen; int status; @@ -2925,7 +2929,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) { - uint32_t *savep; + __be32 *savep; uint32_t attrlen, bitmap[2] = {0}; int status; @@ -2952,7 +2956,7 @@ xdr_error: static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) { - uint32_t *savep; + __be32 *savep; uint32_t attrlen, bitmap[2] = {0}; int status; @@ -2985,7 +2989,7 @@ xdr_error: static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) { - uint32_t *savep; + __be32 *savep; uint32_t attrlen, bitmap[2] = {0}; int status; @@ -3010,7 +3014,7 @@ xdr_error: static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) { - uint32_t *savep; + __be32 *savep; uint32_t attrlen, bitmap[2] = {0}, type; @@ -3079,7 +3083,7 @@ xdr_error: static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) { - uint32_t *savep; + __be32 *savep; uint32_t attrlen, bitmap[2]; int status; @@ -3111,7 +3115,7 @@ xdr_error: static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) { - uint32_t *p; + __be32 *p; uint32_t len; int status; @@ -3147,7 +3151,7 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) { uint64_t offset, length, clientid; - uint32_t *p; + __be32 *p; uint32_t namelen, type; READ_BUF(32); @@ -3172,7 +3176,7 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_LOCK); @@ -3195,7 +3199,7 @@ static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res) static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_LOCKU); @@ -3214,7 +3218,7 @@ static int decode_lookup(struct xdr_stream *xdr) /* This is too sick! */ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) { - uint32_t *p; + __be32 *p; uint32_t limit_type, nblocks, blocksize; READ_BUF(12); @@ -3233,7 +3237,7 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) { - uint32_t *p; + __be32 *p; uint32_t delegation_type; READ_BUF(4); @@ -3259,7 +3263,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) { - uint32_t *p; + __be32 *p; uint32_t bmlen; int status; @@ -3287,7 +3291,7 @@ xdr_error: static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); @@ -3300,7 +3304,7 @@ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmre static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); @@ -3324,7 +3328,7 @@ static int decode_putrootfh(struct xdr_stream *xdr) static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) { struct kvec *iov = req->rq_rcv_buf.head; - uint32_t *p; + __be32 *p; uint32_t count, eof, recvd, hdrlen; int status; @@ -3354,7 +3358,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n struct page *page = *rcvbuf->pages; struct kvec *iov = rcvbuf->head; unsigned int nr, pglen = rcvbuf->page_len; - uint32_t *end, *entry, *p, *kaddr; + __be32 *end, *entry, *p, *kaddr; uint32_t len, attrlen, xlen; int hdrlen, recvd, status; @@ -3376,7 +3380,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n xdr_read_pages(xdr, pglen); BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); - kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0); + kaddr = p = kmap_atomic(page, KM_USER0); end = p + ((pglen + readdir->pgbase) >> 2); entry = p; for (nr = 0; *p++; nr++) { @@ -3428,7 +3432,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct kvec *iov = rcvbuf->head; int hdrlen, len, recvd; - uint32_t *p; + __be32 *p; char *kaddr; int status; @@ -3505,7 +3509,7 @@ decode_restorefh(struct xdr_stream *xdr) static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, size_t *acl_len) { - uint32_t *savep; + __be32 *savep; uint32_t attrlen, bitmap[2] = {0}; struct kvec *iov = req->rq_rcv_buf.head; @@ -3551,7 +3555,7 @@ decode_savefh(struct xdr_stream *xdr) static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) { - uint32_t *p; + __be32 *p; uint32_t bmlen; int status; @@ -3567,7 +3571,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) { - uint32_t *p; + __be32 *p; uint32_t opnum; int32_t nfserr; @@ -3610,7 +3614,7 @@ static int decode_setclientid_confirm(struct xdr_stream *xdr) static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) { - uint32_t *p; + __be32 *p; int status; status = decode_op_hdr(xdr, OP_WRITE); @@ -3632,7 +3636,7 @@ static int decode_delegreturn(struct xdr_stream *xdr) /* * Decode OPEN_DOWNGRADE response */ -static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) +static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3660,7 +3664,7 @@ out: /* * Decode ACCESS response */ -static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res) +static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3678,7 +3682,7 @@ out: /* * Decode LOOKUP response */ -static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res) +static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3701,7 +3705,7 @@ out: /* * Decode LOOKUP_ROOT response */ -static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res) +static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3721,7 +3725,7 @@ out: /* * Decode REMOVE response */ -static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res) +static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3742,7 +3746,7 @@ out: /* * Decode RENAME response */ -static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res) +static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3772,7 +3776,7 @@ out: /* * Decode LINK response */ -static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res) +static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3805,7 +3809,7 @@ out: /* * Decode CREATE response */ -static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res) +static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3834,7 +3838,7 @@ out: /* * Decode SYMLINK response */ -static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res) +static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res) { return nfs4_xdr_dec_create(rqstp, p, res); } @@ -3842,7 +3846,7 @@ static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4 /* * Decode GETATTR response */ -static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res) +static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3865,7 +3869,7 @@ out: * Encode an SETACL request */ static int -nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args) +nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -3886,7 +3890,7 @@ out: * Decode SETACL response */ static int -nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res) +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3908,7 +3912,7 @@ out: * Decode GETACL response */ static int -nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len) +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3930,7 +3934,7 @@ out: /* * Decode CLOSE response */ -static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) +static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3960,7 +3964,7 @@ out: /* * Decode OPEN response */ -static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) +static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3994,7 +3998,7 @@ out: /* * Decode OPEN_CONFIRM response */ -static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res) +static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4015,7 +4019,7 @@ out: /* * Decode OPEN response */ -static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) +static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4039,7 +4043,7 @@ out: /* * Decode SETATTR response */ -static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res) +static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4065,7 +4069,7 @@ out: /* * Decode LOCK response */ -static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res) +static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4086,7 +4090,7 @@ out: /* * Decode LOCKT response */ -static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res) +static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4107,7 +4111,7 @@ out: /* * Decode LOCKU response */ -static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res) +static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4128,7 +4132,7 @@ out: /* * Decode READLINK response */ -static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res) +static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4149,7 +4153,7 @@ out: /* * Decode READDIR response */ -static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res) +static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4170,7 +4174,7 @@ out: /* * Decode Read response */ -static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res) +static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4193,7 +4197,7 @@ out: /* * Decode WRITE response */ -static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res) +static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4219,7 +4223,7 @@ out: /* * Decode COMMIT response */ -static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res) +static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4243,7 +4247,7 @@ out: /* * FSINFO request */ -static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) +static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4263,7 +4267,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi /* * PATHCONF request */ -static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf) +static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4281,7 +4285,7 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_p /* * STATFS request */ -static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat) +static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4299,7 +4303,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fss /* * GETATTR_BITMAP request */ -static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res) +static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4318,7 +4322,7 @@ out: /* * Decode RENEW response */ -static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) +static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4334,7 +4338,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) /* * a SETCLIENTID request */ -static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, +static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp) { struct xdr_stream xdr; @@ -4353,7 +4357,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, /* * a SETCLIENTID_CONFIRM request */ -static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) +static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4375,7 +4379,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s /* * DELEGRETURN request */ -static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res) +static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4397,7 +4401,7 @@ out: /* * FS_LOCATIONS request */ -static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res) +static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res) { struct xdr_stream xdr; struct compound_hdr hdr; -- GitLab From 0dbb4c6799cf8fa8c5ba1926153a30960117477d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:49 -0700 Subject: [PATCH 1581/1619] [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(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c86a1ead477..4133ef5264e 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 bea0b016bd7..d205466233f 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 1d801e30c40..3be4e72a022 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 b4e740e4494..0ace092d126 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 61095fe4b5c..6f346677332 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 7421bcb3b72..8d09b47c91b 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 e284123b977..0cf3fa312a3 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 dc5397d9d23..ac8058bc8f9 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); -- GitLab From e6f684f6443dd37384c63d2f27571350e0b5c8aa Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:50 -0700 Subject: [PATCH 1582/1619] [PATCH] fs/nfs/callback* passes error values big-endian [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/callback.h | 6 ++--- fs/nfs/callback_proc.c | 6 ++--- fs/nfs/callback_xdr.c | 60 +++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index 5676163d26e..6921d82b850 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h @@ -44,7 +44,7 @@ struct cb_getattrargs { }; struct cb_getattrres { - uint32_t status; + __be32 status; uint32_t bitmap[2]; uint64_t size; uint64_t change_attr; @@ -59,8 +59,8 @@ struct cb_recallargs { uint32_t truncate; }; -extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); -extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); +extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); +extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); #ifdef CONFIG_NFS_V4 extern int nfs_callback_up(void); diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 97cf8f71451..72e55d83756 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -14,7 +14,7 @@ #define NFSDBG_FACILITY NFSDBG_CALLBACK -unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) +__be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) { struct nfs_client *clp; struct nfs_delegation *delegation; @@ -55,11 +55,11 @@ out: return res->status; } -unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) +__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) { struct nfs_client *clp; struct inode *inode; - unsigned res; + __be32 res; res = htonl(NFS4ERR_BADHANDLE); clp = nfs_find_client(args->addr, 4); diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 5998d0c7175..909a1408bca 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -22,9 +22,9 @@ #define NFSDBG_FACILITY NFSDBG_CALLBACK -typedef unsigned (*callback_process_op_t)(void *, void *); -typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); -typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); +typedef __be32 (*callback_process_op_t)(void *, void *); +typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); +typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); struct callback_op { @@ -61,7 +61,7 @@ static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes) return p; } -static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str) +static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str) { uint32_t *p; @@ -81,7 +81,7 @@ static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const c return 0; } -static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) +static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) { uint32_t *p; @@ -99,7 +99,7 @@ static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) return 0; } -static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) +static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) { uint32_t *p; unsigned int attrlen; @@ -118,7 +118,7 @@ static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) return 0; } -static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) +static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) { uint32_t *p; @@ -129,11 +129,11 @@ static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) return 0; } -static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) +static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) { uint32_t *p; unsigned int minor_version; - unsigned status; + __be32 status; status = decode_string(xdr, &hdr->taglen, &hdr->tag); if (unlikely(status != 0)) @@ -159,7 +159,7 @@ static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compou return 0; } -static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) +static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) { uint32_t *p; p = read_buf(xdr, 4); @@ -169,9 +169,9 @@ static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) return 0; } -static unsigned decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args) +static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args) { - unsigned status; + __be32 status; status = decode_fh(xdr, &args->fh); if (unlikely(status != 0)) @@ -183,10 +183,10 @@ out: return status; } -static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args) +static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args) { uint32_t *p; - unsigned status; + __be32 status; args->addr = &rqstp->rq_addr; status = decode_stateid(xdr, &args->stateid); @@ -204,7 +204,7 @@ out: return status; } -static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) +static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) { uint32_t *p; @@ -217,7 +217,7 @@ static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const ch #define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) #define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) -static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep) +static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep) { uint32_t bm[2]; uint32_t *p; @@ -247,7 +247,7 @@ static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitma return 0; } -static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change) +static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change) { uint32_t *p; @@ -260,7 +260,7 @@ static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitma return 0; } -static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size) +static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size) { uint32_t *p; @@ -273,7 +273,7 @@ static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, return 0; } -static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *time) +static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time) { uint32_t *p; @@ -285,23 +285,23 @@ static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec * return 0; } -static unsigned encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time) +static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time) { if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) return 0; return encode_attr_time(xdr,time); } -static unsigned encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time) +static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time) { if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) return 0; return encode_attr_time(xdr,time); } -static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr) +static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr) { - unsigned status; + __be32 status; hdr->status = xdr_reserve_space(xdr, 4); if (unlikely(hdr->status == NULL)) @@ -315,7 +315,7 @@ static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compou return 0; } -static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res) +static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) { uint32_t *p; @@ -327,10 +327,10 @@ static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res) return 0; } -static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) +static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) { uint32_t *savep = NULL; - unsigned status = res->status; + __be32 status = res->status; if (unlikely(status != 0)) goto out; @@ -353,15 +353,15 @@ out: return status; } -static unsigned process_op(struct svc_rqst *rqstp, +static __be32 process_op(struct svc_rqst *rqstp, struct xdr_stream *xdr_in, void *argp, struct xdr_stream *xdr_out, void *resp) { struct callback_op *op = &callback_ops[0]; unsigned int op_nr = OP_CB_ILLEGAL; - unsigned int status = 0; + __be32 status = 0; long maxlen; - unsigned res; + __be32 res; dprintk("%s: start\n", __FUNCTION__); status = decode_op_hdr(xdr_in, &op_nr); @@ -405,7 +405,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r struct cb_compound_hdr_res hdr_res; struct xdr_stream xdr_in, xdr_out; uint32_t *p; - unsigned int status; + __be32 status; unsigned int nops = 1; dprintk("%s: start\n", __FUNCTION__); -- GitLab From 5704fdeb41c9fb282ae576516f221ea0b8f64b2b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:51 -0700 Subject: [PATCH 1583/1619] [PATCH] xdr annotations: fs/nfs/callback* on-the-wire data is big-endian [mostly 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/callback.h | 4 ++-- fs/nfs/callback_xdr.c | 44 +++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index 6921d82b850..db3d7919c60 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h @@ -31,10 +31,10 @@ struct cb_compound_hdr_arg { }; struct cb_compound_hdr_res { - uint32_t *status; + __be32 *status; int taglen; const char *tag; - uint32_t *nops; + __be32 *nops; }; struct cb_getattrargs { diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 909a1408bca..f8ea1f51f59 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -41,19 +41,19 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp) return htonl(NFS4_OK); } -static int nfs4_decode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy) +static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } -static int nfs4_encode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy) +static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } -static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes) +static __be32 *read_buf(struct xdr_stream *xdr, int nbytes) { - uint32_t *p; + __be32 *p; p = xdr_inline_decode(xdr, nbytes); if (unlikely(p == NULL)) @@ -63,7 +63,7 @@ static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes) static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str) { - uint32_t *p; + __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) @@ -83,7 +83,7 @@ static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const cha static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) { - uint32_t *p; + __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) @@ -101,7 +101,7 @@ static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) { - uint32_t *p; + __be32 *p; unsigned int attrlen; p = read_buf(xdr, 4); @@ -120,7 +120,7 @@ static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) { - uint32_t *p; + __be32 *p; p = read_buf(xdr, 16); if (unlikely(p == NULL)) @@ -131,7 +131,7 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) { - uint32_t *p; + __be32 *p; unsigned int minor_version; __be32 status; @@ -161,7 +161,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) { - uint32_t *p; + __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); @@ -185,7 +185,7 @@ out: static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args) { - uint32_t *p; + __be32 *p; __be32 status; args->addr = &rqstp->rq_addr; @@ -206,7 +206,7 @@ out: static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) { - uint32_t *p; + __be32 *p; p = xdr_reserve_space(xdr, 4 + len); if (unlikely(p == NULL)) @@ -217,10 +217,10 @@ static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char #define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) #define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) -static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep) +static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep) { - uint32_t bm[2]; - uint32_t *p; + __be32 bm[2]; + __be32 *p; bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0); bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1); @@ -249,7 +249,7 @@ static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change) { - uint32_t *p; + __be32 *p; if (!(bitmap[0] & FATTR4_WORD0_CHANGE)) return 0; @@ -262,7 +262,7 @@ static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size) { - uint32_t *p; + __be32 *p; if (!(bitmap[0] & FATTR4_WORD0_SIZE)) return 0; @@ -275,7 +275,7 @@ static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, u static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time) { - uint32_t *p; + __be32 *p; p = xdr_reserve_space(xdr, 12); if (unlikely(p == 0)) @@ -317,7 +317,7 @@ static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) { - uint32_t *p; + __be32 *p; p = xdr_reserve_space(xdr, 8); if (unlikely(p == NULL)) @@ -329,7 +329,7 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) { - uint32_t *savep = NULL; + __be32 *savep = NULL; __be32 status = res->status; if (unlikely(status != 0)) @@ -404,7 +404,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r struct cb_compound_hdr_arg hdr_arg; struct cb_compound_hdr_res hdr_res; struct xdr_stream xdr_in, xdr_out; - uint32_t *p; + __be32 *p; __be32 status; unsigned int nops = 1; @@ -412,7 +412,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); - p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); + p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); xdr_init_encode(&xdr_out, &rqstp->rq_res, p); decode_compound_hdr_arg(&xdr_in, &hdr_arg); -- GitLab From bc4785cd475a11ba125df7af674e16c6ea1cfc30 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:51 -0700 Subject: [PATCH 1584/1619] [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(-) diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3b234d4601e..e5f128ffc32 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 8d09b47c91b..8118036cc44 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 6b2de1be581..45228c1a119 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 ac8058bc8f9..768c1ad5ff6 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; }; -- GitLab From d21ec0c33d0a9eb7a6f6c716008863a97797709e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:52 -0700 Subject: [PATCH 1585/1619] [PATCH] xdr annotations: mount_clnt [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/mount_clnt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index d507b021207..f75fe72b416 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -95,7 +95,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, * XDR encode/decode functions for MOUNT */ static int -xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path) +xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) { p = xdr_encode_string(p, path); @@ -104,7 +104,7 @@ xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path) } static int -xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) +xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) { struct nfs_fh *fh = res->fh; @@ -116,7 +116,7 @@ xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) } static int -xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) +xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) { struct nfs_fh *fh = res->fh; -- GitLab From 83bbe2ef63ec4f6a22aaaa0c03bd918b38300127 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:53 -0700 Subject: [PATCH 1586/1619] [PATCH] nfs_common 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/nfs_common/nfsacl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index 0c2be8c0307..c11f5375d7c 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c @@ -46,7 +46,7 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) { struct nfsacl_encode_desc *nfsacl_desc = (struct nfsacl_encode_desc *) desc; - u32 *p = (u32 *) elem; + __be32 *p = elem; struct posix_acl_entry *entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; @@ -127,7 +127,7 @@ xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem) { struct nfsacl_decode_desc *nfsacl_desc = (struct nfsacl_decode_desc *) desc; - u32 *p = (u32 *) elem; + __be32 *p = elem; struct posix_acl_entry *entry; if (!nfsacl_desc->acl) { -- GitLab From 63f103111fdfc3cba00e4c94921d32362f375d93 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:54 -0700 Subject: [PATCH 1587/1619] [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(-) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 09030afd724..03ab6822291 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 6e78ea969f4..27666f5b8b5 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; -- GitLab From 83b11340d683a67a77e35a5ffb5ad4afbf0be4e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:55 -0700 Subject: [PATCH 1588/1619] [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(-) diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 501d8388453..727ab3bd450 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 069257ea99a..749bad1ca16 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 * -- GitLab From ad451d389f46f699832da3e9ad95f610cb8c0fd2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:55 -0700 Subject: [PATCH 1589/1619] [PATCH] xdr annotations: nfsd_dispatch() 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/nfssvc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 013b38996e6..8067118b1c0 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -495,8 +495,8 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) { struct svc_procedure *proc; kxdrproc_t xdr; - u32 nfserr; - u32 *nfserrp; + __be32 nfserr; + __be32 *nfserrp; dprintk("nfsd_dispatch: vers %d proc %d\n", rqstp->rq_vers, rqstp->rq_proc); @@ -515,7 +515,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) /* Decode arguments */ xdr = proc->pc_decode; - if (xdr && !xdr(rqstp, (u32*)rqstp->rq_arg.head[0].iov_base, + if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base, rqstp->rq_argp)) { dprintk("nfsd: failed to decode arguments!\n"); nfsd_cache_update(rqstp, RC_NOCACHE, NULL); @@ -528,7 +528,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) */ nfserrp = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; - rqstp->rq_res.head[0].iov_len += sizeof(u32); + rqstp->rq_res.head[0].iov_len += sizeof(__be32); /* Now call the procedure handler, and encode NFS status. */ nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); -- GitLab From 131a21c2177c267ab259fcd06947c6f593a7de8e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:56 -0700 Subject: [PATCH 1590/1619] [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(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 8d48616882c..fd5397d8c62 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 1135c0d1455..56ebb1443e0 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 d0d4aae7085..2f75160a582 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 0e53de87d88..877192d3ae7 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 */ -- GitLab From 91f07168cef8e99dd16f608fbc703e7a5af0237f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:57 -0700 Subject: [PATCH 1591/1619] [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(-) diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index ed6e2c27b5e..78b2c83d00c 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 247d518248b..b4baca3053c 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 474d882dc2f..79963867b0d 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 */ -- GitLab From 2ebbc012a9433a252be7ab4ce54e94bf7b21e506 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:58 -0700 Subject: [PATCH 1592/1619] [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(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 795ad6c5cb2..ca641424852 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 77be0c4785e..3419d99aeb1 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 66e642762a0..003193fe6fc 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); -- GitLab From 6264d69d7df654ca64f625e9409189a0e50734e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:58 -0700 Subject: [PATCH 1593/1619] [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(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 1141bd29e4e..f21e917bb8e 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 2f75160a582..19a3c83d496 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) -- GitLab From b37ad28bcaa7c486a4ff0fb6c3bdaaacd67b86ce Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:59 -0700 Subject: [PATCH 1594/1619] [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(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ca641424852..63823945f97 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 1cbd2e4ee12..e9d07704680 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 ebcf226a9e4..e5ca6d7028d 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 3419d99aeb1..d7b630f1a9a 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 8bf23cf8b60..a597e2e7246 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 003193fe6fc..45ca01b5f84 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 -- GitLab From c4d987ba841dff4b2fc768e52d1d95af83f9f157 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:00 -0700 Subject: [PATCH 1595/1619] [PATCH] nfsd: NFSv{2,3} trivial endianness annotations for 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/nfs2acl.c | 6 +++--- fs/nfsd/nfs3acl.c | 4 ++-- fs/nfsd/nfs3proc.c | 46 +++++++++++++++++++++++++--------------------- fs/nfsd/nfsproc.c | 40 +++++++++++++++++++++------------------- 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index fd5397d8c62..e3eca081698 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -35,7 +35,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, { svc_fh *fh; struct posix_acl *acl; - int nfserr = 0; + __be32 nfserr = 0; dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); @@ -102,7 +102,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, struct nfsd_attrstat *resp) { svc_fh *fh; - int nfserr = 0; + __be32 nfserr = 0; dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); @@ -143,7 +143,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp, static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", SVCFH_fmt(&argp->fh), diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 78b2c83d00c..fcad2895ddb 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -33,7 +33,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, { svc_fh *fh; struct posix_acl *acl; - int nfserr = 0; + __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) @@ -98,7 +98,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_attrstat *resp) { svc_fh *fh; - int nfserr = 0; + __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index a12663fdfe1..64db601c2bd 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -56,7 +56,8 @@ static __be32 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, struct nfsd3_attrstat *resp) { - int err, nfserr; + int err; + __be32 nfserr; dprintk("nfsd: GETATTR(3) %s\n", SVCFH_fmt(&argp->fh)); @@ -80,7 +81,7 @@ static __be32 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, struct nfsd3_attrstat *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: SETATTR(3) %s\n", SVCFH_fmt(&argp->fh)); @@ -98,7 +99,7 @@ static __be32 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_diropres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: LOOKUP(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -122,7 +123,7 @@ static __be32 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: ACCESS(3) %s 0x%x\n", SVCFH_fmt(&argp->fh), @@ -141,7 +142,7 @@ static __be32 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, struct nfsd3_readlinkres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); @@ -159,7 +160,7 @@ static __be32 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, struct nfsd3_readres *resp) { - int nfserr; + __be32 nfserr; u32 max_blocksize = svc_max_payload(rqstp); dprintk("nfsd: READ(3) %s %lu bytes at %lu\n", @@ -199,7 +200,7 @@ static __be32 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, struct nfsd3_writeres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n", SVCFH_fmt(&argp->fh), @@ -229,7 +230,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, { svc_fh *dirfhp, *newfhp = NULL; struct iattr *attr; - u32 nfserr; + __be32 nfserr; dprintk("nfsd: CREATE(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -269,7 +270,7 @@ static __be32 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, struct nfsd3_diropres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: MKDIR(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -289,7 +290,7 @@ static __be32 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, struct nfsd3_diropres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n", SVCFH_fmt(&argp->ffh), @@ -311,7 +312,8 @@ static __be32 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, struct nfsd3_diropres *resp) { - int nfserr, type; + __be32 nfserr; + int type; dev_t rdev = 0; dprintk("nfsd: MKNOD(3) %s %.*s\n", @@ -347,7 +349,7 @@ static __be32 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: REMOVE(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -367,7 +369,7 @@ static __be32 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: RMDIR(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -383,7 +385,7 @@ static __be32 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, struct nfsd3_renameres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: RENAME(3) %s %.*s ->\n", SVCFH_fmt(&argp->ffh), @@ -405,7 +407,7 @@ static __be32 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, struct nfsd3_linkres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: LINK(3) %s ->\n", SVCFH_fmt(&argp->ffh)); @@ -428,7 +430,8 @@ static __be32 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, struct nfsd3_readdirres *resp) { - int nfserr, count; + __be32 nfserr; + int count; dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), @@ -463,7 +466,8 @@ static __be32 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, struct nfsd3_readdirres *resp) { - int nfserr, count = 0; + __be32 nfserr; + int count = 0; loff_t offset; int i; caddr_t page_addr = NULL; @@ -521,7 +525,7 @@ static __be32 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsstatres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: FSSTAT(3) %s\n", SVCFH_fmt(&argp->fh)); @@ -538,7 +542,7 @@ static __be32 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsinfores *resp) { - int nfserr; + __be32 nfserr; u32 max_blocksize = svc_max_payload(rqstp); dprintk("nfsd: FSINFO(3) %s\n", @@ -580,7 +584,7 @@ static __be32 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_pathconfres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: PATHCONF(3) %s\n", SVCFH_fmt(&argp->fh)); @@ -623,7 +627,7 @@ static __be32 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, struct nfsd3_commitres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: COMMIT(3) %s %u@%Lu\n", SVCFH_fmt(&argp->fh), diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 03ab6822291..ec983b77768 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -36,16 +36,16 @@ nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) return nfs_ok; } -static int -nfsd_return_attrs(int err, struct nfsd_attrstat *resp) +static __be32 +nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp) { if (err) return err; return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, resp->fh.fh_dentry, &resp->stat)); } -static int -nfsd_return_dirop(int err, struct nfsd_diropres *resp) +static __be32 +nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp) { if (err) return err; return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, @@ -60,7 +60,7 @@ static __be32 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); @@ -76,7 +76,7 @@ static __be32 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, struct nfsd_attrstat *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", SVCFH_fmt(&argp->fh), argp->attrs.ia_valid, (long) argp->attrs.ia_size); @@ -96,7 +96,7 @@ static __be32 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, struct nfsd_diropres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: LOOKUP %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); @@ -116,7 +116,7 @@ static __be32 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp, struct nfsd_readlinkres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); @@ -136,7 +136,7 @@ static __be32 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, struct nfsd_readres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: READ %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), @@ -176,7 +176,7 @@ static __be32 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, struct nfsd_attrstat *resp) { - int nfserr; + __be32 nfserr; int stable = 1; dprintk("nfsd: WRITE %s %d bytes at %d\n", @@ -206,7 +206,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct iattr *attr = &argp->attrs; struct inode *inode; struct dentry *dchild; - int nfserr, type, mode; + int type, mode; + __be32 nfserr; dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); dprintk("nfsd: CREATE %s %.*s\n", @@ -352,7 +353,7 @@ static __be32 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, void *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); @@ -367,7 +368,7 @@ static __be32 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp, void *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: RENAME %s %.*s -> \n", SVCFH_fmt(&argp->ffh), argp->flen, argp->fname); @@ -385,7 +386,7 @@ static __be32 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp, void *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: LINK %s ->\n", SVCFH_fmt(&argp->ffh)); @@ -406,7 +407,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, void *resp) { struct svc_fh newfh; - int nfserr; + __be32 nfserr; dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n", SVCFH_fmt(&argp->ffh), argp->flen, argp->fname, @@ -434,7 +435,7 @@ static __be32 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct nfsd_diropres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); @@ -458,7 +459,7 @@ static __be32 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, void *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); @@ -474,7 +475,8 @@ static __be32 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, struct nfsd_readdirres *resp) { - int nfserr, count; + int count; + __be32 nfserr; loff_t offset; dprintk("nfsd: READDIR %s %d bytes at %d\n", @@ -513,7 +515,7 @@ static __be32 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd_statfsres *resp) { - int nfserr; + __be32 nfserr; dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); -- GitLab From b8dd7b9ab194d9ab322881f49fde42954757efae Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:01 -0700 Subject: [PATCH 1596/1619] [PATCH] nfsd: NFSv4 errno 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/nfs4state.c | 15 +++++++++------ fs/nfsd/nfs4xdr.c | 42 ++++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e5ca6d7028d..ae1d47715b9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2646,6 +2646,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct file_lock conflock; __be32 status = 0; unsigned int strhashval; + int err; dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", (long long) lock->lk_offset, @@ -2758,13 +2759,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock * locks_copy_lock: */ conflock.fl_ops = NULL; conflock.fl_lmops = NULL; - status = posix_lock_file_conf(filp, &file_lock, &conflock); + err = posix_lock_file_conf(filp, &file_lock, &conflock); dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status); - switch (-status) { + switch (-err) { case 0: /* success! */ update_stateid(&lock_stp->st_stateid); memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, sizeof(stateid_t)); + status = 0; break; case (EAGAIN): /* conflock holds conflicting lock */ status = nfserr_denied; @@ -2775,7 +2777,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock status = nfserr_deadlock; break; default: - dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",status); + dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err); status = nfserr_resource; break; } @@ -2880,6 +2882,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct file *filp = NULL; struct file_lock file_lock; __be32 status; + int err; dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", (long long) locku->lu_offset, @@ -2917,8 +2920,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock /* * Try to unlock the file in the VFS. */ - status = posix_lock_file(filp, &file_lock); - if (status) { + err = posix_lock_file(filp, &file_lock); + if (err) { dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); goto out_nfserr; } @@ -2937,7 +2940,7 @@ out: return status; out_nfserr: - status = nfserrno(status); + status = nfserrno(err); goto out; } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d7b630f1a9a..f3f239db04b 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -247,6 +247,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia int expected_len, len = 0; u32 dummy32; char *buf; + int host_err; DECODE_HEAD; iattr->ia_valid = 0; @@ -280,7 +281,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia *acl = nfs4_acl_new(); if (*acl == NULL) { - status = -ENOMEM; + host_err = -ENOMEM; goto out_nfserr; } defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl); @@ -295,20 +296,20 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia len += XDR_QUADLEN(dummy32) << 2; READMEM(buf, dummy32); ace.whotype = nfs4_acl_get_whotype(buf, dummy32); - status = 0; + host_err = 0; if (ace.whotype != NFS4_ACL_WHO_NAMED) ace.who = 0; else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP) - status = nfsd_map_name_to_gid(argp->rqstp, + host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &ace.who); else - status = nfsd_map_name_to_uid(argp->rqstp, + host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &ace.who); - if (status) + if (host_err) goto out_nfserr; - status = nfs4_acl_add_ace(*acl, ace.type, ace.flag, + host_err = nfs4_acl_add_ace(*acl, ace.type, ace.flag, ace.access_mask, ace.whotype, ace.who); - if (status) + if (host_err) goto out_nfserr; } } else @@ -327,7 +328,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia READ_BUF(dummy32); len += (XDR_QUADLEN(dummy32) << 2); READMEM(buf, dummy32); - if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) + if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) goto out_nfserr; iattr->ia_valid |= ATTR_UID; } @@ -338,7 +339,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia READ_BUF(dummy32); len += (XDR_QUADLEN(dummy32) << 2); READMEM(buf, dummy32); - if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) + if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) goto out_nfserr; iattr->ia_valid |= ATTR_GID; } @@ -414,7 +415,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia DECODE_TAIL; out_nfserr: - status = nfserrno(status); + status = nfserrno(host_err); goto out; } @@ -1438,6 +1439,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u32 rdattr_err = 0; __be32 *p = buffer; __be32 status; + int err; int aclsupport = 0; struct nfs4_acl *acl = NULL; @@ -1451,14 +1453,14 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, goto out; } - status = vfs_getattr(exp->ex_mnt, dentry, &stat); - if (status) + err = vfs_getattr(exp->ex_mnt, dentry, &stat); + if (err) goto out_nfserr; if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { - status = vfs_statfs(dentry, &statfs); - if (status) + err = vfs_statfs(dentry, &statfs); + if (err) goto out_nfserr; } if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { @@ -1470,15 +1472,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, } if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_SUPPORTED_ATTRS)) { - status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); - aclsupport = (status == 0); + err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); + aclsupport = (err == 0); if (bmval0 & FATTR4_WORD0_ACL) { - if (status == -EOPNOTSUPP) + if (err == -EOPNOTSUPP) bmval0 &= ~FATTR4_WORD0_ACL; - else if (status == -EINVAL) { + else if (err == -EINVAL) { status = nfserr_attrnotsupp; goto out; - } else if (status != 0) + } else if (err != 0) goto out_nfserr; } } @@ -1818,7 +1820,7 @@ out: fh_put(&tempfh); return status; out_nfserr: - status = nfserrno(status); + status = nfserrno(err); goto out; out_resource: *countp = 0; -- GitLab From f00f328fda1eeec575cd0f360da81b66bf4133a1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:01 -0700 Subject: [PATCH 1597/1619] [PATCH] xdr annotations: nfsd callback* 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/nfs4callback.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 324a278f280..8497ed4862b 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -85,8 +85,8 @@ enum nfs_cb_opnum4 { /* * Generic encode routines from fs/nfs/nfs4xdr.c */ -static inline u32 * -xdr_writemem(u32 *p, const void *ptr, int nbytes) +static inline __be32 * +xdr_writemem(__be32 *p, const void *ptr, int nbytes) { int tmp = XDR_QUADLEN(nbytes); if (!tmp) @@ -205,7 +205,7 @@ nfs_cb_stat_to_errno(int stat) static int encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) { - u32 * p; + __be32 * p; RESERVE_SPACE(16); WRITE32(0); /* tag length is always 0 */ @@ -218,7 +218,7 @@ encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) static int encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) { - u32 *p; + __be32 *p; int len = cb_rec->cbr_fhlen; RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); @@ -231,7 +231,7 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) } static int -nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p) +nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) { struct xdr_stream xdrs, *xdr = &xdrs; @@ -241,7 +241,7 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p) } static int -nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args) +nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) { struct xdr_stream xdr; struct nfs4_cb_compound_hdr hdr = { @@ -257,7 +257,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args static int decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ - u32 *p; + __be32 *p; READ_BUF(8); READ32(hdr->status); @@ -272,7 +272,7 @@ decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) static int decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) { - u32 *p; + __be32 *p; u32 op; int32_t nfserr; @@ -291,13 +291,13 @@ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) } static int -nfs4_xdr_dec_cb_null(struct rpc_rqst *req, u32 *p) +nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) { return 0; } static int -nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p) +nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p) { struct xdr_stream xdr; struct nfs4_cb_compound_hdr hdr; -- GitLab From c7afef1f963bec198b186cc34b9e8c9b9ce2e266 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:02 -0700 Subject: [PATCH 1598/1619] [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(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index e13fa23bd10..f37df46d2ea 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 9b9e7e127c0..11fdaf7721b 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 8497ed4862b..f57655a7a2b 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 ae1d47715b9..2e468c9e64d 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 fdf7cf3dfad..6100bbe2743 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 8067118b1c0..0aaccb03bf7 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 c3a3557c2a5..007480cd6a6 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 27666f5b8b5..045e38cdbe6 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 19a3c83d496..68d29b66c6e 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 749bad1ca16..f3b51d62ec7 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 a597e2e7246..c3673f487e8 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 */ -- GitLab From a90b061c0bf712961cea40d9c916b300073d12e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:03 -0700 Subject: [PATCH 1599/1619] [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(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 63823945f97..0a7bbdc4a10 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 2e468c9e64d..293b6495829 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 68d29b66c6e..eb231143d57 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. -- GitLab From e51959faa61278c762389802faf8ba1a40676628 Mon Sep 17 00:00:00 2001 From: Zachary Amsden Date: Thu, 19 Oct 2006 23:29:04 -0700 Subject: [PATCH 1600/1619] [PATCH] Fix potential interrupts during alternative patching Interrupts must be disabled during alternative instruction patching. On systems with high timer IRQ rates, or when running in an emulator, timing differences can result in random kernel panics because of running partially patched instructions. This doesn't yet fix NMIs, which requires extricating the patch code from the late bug checking and is logically separate (and also less likely to cause problems). Signed-off-by: Zachary Amsden Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/alternative.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c index 28ab8064976..583c238e17f 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c @@ -344,6 +344,7 @@ void alternatives_smp_switch(int smp) void __init alternative_instructions(void) { + unsigned long flags; if (no_replacement) { printk(KERN_INFO "(SMP-)alternatives turned off\n"); free_init_pages("SMP alternatives", @@ -351,6 +352,8 @@ void __init alternative_instructions(void) (unsigned long)__smp_alt_end); return; } + + local_irq_save(flags); apply_alternatives(__alt_instructions, __alt_instructions_end); /* switch to patch-once-at-boottime-only mode and free the @@ -386,4 +389,5 @@ void __init alternative_instructions(void) alternatives_smp_switch(0); } #endif + local_irq_restore(flags); } -- GitLab From 6220ec7844fda2686496013a66b5b9169976b991 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Oct 2006 23:29:05 -0700 Subject: [PATCH 1601/1619] [PATCH] highest_possible_node_id() linkage fix Qooting Adrian: - net/sunrpc/svc.c uses highest_possible_node_id() - include/linux/nodemask.h says highest_possible_node_id() is out-of-line #if MAX_NUMNODES > 1 - the out-of-line highest_possible_node_id() is in lib/cpumask.c - lib/Makefile: lib-$(CONFIG_SMP) += cpumask.o CONFIG_ARCH_DISCONTIGMEM_ENABLE=y, CONFIG_SMP=n, CONFIG_SUNRPC=y -> highest_possible_node_id() is used in net/sunrpc/svc.c CONFIG_NODES_SHIFT defined and > 0 -> include/linux/numa.h: MAX_NUMNODES > 1 -> compile error The bug is not present on architectures where ARCH_DISCONTIGMEM_ENABLE depends on NUMA (but m32r isn't the only affected architecture). So move the function into page_alloc.c Cc: Adrian Bunk Cc: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/cpumask.c | 16 ---------------- mm/page_alloc.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/cpumask.c b/lib/cpumask.c index 7a2a73f88d5..3a67dc5ada7 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -43,19 +43,3 @@ 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 diff --git a/mm/page_alloc.c b/mm/page_alloc.c index afee38f04d8..ebd425c2e2a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3120,3 +3120,19 @@ unsigned long page_to_pfn(struct page *page) EXPORT_SYMBOL(pfn_to_page); EXPORT_SYMBOL(page_to_pfn); #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */ + +#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 -- GitLab From fca4edb48b693d9df7de4c42d91b4158d8b7e347 Mon Sep 17 00:00:00 2001 From: Amol Lad Date: Thu, 19 Oct 2006 23:29:06 -0700 Subject: [PATCH 1602/1619] [PATCH] drivers/isdn: ioremap balanced with iounmap ioremap must be balanced by an iounmap and failing to do so can result in a memory leak. Signed-off-by: Amol Lad Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hisax/diva.c | 26 ++++++++++++++++++++++++-- drivers/isdn/hysdn/boardergo.c | 2 +- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 7e95f04f13d..3dacfff93f5 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -716,8 +716,10 @@ release_io_diva(struct IsdnCardState *cs) *cfg = 0; /* disable INT0/1 */ *cfg = 2; /* reset pending INT0 */ - iounmap((void *)cs->hw.diva.cfg_reg); - iounmap((void *)cs->hw.diva.pci_cfg); + if (cs->hw.diva.cfg_reg) + iounmap((void *)cs->hw.diva.cfg_reg); + if (cs->hw.diva.pci_cfg) + iounmap((void *)cs->hw.diva.pci_cfg); return; } else if (cs->subtyp != DIVA_IPAC_ISA) { del_timer(&cs->hw.diva.tl); @@ -733,6 +735,23 @@ release_io_diva(struct IsdnCardState *cs) } } +static void +iounmap_diva(struct IsdnCardState *cs) +{ + if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) { + if (cs->hw.diva.cfg_reg) { + iounmap((void *)cs->hw.diva.cfg_reg); + cs->hw.diva.cfg_reg = 0; + } + if (cs->hw.diva.pci_cfg) { + iounmap((void *)cs->hw.diva.pci_cfg); + cs->hw.diva.pci_cfg = 0; + } + } + + return; +} + static void reset_diva(struct IsdnCardState *cs) { @@ -1069,11 +1088,13 @@ setup_diva(struct IsdnCard *card) if (!cs->irq) { printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + iounmap_diva(cs); return(0); } if (!cs->hw.diva.cfg_reg) { printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + iounmap_diva(cs); return(0); } cs->irq_flags |= IRQF_SHARED; @@ -1123,6 +1144,7 @@ ready: CardType[card->typ], cs->hw.diva.cfg_reg, cs->hw.diva.cfg_reg + bytecnt); + iounmap_diva(cs); return (0); } } diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 8bbe33ae06d..82e42a80dc4 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -403,7 +403,7 @@ ergo_releasehardware(hysdn_card * card) free_irq(card->irq, card); /* release interrupt */ release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */ release_region(card->iobase + PCI9050_USER_IO, 1); - vfree(card->dpram); + iounmap(card->dpram); card->dpram = NULL; /* release shared mem */ } /* ergo_releasehardware */ -- GitLab From ca926e80dcfd18adaf7c4304935da4cc8ded8364 Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Thu, 19 Oct 2006 23:29:06 -0700 Subject: [PATCH 1603/1619] [PATCH] doc: fixing cpu-hotplug documentation Fixing cpu-hotplug documentation as follows: - moving confusing asterisk on additional_cpus descrition - fixing some typos - unifying indentation for source code and command line example Signed-off-by: Satoru Takeuchi Cc: Ashok Raj Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpu-hotplug.txt | 148 +++++++++++++++++----------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt index bc107cb157a..4868c34f750 100644 --- a/Documentation/cpu-hotplug.txt +++ b/Documentation/cpu-hotplug.txt @@ -46,7 +46,7 @@ maxcpus=n Restrict boot time cpus to n. Say if you have 4 cpus, using maxcpus=2 will only boot 2. You can choose to bring the other cpus later online, read FAQ's for more info. -additional_cpus*=n Use this to limit hotpluggable cpus. This option sets +additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets cpu_possible_map = cpu_present_map + additional_cpus (*) Option valid only for following architectures @@ -101,15 +101,15 @@ cpu_possible_map/for_each_possible_cpu() to iterate. Never use anything other than cpumask_t to represent bitmap of CPUs. -#include + #include -for_each_possible_cpu - Iterate over cpu_possible_map -for_each_online_cpu - Iterate over cpu_online_map -for_each_present_cpu - Iterate over cpu_present_map -for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask. + for_each_possible_cpu - Iterate over cpu_possible_map + for_each_online_cpu - Iterate over cpu_online_map + for_each_present_cpu - Iterate over cpu_present_map + for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask. -#include -lock_cpu_hotplug() and unlock_cpu_hotplug(): + #include + lock_cpu_hotplug() and unlock_cpu_hotplug(): The above calls are used to inhibit cpu hotplug operations. While holding the cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid @@ -120,7 +120,7 @@ will work as long as stop_machine_run() is used to take a cpu down. CPU Hotplug - Frequently Asked Questions. -Q: How to i enable my kernel to support CPU hotplug? +Q: How to enable my kernel to support CPU hotplug? A: When doing make defconfig, Enable CPU hotplug support "Processor type and Features" -> Support for Hotpluggable CPUs @@ -141,39 +141,39 @@ A: You should now notice an entry in sysfs. Check if sysfs is mounted, using the "mount" command. You should notice an entry as shown below in the output. -.... -none on /sys type sysfs (rw) -.... + .... + none on /sys type sysfs (rw) + .... -if this is not mounted, do the following. +If this is not mounted, do the following. -#mkdir /sysfs -#mount -t sysfs sys /sys + #mkdir /sysfs + #mount -t sysfs sys /sys -now you should see entries for all present cpu, the following is an example +Now you should see entries for all present cpu, the following is an example in a 8-way system. -#pwd -#/sys/devices/system/cpu -#ls -l -total 0 -drwxr-xr-x 10 root root 0 Sep 19 07:44 . -drwxr-xr-x 13 root root 0 Sep 19 07:45 .. -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0 -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1 -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2 -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3 -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4 -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5 -drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6 -drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7 + #pwd + #/sys/devices/system/cpu + #ls -l + total 0 + drwxr-xr-x 10 root root 0 Sep 19 07:44 . + drwxr-xr-x 13 root root 0 Sep 19 07:45 .. + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0 + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1 + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2 + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3 + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4 + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5 + drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6 + drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7 Under each directory you would find an "online" file which is the control file to logically online/offline a processor. Q: Does hot-add/hot-remove refer to physical add/remove of cpus? A: The usage of hot-add/remove may not be very consistently used in the code. -CONFIG_CPU_HOTPLUG enables logical online/offline capability in the kernel. +CONFIG_HOTPLUG_CPU enables logical online/offline capability in the kernel. To support physical addition/removal, one would need some BIOS hooks and the platform should have something like an attention button in PCI hotplug. CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs. @@ -181,17 +181,17 @@ CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs. Q: How do i logically offline a CPU? A: Do the following. -#echo 0 > /sys/devices/system/cpu/cpuX/online + #echo 0 > /sys/devices/system/cpu/cpuX/online -once the logical offline is successful, check +Once the logical offline is successful, check -#cat /proc/interrupts + #cat /proc/interrupts -you should now not see the CPU that you removed. Also online file will report +You should now not see the CPU that you removed. Also online file will report the state as 0 when a cpu if offline and 1 when its online. -#To display the current cpu state. -#cat /sys/devices/system/cpu/cpuX/online + #To display the current cpu state. + #cat /sys/devices/system/cpu/cpuX/online Q: Why cant i remove CPU0 on some systems? A: Some architectures may have some special dependency on a certain CPU. @@ -234,8 +234,8 @@ Q: If i have some kernel code that needs to be aware of CPU arrival and departure, how to i arrange for proper notification? A: This is what you would need in your kernel code to receive notifications. - #include - static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb, + #include + static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; @@ -279,10 +279,10 @@ Q: I don't see my action being called for all CPUs already up and running? A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined. If you need to perform some action for each cpu already in the system, then - for_each_online_cpu(i) { + for_each_online_cpu(i) { foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i); - foobar_cpu_callback(&foobar-cpu_notifier, CPU_ONLINE, i); - } + foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i); + } Q: If i would like to develop cpu hotplug support for a new architecture, what do i need at a minimum? @@ -307,38 +307,38 @@ Q: I need to ensure that a particular cpu is not removed when there is some work specific to this cpu is in progress. A: First switch the current thread context to preferred cpu - int my_func_on_cpu(int cpu) - { - cpumask_t saved_mask, new_mask = CPU_MASK_NONE; - int curr_cpu, err = 0; - - saved_mask = current->cpus_allowed; - cpu_set(cpu, new_mask); - err = set_cpus_allowed(current, new_mask); - - if (err) - return err; - - /* - * If we got scheduled out just after the return from - * set_cpus_allowed() before running the work, this ensures - * we stay locked. - */ - curr_cpu = get_cpu(); - - if (curr_cpu != cpu) { - err = -EAGAIN; - goto ret; - } else { - /* - * Do work : But cant sleep, since get_cpu() disables preempt - */ - } - ret: - put_cpu(); - set_cpus_allowed(current, saved_mask); - return err; - } + int my_func_on_cpu(int cpu) + { + cpumask_t saved_mask, new_mask = CPU_MASK_NONE; + int curr_cpu, err = 0; + + saved_mask = current->cpus_allowed; + cpu_set(cpu, new_mask); + err = set_cpus_allowed(current, new_mask); + + if (err) + return err; + + /* + * If we got scheduled out just after the return from + * set_cpus_allowed() before running the work, this ensures + * we stay locked. + */ + curr_cpu = get_cpu(); + + if (curr_cpu != cpu) { + err = -EAGAIN; + goto ret; + } else { + /* + * Do work : But cant sleep, since get_cpu() disables preempt + */ + } + ret: + put_cpu(); + set_cpus_allowed(current, saved_mask); + return err; + } Q: How do we determine how many CPUs are available for hotplug. -- GitLab From c4ec7b0de4bc18ccb4380de638550984d9a65c25 Mon Sep 17 00:00:00 2001 From: Dmitriy Monakhov Date: Thu, 19 Oct 2006 23:29:08 -0700 Subject: [PATCH 1604/1619] [PATCH] mm: D-cache aliasing issue in cow_user_page --=-=-= from mm/memory.c: 1434 static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va) 1435 { 1436 /* 1437 * If the source page was a PFN mapping, we don't have 1438 * a "struct page" for it. We do a best-effort copy by 1439 * just copying from the original user address. If that 1440 * fails, we just zero-fill it. Live with it. 1441 */ 1442 if (unlikely(!src)) { 1443 void *kaddr = kmap_atomic(dst, KM_USER0); 1444 void __user *uaddr = (void __user *)(va & PAGE_MASK); 1445 1446 /* 1447 * This really shouldn't fail, because the page is there 1448 * in the page tables. But it might just be unreadable, 1449 * in which case we just give up and fill the result with 1450 * zeroes. 1451 */ 1452 if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) 1453 memset(kaddr, 0, PAGE_SIZE); 1454 kunmap_atomic(kaddr, KM_USER0); #### D-cache have to be flushed here. #### It seems it is just forgotten. 1455 return; 1456 1457 } 1458 copy_user_highpage(dst, src, va); #### Ok here. flush_dcache_page() called from this func if arch need it 1459 } Following is the patch fix this issue: Signed-off-by: Dmitriy Monakhov Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/memory.c b/mm/memory.c index b5a4aadd961..156861fcac4 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1452,6 +1452,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) memset(kaddr, 0, PAGE_SIZE); kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(dst); return; } -- GitLab From 1cd441f99819abdd2d919ff13e8c75af58a0fd9c Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 19 Oct 2006 23:29:09 -0700 Subject: [PATCH 1605/1619] [PATCH] ipmi: fix return codes in failure case These returns should be negative, like the others in this function. Signed-off-by: Dave Jones Acked-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 24825bdca8f..e5cfb1fa47d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1789,7 +1789,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) - return ENOMEM; + return -ENOMEM; info->addr_source = "PCI"; @@ -1810,7 +1810,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, kfree(info); printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n", pci_name(pdev), class_type); - return ENOMEM; + return -ENOMEM; } rv = pci_enable_device(pdev); -- GitLab From b95936cb9267e4c90a0b92361609ef5fd85a0a5f Mon Sep 17 00:00:00 2001 From: Doug Warzecha Date: Thu, 19 Oct 2006 23:29:09 -0700 Subject: [PATCH 1606/1619] [PATCH] firmware/dcdbas: add size check in smi_data_write Add a size check in smi_data_write to prevent possible wrapping problems with large pos values when calling smi_data_buf_realloc on 32-bit. Signed-off-by: Doug Warzecha Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/dcdbas.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 8bcb58cd4ac..1865b56fb14 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -8,7 +8,7 @@ * * See Documentation/dcdbas.txt for more information. * - * Copyright (C) 1995-2005 Dell Inc. + * Copyright (C) 1995-2006 Dell Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License v2.0 as published by @@ -40,7 +40,7 @@ #include "dcdbas.h" #define DRIVER_NAME "dcdbas" -#define DRIVER_VERSION "5.6.0-2" +#define DRIVER_VERSION "5.6.0-3.2" #define DRIVER_DESCRIPTION "Dell Systems Management Base Driver" static struct platform_device *dcdbas_pdev; @@ -175,6 +175,9 @@ static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos, { ssize_t ret; + if ((pos + count) > MAX_SMI_DATA_BUF_SIZE) + return -EINVAL; + mutex_lock(&smi_data_lock); ret = smi_data_buf_realloc(pos + count); -- GitLab From 82591e6ea234762eeaa8b2337fe060ed438c18dc Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Thu, 19 Oct 2006 23:29:10 -0700 Subject: [PATCH 1607/1619] [PATCH] mm: more commenting on lock ordering Clarify lockorder comments now that sys_msync dropps mmap_sem before calling do_fsync. Signed-off-by: Nick Piggin Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/filemap.c | 4 ++-- mm/rmap.c | 36 +++++++++++++++--------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 57faa8d1209..8558732e85c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -75,8 +75,8 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, * ->mmap_sem * ->lock_page (access_process_vm) * - * ->mmap_sem - * ->i_mutex (msync) + * ->i_mutex (generic_file_buffered_write) + * ->mmap_sem (fault_in_pages_readable->do_page_fault) * * ->i_mutex * ->i_alloc_sem (various) diff --git a/mm/rmap.c b/mm/rmap.c index a9136d8b757..d8a842a586d 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -21,27 +21,21 @@ * Lock ordering in mm: * * inode->i_mutex (while writing or truncating, not reading or faulting) - * inode->i_alloc_sem - * - * When a page fault occurs in writing from user to file, down_read - * of mmap_sem nests within i_mutex; in sys_msync, i_mutex nests within - * down_read of mmap_sem; i_mutex and down_write of mmap_sem are never - * taken together; in truncation, i_mutex is taken outermost. - * - * mm->mmap_sem - * page->flags PG_locked (lock_page) - * mapping->i_mmap_lock - * anon_vma->lock - * mm->page_table_lock or pte_lock - * zone->lru_lock (in mark_page_accessed, isolate_lru_page) - * swap_lock (in swap_duplicate, swap_info_get) - * mmlist_lock (in mmput, drain_mmlist and others) - * mapping->private_lock (in __set_page_dirty_buffers) - * inode_lock (in set_page_dirty's __mark_inode_dirty) - * sb_lock (within inode_lock in fs/fs-writeback.c) - * mapping->tree_lock (widely used, in set_page_dirty, - * in arch-dependent flush_dcache_mmap_lock, - * within inode_lock in __sync_single_inode) + * inode->i_alloc_sem (vmtruncate_range) + * mm->mmap_sem + * page->flags PG_locked (lock_page) + * mapping->i_mmap_lock + * anon_vma->lock + * mm->page_table_lock or pte_lock + * zone->lru_lock (in mark_page_accessed, isolate_lru_page) + * swap_lock (in swap_duplicate, swap_info_get) + * mmlist_lock (in mmput, drain_mmlist and others) + * mapping->private_lock (in __set_page_dirty_buffers) + * inode_lock (in set_page_dirty's __mark_inode_dirty) + * sb_lock (within inode_lock in fs/fs-writeback.c) + * mapping->tree_lock (widely used, in set_page_dirty, + * in arch-dependent flush_dcache_mmap_lock, + * within inode_lock in __sync_single_inode) */ #include -- GitLab From 3e2a532b26b491706bd8b5c7cfc8d767b43b8f36 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 19 Oct 2006 23:29:11 -0700 Subject: [PATCH 1608/1619] [PATCH] ext3/4: fix J_ASSERT(transaction->t_updates > 0) in journal_stop() A disk generated some I/O error, after it, I hitted J_ASSERT(transaction->t_updates > 0) in journal_stop(). It seems to happened on ext3_truncate() path from stack trace. Then, maybe the following case may trigger J_ASSERT(transaction->t_updates > 0). ext3_truncate() -> ext3_free_branches() -> ext3_journal_test_restart() -> ext3_journal_restart() -> journal_restart() transaction->t_updates--; /* another process aborted journal */ -> start_this_handle() returns -EROFS without transaction->t_updates++; -> ext3_journal_stop() -> journal_stop() J_ASSERT(transaction->t_updates > 0) If journal was aborted in middle of journal_restart(), ext3_truncate() may trigger J_ASSERT(). Signed-off-by: OGAWA Hirofumi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/transaction.c | 5 +++-- fs/jbd2/transaction.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index e1b3c8af4d1..d5c63047a8b 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1314,13 +1314,14 @@ int journal_stop(handle_t *handle) 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 + else { + J_ASSERT(transaction->t_updates > 0); err = 0; + } if (--handle->h_ref > 0) { jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 149957bef90..b6cf2be845a 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1314,13 +1314,14 @@ int jbd2_journal_stop(handle_t *handle) 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 + else { + J_ASSERT(transaction->t_updates > 0); err = 0; + } if (--handle->h_ref > 0) { jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, -- GitLab From e05d722e4555cd54677b4c8431d9e81fd047ef7a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 19 Oct 2006 23:29:12 -0700 Subject: [PATCH 1609/1619] [PATCH] kernel/nsproxy.c: use kmemdup() Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/nsproxy.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 6ebdb82a0ce..674aceb7335 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -44,11 +44,9 @@ 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)); + ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL); + if (ns) atomic_set(&ns->count, 1); - } return ns; } -- GitLab From 1a047060a99f274a7c52cfea8159e4142a14b8a7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 19 Oct 2006 23:29:13 -0700 Subject: [PATCH 1610/1619] [PATCH] knfsd: fix race that can disable NFS server This patch is suitable for just about any 2.6 kernel. It should go in 2.6.19 and 2.6.18.2 and possible even the .17 and .16 stable series. This is a long standing bug that seems to have only recently become apparent, presumably due to increasing use of NFS over TCP - many distros seem to be making it the default. The SK_CONN bit gets set when a listening socket may be ready for an accept, just as SK_DATA is set when data may be available. It is entirely possible for svc_tcp_accept to be called with neither of these set. It doesn't happen often but there is a small race in svc_sock_enqueue as SK_CONN and SK_DATA are tested outside the spin_lock. They could be cleared immediately after the test and before the lock is gained. This normally shouldn't be a problem. The sockets are non-blocking so trying to read() or accept() when ther is nothing to do is not a problem. However: svc_tcp_recvfrom makes the decision "Should I accept() or should I read()" based on whether SK_CONN is set or not. This usually works but is not safe. The decision should be based on whether it is a TCP_LISTEN socket or a TCP_CONNECTED socket. Signed-off-by: Neil Brown Cc: Adrian Bunk Cc: Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/svcsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 61e307cca13..96521f16342 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -973,7 +973,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) return 0; } - if (test_bit(SK_CONN, &svsk->sk_flags)) { + if (svsk->sk_sk->sk_state == TCP_LISTEN) { svc_tcp_accept(svsk); svc_sock_received(svsk); return 0; -- GitLab From ac4e0aba7daf0a7c6ac20974070428481dc940f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 19 Oct 2006 23:29:14 -0700 Subject: [PATCH 1611/1619] [PATCH] one more ARM IRQ fix Fix one more compile breakage caused by the post -rc1 IRQ changes. Signed-off-by: Adrian Bunk Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/mach-lh7a40x/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h index 18e8bb4eb20..0ca20c6c83b 100644 --- a/arch/arm/mach-lh7a40x/common.h +++ b/arch/arm/mach-lh7a40x/common.h @@ -15,4 +15,4 @@ extern void lh7a404_init_irq (void); extern void lh7a40x_clcd_init (void); extern void lh7a40x_init_board_irq (void); -#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs) +#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq)) -- GitLab From b2ef7858db6394b758818358a43c7dd5f232bbcc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Oct 2006 10:40:48 -0700 Subject: [PATCH 1612/1619] Revert "[mv643xx] Add pci device table for auto module loading." This reverts commit 4596c75c23dde2623cbeec69357d5eb13d28387e as requested by Olaf Hering. It causes compile errors, and says Olaf: "This change is also wrong, the autoloading works perfect with 2.6.18, no need to add random PCI ids. See commit a0245f7ad5214cb00131d7cd176446e067c913dc, platform devices have now a modalias entry in sysfs. The network card is not a PCI device." Signed-off-by: Linus Torvalds --- drivers/net/mv643xx_eth.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index a4f861bf32d..9997081c6da 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1557,12 +1557,6 @@ static void __exit mv643xx_cleanup_module(void) module_init(mv643xx_init_module); module_exit(mv643xx_cleanup_module); -static struct pci_device_id pci_marvell_mv64360[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) }, - {} -}; -MODULE_DEVICE_TABLE(pci, pci_marvell_mv64360); - MODULE_LICENSE("GPL"); MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" " and Dale Farnsworth"); -- GitLab From 79cd22d3ac921b9209bf813c7e75e6b69e74896c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 12 Oct 2006 14:29:33 +0900 Subject: [PATCH 1613/1619] ocfs2: delete redundant memcmp() This patch deletes redundant memcmp() while looking up in rb tree. Signed-off-by: Akinbou Mita Signed-off-by: Mark Fasheh --- fs/ocfs2/cluster/nodemanager.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index e1fceb8aa32..d11753c50bc 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -152,14 +152,16 @@ static struct o2nm_node *o2nm_node_ip_tree_lookup(struct o2nm_cluster *cluster, struct o2nm_node *node, *ret = NULL; while (*p) { + int cmp; + parent = *p; node = rb_entry(parent, struct o2nm_node, nd_ip_node); - if (memcmp(&ip_needle, &node->nd_ipv4_address, - sizeof(ip_needle)) < 0) + cmp = memcmp(&ip_needle, &node->nd_ipv4_address, + sizeof(ip_needle)); + if (cmp < 0) p = &(*p)->rb_left; - else if (memcmp(&ip_needle, &node->nd_ipv4_address, - sizeof(ip_needle)) > 0) + else if (cmp > 0) p = &(*p)->rb_right; else { ret = node; -- GitLab From 711a40fcaa83bfad87736544b69f6fdd6527482d Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Wed, 11 Oct 2006 12:23:02 -0700 Subject: [PATCH 1614/1619] ocfs2: remove spurious d_count check in ocfs2_rename() This was causing some folks to incorrectly get -EBUSY during rename. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh --- fs/ocfs2/namei.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 259155f0eb2..a57b751d4f4 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1085,14 +1085,6 @@ static int ocfs2_rename(struct inode *old_dir, BUG(); } - if (atomic_read(&old_dentry->d_count) > 2) { - shrink_dcache_parent(old_dentry); - if (atomic_read(&old_dentry->d_count) > 2) { - status = -EBUSY; - goto bail; - } - } - /* Assume a directory heirarchy thusly: * a/b/c * a/d -- GitLab From 0effef776ff95b7a6d6e48a2ef407ecaa8c21f96 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 3 Oct 2006 17:44:42 -0700 Subject: [PATCH 1615/1619] ocfs2: fix page zeroing during simple extends The page zeroing code was missing the region between old i_size and new i_size for those extends that didn't actually require a change in space allocation. Signed-off-by: Mark Fasheh --- fs/ocfs2/file.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index d9ba0a931a0..b499c329257 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -728,31 +728,36 @@ static int ocfs2_extend_file(struct inode *inode, clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - OCFS2_I(inode)->ip_clusters; - if (clusters_to_add) { - /* - * protect the pages that ocfs2_zero_extend is going to - * be pulling into the page cache.. we do this before the - * metadata extend so that we don't get into the situation - * where we've extended the metadata but can't get the data - * lock to zero. - */ - ret = ocfs2_data_lock(inode, 1); - if (ret < 0) { - mlog_errno(ret); - goto out; - } + /* + * protect the pages that ocfs2_zero_extend is going to be + * pulling into the page cache.. we do this before the + * metadata extend so that we don't get into the situation + * where we've extended the metadata but can't get the data + * lock to zero. + */ + ret = ocfs2_data_lock(inode, 1); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + if (clusters_to_add) { ret = ocfs2_extend_allocation(inode, clusters_to_add); if (ret < 0) { mlog_errno(ret); goto out_unlock; } + } - ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip); - if (ret < 0) { - mlog_errno(ret); - goto out_unlock; - } + /* + * Call this even if we don't add any clusters to the tree. We + * still need to zero the area between the old i_size and the + * new i_size. + */ + ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip); + if (ret < 0) { + mlog_errno(ret); + goto out_unlock; } if (!tail_to_skip) { @@ -764,8 +769,7 @@ static int ocfs2_extend_file(struct inode *inode, } out_unlock: - if (clusters_to_add) /* this is the only case in which we lock */ - ocfs2_data_unlock(inode, 1); + ocfs2_data_unlock(inode, 1); out: return ret; -- GitLab From e2057c5a63821e17c8a54dab6db680c77ce7ee6c Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 3 Oct 2006 17:53:05 -0700 Subject: [PATCH 1616/1619] ocfs2: cond_resched() in ocfs2_zero_extend() The loop within ocfs2_zero_extend() can execute for a long time, causing spurious soft lockup warnings. Signed-off-by: Mark Fasheh --- fs/ocfs2/file.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index b499c329257..1be74c4e781 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -30,6 +30,7 @@ #include #include #include +#include #define MLOG_MASK_PREFIX ML_INODE #include @@ -691,6 +692,12 @@ static int ocfs2_zero_extend(struct inode *inode, } start_off += sb->s_blocksize; + + /* + * Very large extends have the potential to lock up + * the cpu for extended periods of time. + */ + cond_resched(); } out: -- GitLab From 559c9ac391c046710bdeee5581dc5d9dda794881 Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Tue, 10 Oct 2006 15:15:55 -0700 Subject: [PATCH 1617/1619] configfs: handle kzalloc() failure in check_perm() check_perm() does not drop the reference to the module when kzalloc() failure occurs. Signed-Off-By: Chandra Seetharaman Signed-off-by: Joel Becker Signed-off-by: Mark Fasheh --- fs/configfs/file.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/configfs/file.c b/fs/configfs/file.c index e6d5754a715..cf33fac68c8 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -275,13 +275,14 @@ static int check_perm(struct inode * inode, struct file * file) * it in file->private_data for easy access. */ buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL); - if (buffer) { - init_MUTEX(&buffer->sem); - buffer->needs_read_fill = 1; - buffer->ops = ops; - file->private_data = buffer; - } else + if (!buffer) { error = -ENOMEM; + goto Enomem; + } + init_MUTEX(&buffer->sem); + buffer->needs_read_fill = 1; + buffer->ops = ops; + file->private_data = buffer; goto Done; Einval: @@ -289,6 +290,7 @@ static int check_perm(struct inode * inode, struct file * file) goto Done; Eaccess: error = -EACCES; + Enomem: module_put(attr->ca_owner); Done: if (error && item) -- GitLab From e17e31e388b2e49ff1c9a2bdb39d7aeb2975c19a Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 20 Oct 2006 09:23:05 +0200 Subject: [PATCH 1618/1619] [PATCH] Fix up rpaphp driver for pci hotplug header move Use grep instead of make during interface changes. Signed-off-by: Olaf Hering Signed-off-by: Linus Torvalds --- drivers/pci/hotplug/rpaphp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 310b6186c0e..2e7accf0f73 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -28,7 +28,7 @@ #define _PPC64PHP_H #include -#include "pci_hotplug.h" +#include #define DR_INDICATOR 9002 #define DR_ENTITY_SENSE 9003 -- GitLab From c7a3bd177f248d01ee18a01d22048c80e071c331 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 20 Oct 2006 14:20:17 -0700 Subject: [PATCH 1619/1619] [PATCH] fix PXA2xx UDC compilation error This was apparently missed by the move to the generic IRQ code. Signed-off-by: Nicolas Pitre Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/gadget/pxa2xx_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index f42c00ef0bc..671c24bc6d7 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -43,11 +43,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include -- GitLab