LWN.net Logo

atm_dev reference counting

From:  chas williams <chas@cmf.nrl.navy.mil>
To:  davem@redhat.com
Subject:  [patch][2.4] atm_dev reference counting
Date:  Tue, 01 Jul 2003 14:02:32 -0400
Cc:  linux-kernel@vger.kernel.org

this is a back port from 2.5.

[atm]: add reference counting to atm_dev

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1012  -> 1.1013 
#	      net/atm/addr.c	1.2     -> 1.3    
#	       net/atm/lec.c	1.14    -> 1.15   
#	    drivers/atm/he.c	1.2     -> 1.3    
#	  net/atm/atm_misc.c	1.2     -> 1.3    
#	   drivers/atm/eni.c	1.7     -> 1.8    
#	       net/atm/mpc.c	1.7     -> 1.8    
#	include/linux/atmdev.h	1.8     -> 1.9    
#	      net/atm/proc.c	1.6     -> 1.7    
#	 net/atm/resources.c	1.5     -> 1.6    
#	      net/atm/clip.c	1.8     -> 1.9    
#	drivers/atm/fore200e.c	1.8     -> 1.9    
#	drivers/atm/idt77252.c	1.7     -> 1.8    
#	drivers/atm/atmtcp.c	1.3     -> 1.4    
#	 net/atm/signaling.c	1.4     -> 1.5    
#	 net/atm/resources.h	1.2     -> 1.3    
#	    net/atm/common.c	1.15    -> 1.16   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/26	bdschuym@pandora.be	1.1005.4.16
# [NETFILTER]: Add arptables mangle module.
# --------------------------------------------
# 03/06/26	chas@cmf.nrl.navy.mil	1.1005.4.17
# [ATM]: ixmicro puts esi in different location
# --------------------------------------------
# 03/06/26	chas@cmd.nrl.navy.mil	1.1005.4.18
# [ATM]: remove iovcnt member in struct atm_skb
# --------------------------------------------
# 03/06/26	chas@cmf.nrl.navy.mil	1.1005.4.19
# [ATM]: lock neighbor entry during update in clip.c
# --------------------------------------------
# 03/06/26	chas@cmf.nrl.navy.mil	1.1005.4.20
# [ATM]: make sub skb->cb is clear before upcall to network
# --------------------------------------------
# 03/06/26	chas@cmf.nrl.navy.mil	1.1005.4.21
# [ATM]: eliminate ATM_PDU_OVHD, ops->free_rx_skb and ops->alloc_tx
# --------------------------------------------
# 03/06/26	chas@cmf.nrl.navy.mil	1.1005.4.22
# [ATM]: make clip buildable as a module
# --------------------------------------------
# 03/06/27	marcelo@freak.distro.conectiva	1.1011.1.1
# Merge bk://kernel.bkbits.net/davem/crypto-2.4
# into freak.distro.conectiva:/home/marcelo/bk/linux-2.4
# --------------------------------------------
# 03/06/27	bcollins@debian.org	1.1011.1.2
# [PATCH] Update IEEE1394 (r972)
# 
#  IEEE1394 : Add OUI database.
#  DV1394   : Fix endian conversion brokeness.
#  ETH1394  : Updates for async streams, EUI based ARP and packet
#             fragmentation.
#  IEEE1394 : Host key lookup improvements.
#  SBP2     : Fix > S400 max_payload setting.
#  IEEE1394 : Move hotplug declerations around to more generic place.
#  IEEE1394 : Fix possible memory leak in ISO code.
#  IEEE1394 : Fix proc output for > page size.
#  OHCI1394 : Async stream packets.
#  OHCI1394 : Trivial CONFIG_PM support.
#  SBP2     : Only allocate scsi_host for ieee1394_hosts that have sbp2
#             devices attached to it (on demand scsi_host allocation).
#  SBP2     : Code cleanups to bring closer to 2.5 code.
#  SBP2     : Handle Logical_Unit_Number entries.
#  VIDEO1394: Handle user pointer correctly.
#  IEEE1394 : Macro namespace cleanups.
#  ALL      : Cleanups of some C constructs.
#  ETH1394  : Limited multicast support.
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.3
# [PATCH] s390 base update
# 
# s/390 base fixes:
#  - docu: Correct description of 3270 device nodes
#  - arch: Do reate_proc_entry for debug feature outside spin locked code.
#  - arch: Set CR5 to get program checks for space switching instructions.
#  - arch: Use sig_exit in 64 bit signal handler.
#  - arch: Avoid warning in idals.h.
#  - arch: Do pfix early in the boot process. No pfix for 64 bit.
#  - arch: Fix linker output format for 64 bit kernels.
#  - arch: Fix race condition in dirty bit clearing.
#  - arch: Fix deadlock in pgd_populate.
# 
# diffstat:
#  arch/s390/kernel/debug.c       |   20 ++++--
#  arch/s390/kernel/head.S        |    2
#  arch/s390/kernel/s390_ksyms.c  |    5 +
#  arch/s390/kernel/setup.c       |  133 ++++++++++++++++++++++++++++++++++++++++-
#  arch/s390/mm/init.c            |    5 -
#  arch/s390x/kernel/debug.c      |   20 ++++--
#  arch/s390x/kernel/head.S       |   17 -----
#  arch/s390x/kernel/s390_ksyms.c |    2
#  arch/s390x/kernel/setup.c      |    6 -
#  arch/s390x/kernel/signal.c     |    5 -
#  arch/s390x/mm/init.c           |   74 ++++++++++++++++------
#  arch/s390x/vmlinux-shared.lds  |    2
#  arch/s390x/vmlinux.lds         |    2
#  include/asm-s390/idals.h       |    4 -
#  include/asm-s390/page.h        |   61 +-----------------
#  include/asm-s390/pgtable.h     |   36 ++---------
#  include/asm-s390x/idals.h      |    4 -
#  include/asm-s390x/page.h       |   61 +-----------------
#  include/asm-s390x/pgtable.h    |   36 ++---------
#  include/asm-s390x/setup.h      |    2
#  include/linux/mm.h             |   10 ++-
#  21 files changed, 261 insertions(+), 246 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.4
# [PATCH] s390 common i/o layer fixes
# 
# Common i/o fixes:
#  - Don't confuse device drivers with zero sense data.
#  - Check return code for the start of the basic sense ccw.
#  - Fix deadlock in enable_cpu_sync_isc.
#  - Fix check for path not operational condition.
#  - Use unsigned long for flags variable in read_dev_chars.
#  - Only try sense path group id on available paths.
#  - Retry sense path group id on another path after deferred cc=3.
#  - Fix deadlock in link incident handler.
#  - Fix output in /proc/chpids.
#  - Adapt to latest path group algorithm.
#  - Fix handling of condition code 1 (status pending) on i/o operations.
#  - Only process status pending conditions when doing sync. i/o.
#  - Path revalidation fixes:
#    * Add a handler for machine checks with chpid sources.
#    * Distinguish between device gone and device not accessible in the
#      device not operational handler.
#    * Don't accept i/o from the device drivers while doing path revalidation.
#    * Use a bottom half for doing path verification from interrupt context.
#    * Don't do path verification if sync. isc is alread in use. Reschedule bh.
#    * Kill pending i/o before doing path verification.
#    * Always start with a logical path mask of 0xff because the information
#      store by stsch() can be outdated.
#  - Always use a tpi loop for basic sense.
#  - Lowered level of 'not operational' messages.
#  - Check after store event information if there are more crws pending.
#  - Make diag210 a non-inline function to avoid problems with modules loaded
#    above 2G.
#  - Show reserved devices as "boxed" instead of "unkown".
#  - Fix for path no operational condition in cio_start.
#  - Fix /proc/cio_ignore string parsing.
#  - Fix parsing of verbs in chandev.
# 
# diffstat:
#  drivers/s390/misc/chandev.c |    2
#  drivers/s390/s390io.c       | 2422 +++++++++++++++++++++++++-------------------
#  drivers/s390/s390mach.c     |   14
#  include/asm-s390/irq.h      |   43
#  include/asm-s390/s390io.h   |   14
#  include/asm-s390/setup.h    |    1
#  include/asm-s390x/irq.h     |   44
#  include/asm-s390x/s390io.h  |   16
#  include/asm-s390x/setup.h   |    1
#  9 files changed, 1494 insertions(+), 1063 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.5
# [PATCH] s390 dasd driver update
# 
# Big patch for the dasd driver.
# 
# New features:
#  - Add 'set on/off' to /proc/dasd/statistics.
#  - Added BIODASDPSRD ioctl (Read Subsystem Performance Statistics).
#  - Added BIODASDSATTR ioctl (Set Cache Attributes).
#  - Support for XRC timestamping.
#  - Add support for breaking the reservation of a dasd (boxed dasd access).
#  - Implemented hotplug support for dasd.
#  - Support for ESS dasd devices.
# 
# Bug-Fixes:
#  - Use internal timer instead of DOIO_TIMEOUT option (cio).
#  - Use 'get_clock' instead of 'STCK....'
#  - Switch off autodetect/probeonly as default behaviour.
#  - Rework of dasd messages.
#  - Reseve IOCTL-NR 240-255 for EMC
#  - Fix statistics counting.
#  - Clear request queue in dasd_disable_blkdev.
#  - Fix for a race between dasd_format and sleep_on_req.
#  - Fix for a race between reserve timeout and successful completion.
#  - Set maximun end-cylinder to geometry cylinder -1 (in Define Extent).
#  - Private implementation of BLKROSET.
#  - Allow sharing of external interrupt 0x2603 between pfault and dasd diag.
#  - Plug devices during bringup.
#  - Get diag discipline to work again.
#  - Check diag discipline forst on dynamic attach of a device.
#  - EXPORT dasd_device_from_devno (needed by EMC)
#  - Fix problem with ext3 doing modifications to the first request on the
#    request queue.
#  - Prevent scheduling in timer_bh.
#  - Check for empty queue after state change pending interrupt.
#  - Register a dasd only if the blocksize and the number of blocks are valid.
#  - Check for spurious interrupts while waiting for basic sense data.
#  - Check for unformatted dasd in BIODASDINFO ioctl.
#  - Check for unformatted dasd in dasd_disable_blkdev.
#  - Fix oops during boot if an invalid dasd= parameter has been specified.
#  - Prevent dasd driver from creating /proc/partition names for scsi devices.
#  - Return error for non-dasd-devices in dasd ioctls.
#  - Add missing MODULE_LICENSE("GPL").
#  - Don't accept invalid device numbers in /proc/dasd/devices interface.
#  - Add check in dasd_discipline_del if discipline to be removed has been added.
#  - Remove static initializer from dasd_major_info and use proper
#    list_for_each operations for dasd_major_info list.
#  - Disable dasd diag for 64 bit.
#  - Fix race condition on timer variable in dasd_device_t.
#  - Fix timeout processing for reserve/release requests.
#  - Fix race condition between setup and first use of request_queue.
#  - make dasd_eckd compile with gcc 3.3.
#  - Post requests with invalid blocksize with i/o-error.
#  - Various fixes for ESS dasd device support.
#  - Fixed path revalidation.
#  - Retry i/o after path failure.
#  - Retry i/o after interface control check.
#  - Fix major&minor number for dynamically attached dasd devices.
#  - Fix low memory handling.
#  - Free spinlock in case of an error in dasd_device_from_devno.
#  - Head queue diag discipline to give it a chance to grab is device before eckd.
#  - Remove some warnings.
#  - Fix reserve/release for 64 bit.
#  - Add module licence to fba discipline.
# 
# diffstat:
#  drivers/s390/block/dasd.c          | 3568 ++++++++++++++++++++++++-------------
#  drivers/s390/block/dasd_3990_erp.c | 1347 ++++++-------
#  drivers/s390/block/dasd_diag.c     |  273 +-
#  drivers/s390/block/dasd_diag.h     |   20
#  drivers/s390/block/dasd_eckd.c     |  729 +++++--
#  drivers/s390/block/dasd_eckd.h     |  152 -
#  drivers/s390/block/dasd_fba.c      |  116 -
#  drivers/s390/block/dasd_fba.h      |   12
#  drivers/s390/block/dasd_int.h      |  353 ++-
#  include/asm-s390/ccwcache.h        |   38
#  include/asm-s390/dasd.h            |  187 +
#  include/asm-s390/vtoc.h            |    1
#  include/asm-s390x/ccwcache.h       |   38
#  include/asm-s390x/dasd.h           |  187 +
#  include/asm-s390x/vtoc.h           |    1
#  15 files changed, 4532 insertions(+), 2490 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.6
# [PATCH] s390 31 bit compat.
# 
# 31 bit emulation changes:
#  - Support for PER_LINUX32 personality added.
#  - Added [un]register_ioctl32_conversion.
#  - Don't do float/integer conversion in save/restore_sigregs32.
#  - Add system call emulation for sys_readahead, sys_gettid, sys_tkill,
#    sys_sysctl and sys_stime.
#  - Add ioctl emulation for BLKBSZGET, BLKELVGET, BLKELVSET, BLKFLSBUF
#    BLKFRAGET, BLKFRASET, BLKGETSIZE, BLKGETSIZE64, BLKPG, BLKRASET
#    BLKROGET, BLKROSET, BLKSECTGET, BLKSECTSET, BLKSSZGET, LOOP_CLR_FD
#    LOOP_GET_STATUS, LOOP_SET_FD, LOOP_SET_STATUS, RAW_GETBIND
#    RAW_SETBIND and SIOCATMARK.
#  - Signal backchain fix for 31 bit emulation signal handler.
#  - Added missing check for SIGURG in emulation signal handler.
#  - sys_msgsnd and sys_msgrcv emulation fixes.
#  - Fix emulation for sys_getrlimit.
#  - Add check for (ssize_t32) count < 0 in read and write system call emulation.
#  - Check offset in pwrite system call emulation.
# 
# diffstat:
#  arch/s390x/kernel/Makefile        |    2
#  arch/s390x/kernel/binfmt_elf32.c  |    8
#  arch/s390x/kernel/entry.S         |   12 -
#  arch/s390x/kernel/exec_domain32.c |   30 +++
#  arch/s390x/kernel/ioctl32.c       |  181 ++++++++++++++++++
#  arch/s390x/kernel/linux32.c       |  364 +++++++++++++++++++++++++++++++++++---
#  arch/s390x/kernel/s390_ksyms.c    |   14 +
#  arch/s390x/kernel/signal32.c      |   14 +
#  arch/s390x/kernel/wrapper32.S     |   24 ++
#  9 files changed, 608 insertions(+), 41 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.7
# [PATCH] s390 documentation update
# 
# S/390 Documentation changes:
#  - Updated section about /proc/subchannels.
#  - Added description for /proc/chpids.
#  - Added descriptions for get_irq_first() / get_irq_next().
#  - Added description  for read_conf_data().
#  - Added description  for s390_request_irq_special().
#  - Typos and minor improvements.
# 
# diffstat:
#  Documentation/s390/CommonIO         |   48 +++
#  Documentation/s390/Debugging390.txt |    8
#  Documentation/s390/cds.txt          |  442 ++++++++++++++++++++++++++++--------
#  3 files changed, 397 insertions(+), 101 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.8
# [PATCH] Add Configure.help entries for s390 options
# 
# Update of s/390 specific documentation and help texts.
# 
# diffstat:
#  Documentation/Configure.help |   14 ++++++++++++++
#  Documentation/devices.txt    |   12 ++++++------
#  2 files changed, 20 insertions(+), 6 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.9
# [PATCH] s390 3215 driver update
# 
# Changes for the 3215 driver and new control character helper functions.
# 
# diffstat:
#  drivers/s390/char/con3215.c  |   39 +++++++++++-------
#  drivers/s390/char/ctrlchar.c |   92 +++++++++++++++++++------------------------
#  drivers/s390/char/ctrlchar.h |   12 ++++-
#  3 files changed, 75 insertions(+), 68 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.10
# [PATCH] s390 ctc network driver update
# 
# Changes for the ctc network driver:
#  - Fixed vary on/off issue.
#  - Implemented restart after -EIO.
#  - Changed severity of some warnings to debug.
#  - Fixed physical link lost problems.
# 
# diffstat:
#  drivers/s390/net/ctcmain.c |  969 ++++++++++++++++++++++++++++++---------------
#  drivers/s390/net/ctctty.c  |  106 +++-
#  drivers/s390/net/fsm.h     |    2
#  3 files changed, 735 insertions(+), 342 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.11
# [PATCH] s390 iucv network driver.
# 
# Changes for the iucv network driver:
#  - Added mising call of release_param().
#  - Allow '$' in username.
#  - Workaround for VM bug.
#  - Don't rely on IUCV ipmsgtags.
#  - Additional debug code.
#  - Fix deadlock when starting more than 160 devices.
# 
# diffstat:
#  drivers/s390/net/iucv.c    |  125 +++++++++++++++++++++++++++++++++++++--------
#  drivers/s390/net/iucv.h    |    4 +
#  drivers/s390/net/netiucv.c |   83 +++++++++++++++++++++++------
#  3 files changed, 172 insertions(+), 40 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.12
# [PATCH] s390 defconfigs update
# 
# New default configurations.
# 
# diffstat:
#  arch/s390/defconfig  |  218 ++++++++++++++++++++++++++++++++++++++++++---------
#  arch/s390x/defconfig |  166 ++++++++++++++++++++++++++++++--------
#  2 files changed, 312 insertions(+), 72 deletions(-)
# --------------------------------------------
# 03/06/27	schwidefsky@de.ibm.com	1.1011.1.13
# [PATCH] console semaphore fix.
# 
# Avoid BUG if panic is called from an interrupt context. This patch has been
# accepted to linux-2.5.
# 
# diffstat:
#  kernel/printk.c |    9 ++++++++-
#  1 files changed, 8 insertions(+), 1 deletion(-)
# --------------------------------------------
# 03/06/27	greg@kroah.com	1.1005.1.5
# Cset exclude: cweidema@indiana.edu|ChangeSet|20030620002017|05386
# --------------------------------------------
# 03/06/27	lethal@linux-sh.org	1.1011.1.14
# [PATCH] SH64 Merge
# 
# Here's the patch for sh64! This adds arch/sh64 and include/asm-sh64. All
# changes are localized to these directories.
# 
# Here's the diffstat output, nothing too terribly exciting:
# 
#  arch/sh64/Makefile                      |   91 +
#  arch/sh64/boot/Makefile                 |   34
#  arch/sh64/boot/compressed/Makefile      |   57
#  arch/sh64/boot/compressed/cache.c       |   39
#  arch/sh64/boot/compressed/head.S        |  164 ++
#  arch/sh64/boot/compressed/install.sh    |   56
#  arch/sh64/boot/compressed/misc.c        |  251 +++
#  arch/sh64/boot/compressed/vmlinux.lds.S |   65
#  arch/sh64/config.in                     |  298 ++++
#  arch/sh64/defconfig                     |  467 +++++++
#  arch/sh64/kernel/Makefile               |   38
#  arch/sh64/kernel/entry.S                | 2099 ++++++++++++++++++++++++++++++++
#  arch/sh64/kernel/fpu.c                  |  171 ++
#  arch/sh64/kernel/head.S                 |  347 +++++
#  arch/sh64/kernel/init_task.c            |   36
#  arch/sh64/kernel/irq.c                  |  706 ++++++++++
#  arch/sh64/kernel/irq_intc.c             |  269 ++++
#  arch/sh64/kernel/led.c                  |   69 +
#  arch/sh64/kernel/pci-dma.c              |   46
#  arch/sh64/kernel/pci_sh5.c              |  607 +++++++++
#  arch/sh64/kernel/pci_sh5.h              |  107 +
#  arch/sh64/kernel/pcibios.c              |  129 +
#  arch/sh64/kernel/process.c              |  903 +++++++++++++
#  arch/sh64/kernel/ptrace.c               |  375 +++++
#  arch/sh64/kernel/semaphore.c            |  137 ++
#  arch/sh64/kernel/setup.c                |  362 +++++
#  arch/sh64/kernel/sh_ksyms.c             |   78 +
#  arch/sh64/kernel/signal.c               |  821 ++++++++++++
#  arch/sh64/kernel/sys_sh64.c             |  268 ++++
#  arch/sh64/kernel/time.c                 |  552 ++++++++
#  arch/sh64/kernel/traps.c                |  263 ++++
#  arch/sh64/lib/Makefile                  |   26
#  arch/sh64/lib/c-checksum.c              |  330 +++++
#  arch/sh64/lib/checksum.S                |  656 ++++++++++
#  arch/sh64/lib/copy_user_memcpy.S        |  205 +++
#  arch/sh64/lib/dbg.c                     |  319 ++++
#  arch/sh64/lib/io.c                      |  200 +++
#  arch/sh64/lib/memcpy.c                  |   82 +
#  arch/sh64/lib/old-checksum.c            |   17
#  arch/sh64/lib/page_clear.S              |   46
#  arch/sh64/lib/page_copy.S               |   77 +
#  arch/sh64/lib/panic.c                   |   60
#  arch/sh64/lib/syscalltab.h              |  311 ++++
#  arch/sh64/lib/udelay.c                  |   53
#  arch/sh64/mach-cayman/Makefile          |   15
#  arch/sh64/mach-cayman/irq.c             |  188 ++
#  arch/sh64/mach-cayman/led.c             |   47
#  arch/sh64/mach-cayman/setup.c           |  209 +++
#  arch/sh64/mach-harp/Makefile            |   14
#  arch/sh64/mach-harp/setup.c             |  139 ++
#  arch/sh64/mach-sim/Makefile             |   14
#  arch/sh64/mach-sim/setup.c              |  164 ++
#  arch/sh64/mm/Makefile                   |   43
#  arch/sh64/mm/cache.c                    | 1062 ++++++++++++++++
#  arch/sh64/mm/extable.c                  |   95 +
#  arch/sh64/mm/fault.c                    |  716 ++++++++++
#  arch/sh64/mm/init.c                     |  203 +++
#  arch/sh64/mm/ioremap.c                  |  358 +++++
#  arch/sh64/mm/tlb.c                      |  166 ++
#  arch/sh64/mm/tlbmiss.c                  |  276 ++++
#  arch/sh64/vmlinux.lds.S                 |  158 ++
#  include/asm-sh64/a.out.h                |   37
#  include/asm-sh64/atomic.h               |  102 +
#  include/asm-sh64/bitops.h               |  364 +++++
#  include/asm-sh64/bugs.h                 |   38
#  include/asm-sh64/byteorder.h            |   49
#  include/asm-sh64/cache.h                |  139 ++
#  include/asm-sh64/cayman.h               |   20
#  include/asm-sh64/checksum.h             |  321 ++++
#  include/asm-sh64/current.h              |   31
#  include/asm-sh64/delay.h                |   11
#  include/asm-sh64/div64.h                |   21
#  include/asm-sh64/dma.h                  |   38
#  include/asm-sh64/elf.h                  |  101 +
#  include/asm-sh64/errno.h                |  143 ++
#  include/asm-sh64/fcntl.h                |   87 +
#  include/asm-sh64/hardirq.h              |   42
#  include/asm-sh64/hardware.h             |   19
#  include/asm-sh64/hw_irq.h               |   16
#  include/asm-sh64/init.h                 |   17
#  include/asm-sh64/io.h                   |  215 +++
#  include/asm-sh64/ioctl.h                |   83 +
#  include/asm-sh64/ioctls.h               |  110 +
#  include/asm-sh64/ipc.h                  |   42
#  include/asm-sh64/ipcbuf.h               |   40
#  include/asm-sh64/irq.h                  |  142 ++
#  include/asm-sh64/keyboard.h             |   74 +
#  include/asm-sh64/linux_logo.h           |   47
#  include/asm-sh64/mman.h                 |   49
#  include/asm-sh64/mmu.h                  |    7
#  include/asm-sh64/mmu_context.h          |  209 +++
#  include/asm-sh64/module.h               |   12
#  include/asm-sh64/msgbuf.h               |   42
#  include/asm-sh64/namei.h                |   24
#  include/asm-sh64/page.h                 |  129 +
#  include/asm-sh64/param.h                |   43
#  include/asm-sh64/pci.h                  |  230 +++
#  include/asm-sh64/pgalloc-3level.h       |   78 +
#  include/asm-sh64/pgalloc.h              |  173 ++
#  include/asm-sh64/pgtable-3level.h       |  152 ++
#  include/asm-sh64/pgtable.h              |  336 +++++
#  include/asm-sh64/platform.h             |   69 +
#  include/asm-sh64/poll.h                 |   36
#  include/asm-sh64/posix_types.h          |  128 +
#  include/asm-sh64/processor.h            |  273 ++++
#  include/asm-sh64/ptrace.h               |   38
#  include/asm-sh64/registers.h            |  199 +++
#  include/asm-sh64/resource.h             |   47
#  include/asm-sh64/scatterlist.h          |   36
#  include/asm-sh64/segment.h              |    6
#  include/asm-sh64/semaphore-helper.h     |  100 +
#  include/asm-sh64/semaphore.h            |  139 ++
#  include/asm-sh64/sembuf.h               |   36
#  include/asm-sh64/serial.h               |   33
#  include/asm-sh64/shmbuf.h               |   53
#  include/asm-sh64/shmparam.h             |   20
#  include/asm-sh64/sigcontext.h           |   30
#  include/asm-sh64/siginfo.h              |  233 +++
#  include/asm-sh64/signal.h               |  184 ++
#  include/asm-sh64/smp.h                  |   15
#  include/asm-sh64/smplock.h              |   77 +
#  include/asm-sh64/socket.h               |   64
#  include/asm-sh64/sockios.h              |   24
#  include/asm-sh64/softirq.h              |   30
#  include/asm-sh64/spinlock.h             |   17
#  include/asm-sh64/stat.h                 |   88 +
#  include/asm-sh64/statfs.h               |   36
#  include/asm-sh64/string.h               |   21
#  include/asm-sh64/system.h               |  405 ++++++
#  include/asm-sh64/termbits.h             |  183 ++
#  include/asm-sh64/termios.h              |  118 +
#  include/asm-sh64/timex.h                |   36
#  include/asm-sh64/tlb.h                  |   95 +
#  include/asm-sh64/types.h                |   66 +
#  include/asm-sh64/uaccess.h              |  288 ++++
#  include/asm-sh64/ucontext.h             |   23
#  include/asm-sh64/unaligned.h            |   30
#  include/asm-sh64/unistd.h               |  416 ++++++
#  include/asm-sh64/user.h                 |   71 +
#  139 files changed, 23750 insertions(+)
# 
# and here's the patch..
# --------------------------------------------
# 03/06/27	grigouze@noos.fr	1.1005.1.6
# [PATCH] USB: zaurus SL-C700
# 
# This is a patch for usbnet for working with Zaurus SL-C700.
# The productid is different from other Zaurus, so i add an entry for it :)
# --------------------------------------------
# 03/06/27	baldrick@wanadoo.fr	1.1005.1.7
# [PATCH] USB speedtouch: use common CRC library
# 
# Remove the speedtouch CRC library.  With this change, the speedtch
# module is no longer a multi-part object, so fix that up too.
# --------------------------------------------
# 03/06/27	abbotti@mev.co.uk	1.1005.1.8
# [PATCH] USB: several ftdi_sio driver patches
# 
# I have attached several patches for the ftdi_sio (USB serial device)
# driver that I have been accumulating over the last month or so as
# the official maintainer (Bill Ryder) has been rather quiet of late.
# He hasn't responded to any patches or other messages on
# ftdi-usb-sio-devel since the end of March.
# 
# The last patch Bill sent to linux-usb-devel was for ftdi_sio version
# 1.3.3, which is the latest available for download from the
# sourceforge project page.  Greg had some criticisms about
# whitespace, braces, etc. which was not replied to by Bill.
# 
# In this sequence of patches, I have tidied some things up, accepted
# patches and vid/pids for extra device support and fixed a spinlock
# bug.
# 
# The patches apply cleanly in the sequence presented here.  I have
# split the patches by function, but have attempted to preserve the
# chronology where possible - there is a certain amount of
# time-warping going on as can be seen from the file header comments
# changed by the patches!
# 
# The patches are as follows:
# 
# 2.4.21-ftdi_sio-p01-xonxoff.patch - John Wilkins Xon/Xoff patch
# (included in ftdi_sio-1.3.3)
# 
# 2.4.21-ftdi_sio-p02-homechoice.patch - John Wilkins vid/pid for
# Homechoice (included in ftdi_sio-1.3.3)
# 
# 2.4.21-ftdi_sio-p03-readspeed.patch - Richard Shooter's read
# speed-up code (included in ftdi_sio-1.3.3), but I've tidied up the
# source and moved some stuff around.  I've bumped the version to
# 1.3.3a to distinguish it from the 1.3.3 that Bill previously sent.
# 
# 2.4.21-ftdi_sio-p04-spinlockbug.patch - my patch to avoid copying
# user data with a spinlock held (and interrupts disabled).
# 
# 2.4.21-ftdi_sio-p05-sealink.patch - Adds Sealevel vid/pids - based
# on a patch by Tuan Hoang but with less bloat.
# 
# 2.4.21-ftdi_sio-p06-usbuirt.patch - David Norwood's patch for
# USB-UIRT device using a preset custom divisor.
# 
# 2.4.21-ftdi_sio-p07-writepooltidy.patch - my patch to take account
# of write urb pool table entries that failed allocation, and to free
# the write urb and transfer buffer allocated by the usbserial
# driver.
# 
# 2.4.21-ftdi_sio-p08-relais.patch - support for USB Relais pid,
# backported from 2.5.x.
# 
# 2.4.21-ftdi_sio-p09-tira1.patch - half of Erik Nygren's patch to
# support Home Electronics' Tira-1 IR tranceiver using a preset
# custom divisor.
# 
# 2.4.21-ftdi_sio-p10-forcebaud.patch - the other half of Erik
# Nygren's patch forces the baud rate setting to B38400 for USB-UIRT
# and Tira-1 devices and also forces RTS/CTS on for Tira-1.
# 
# 2.4.21-ftdi_sio-p11-paranoid.patch - my patch to make sure pointers
# that fail paranoid checks are not dereferenced.
# 
# 2.4.21-ftdi_sio-p12-versionbump.patch - my patch to bump the
# version.  This is stepping on Bill's toes a little, but I think
# whatever ends up in the 2.4.22 kernel should be labelled version
# 1.3.4.
# 
# I have a 2.5.x driver version as a work in progress containing most
# of the above changes.  I just need to finish it off a little and
# maybe replace the write urb pool stuff with something resembling
# the changes in the Visor driver.
# --------------------------------------------
# 03/06/27	david@csse.uwa.edu.au	1.1005.1.9
# [PATCH] USB: usb-uhci fix for one-shot interrupt problem
# 
# A change introduced into usb-uhci.c in 2.4.21 causes the kernel to
# freeze when usb-uhci is used with any driver using one-shot interrupt
# transfers. The attached fix was originally proposed by Frode Isaksen and
# improved by Pete Zaitcev. Pete Zaitcev has applied this patch as an
# errata fix for the RedHat 9.0 kernel.
# 
# Other than the serious problem that this causes with the Lego USB driver
# (and yes, this is used pretty heavily in Universities for teaching and
# some research), there are other drivers (e.g. Visor Treo 90) that this
# causes problems for.
# --------------------------------------------
# 03/06/27	david@csse.uwa.edu.au	1.1005.1.10
# [PATCH] USB: usb-ohci handling of one-shot interrupt transfers
# 
# A long standing problem has existed with usb-ohci handling of one-shot
# interrupt transfers (they never worked). Attached is a fix which was
# originally proposed by P.C. Chan and subsequently modified and
# re-presented by Frode Isaksen. The Lego USB driver does not work with
# ohci without this fix and so I would really appreciate it being applied.
# --------------------------------------------
# 03/06/27	oliver@neukum.org	1.1005.1.11
# [PATCH] USB: disconnect of v4l devices in 2.4
# 
# in 2.4 video_unregister_device() has lost its magic properties
# breaking most USB v4l drivers. IMHO they should be converted
# to delayed freeing resources just like ordinary character devices.
# Here's the change for vicam.c.
# --------------------------------------------
# 03/06/27	oliver@neukum.org	1.1005.1.12
# [PATCH] USB: fix to previous vicam patch
# 
# OK, I'll think next time.
#   - fix my own stupid oversight regarding disconnect()
# --------------------------------------------
# 03/06/27	greg@kroah.com	1.1005.1.13
# [PATCH] USB: compiler fixes for previous vicam patches.
# --------------------------------------------
# 03/06/27	greg@kroah.com	1.1011.1.15
# Merge kroah.com:/home/greg/linux/BK/bleed-2.4
# into kroah.com:/home/greg/linux/BK/gregkh-2.4
# --------------------------------------------
# 03/06/27	judd@jpilot.org	1.1011.1.16
# [PATCH] USB: visor.h[c] USB device IDs
# 
# Add ability to specify USB vendor and product ids as module options.
# --------------------------------------------
# 03/06/27	chas@relax.cmf.nrl.navy.mil	1.1013
# do reference counting of struct atm_dev
# --------------------------------------------
#
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Mon Jun 30 13:23:17 2003
+++ b/drivers/atm/atmtcp.c	Mon Jun 30 13:23:17 2003
@@ -153,6 +153,7 @@
 
 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
 {
+	unsigned long flags;
 	struct atm_cirange ci;
 	struct atm_vcc *vcc;
 
@@ -162,9 +163,14 @@
 	if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
 	if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
 	    ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
+	spin_lock_irqsave(&dev->lock, flags);
 	for (vcc = dev->vccs; vcc; vcc = vcc->next)
 		if ((vcc->vpi >> ci.vpi_bits) ||
-		    (vcc->vci >> ci.vci_bits)) return -EBUSY;
+		    (vcc->vci >> ci.vci_bits)) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return -EBUSY;
+		}
+	spin_unlock_irqrestore(&dev->lock, flags);
 	dev->ci_range = ci;
 	return 0;
 }
@@ -227,6 +233,7 @@
 
 static void atmtcp_c_close(struct atm_vcc *vcc)
 {
+	unsigned long flags;
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
 	struct atm_vcc *walk;
@@ -239,13 +246,16 @@
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
+	spin_lock_irqsave(&atmtcp_dev->lock, flags);
 	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
 		wake_up(&walk->sleep);
+	spin_unlock_irqrestore(&atmtcp_dev->lock, flags);
 }
 
 
 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct atmtcp_hdr *hdr;
 	struct atm_vcc *out_vcc;
@@ -260,11 +270,13 @@
 		    (struct atmtcp_control *) skb->data);
 		goto done;
 	}
+	spin_lock_irqsave(&dev->lock, flags);
 	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
+	spin_unlock_irqrestore(&dev->lock, flags);
 	if (!out_vcc) {
 		atomic_inc(&vcc->stats->tx_err);
 		goto done;
@@ -293,13 +305,13 @@
 
 
 static struct atmdev_ops atmtcp_v_dev_ops = {
-	dev_close:	atmtcp_v_dev_close,
-	open:		atmtcp_v_open,
-	close:		atmtcp_v_close,
-	ioctl:		atmtcp_v_ioctl,
-	send:		atmtcp_v_send,
-	proc_read:	atmtcp_v_proc,
-	owner:		THIS_MODULE
+	.dev_close	= atmtcp_v_dev_close,
+	.open		= atmtcp_v_open,
+	.close		= atmtcp_v_close,
+	.ioctl		= atmtcp_v_ioctl,
+	.send		= atmtcp_v_send,
+	.proc_read	= atmtcp_v_proc,
+	.owner		= THIS_MODULE
 };
 
 
@@ -309,21 +321,16 @@
 
 
 static struct atmdev_ops atmtcp_c_dev_ops = {
-	close:		atmtcp_c_close,
-	send:		atmtcp_c_send
+	.close		= atmtcp_c_close,
+	.send		= atmtcp_c_send
 };
 
 
 static struct atm_dev atmtcp_control_dev = {
-	&atmtcp_c_dev_ops,
-	NULL,		/* no PHY */
-	"atmtcp",	/* type */
-	999,		/* dummy device number */
-	NULL,NULL,	/* pretend not to have any VCCs */
-	NULL,NULL,	/* no data */
-	{ 0 },		/* no flags */
-	NULL,		/* no local address */
-	{ 0 }		/* no ESI, no statistics */
+	.ops		= &atmtcp_c_dev_ops,
+	.type		= "atmtcp",
+	.number		= 999,
+	.lock		= SPIN_LOCK_UNLOCKED
 };
 
 
@@ -356,9 +363,12 @@
 	struct atm_dev *dev;
 
 	dev = NULL;
-	if (itf != -1) dev = atm_find_dev(itf);
+	if (itf != -1) dev = atm_dev_lookup(itf);
 	if (dev) {
-		if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
+		if (dev->ops != &atmtcp_v_dev_ops) {
+			atm_dev_release(dev);
+			return -EMEDIUMTYPE;
+		}
 		if (PRIV(dev)->vcc) return -EBUSY;
 	}
 	else {
@@ -389,14 +399,18 @@
 	struct atm_dev *dev;
 	struct atmtcp_dev_data *dev_data;
 
-	dev = atm_find_dev(itf);
+	dev = atm_dev_lookup(itf);
 	if (!dev) return -ENODEV;
-	if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
+	if (dev->ops != &atmtcp_v_dev_ops) {
+		atm_dev_release(dev);
+		return -EMEDIUMTYPE;
+	}
 	dev_data = PRIV(dev);
 	if (!dev_data->persist) return 0;
 	dev_data->persist = 0;
 	if (PRIV(dev)->vcc) return 0;
 	kfree(dev_data);
+	atm_dev_release(dev);
 	shutdown_atm_dev(dev);
 	return 0;
 }
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Mon Jun 30 13:23:17 2003
+++ b/drivers/atm/eni.c	Mon Jun 30 13:23:17 2003
@@ -1887,8 +1887,10 @@
 
 static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
+	unsigned long flags;
 	struct atm_vcc *walk;
 
+	spin_lock_irqsave(&vcc->dev->lock, flags);
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
@@ -1907,17 +1909,29 @@
 			}
 			break;
 		}
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
-	if (*vci == ATM_VCI_UNSPEC) return 0;
+	if (*vci == ATM_VCI_UNSPEC) {
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		return 0;
+	}
 	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
-	    ENI_DEV(vcc->dev)->rx_map[*vci])
+	    ENI_DEV(vcc->dev)->rx_map[*vci]) {
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
 		return -EADDRINUSE;
-	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
+	}
+	if (vcc->qos.txtp.traffic_class == ATM_NONE) {
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		return 0;
+	}
 	for (walk = vcc->dev->vccs; walk; walk = walk->next)
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
-		    walk->qos.txtp.traffic_class != ATM_NONE)
+		    walk->qos.txtp.traffic_class != ATM_NONE) {
+			spin_unlock_irqrestore(&vcc->dev->lock, flags);
 			return -EADDRINUSE;
+		}
+	spin_unlock_irqrestore(&vcc->dev->lock, flags);
 	return 0;
 }
 
@@ -2125,6 +2139,7 @@
 
 static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
 {
+	unsigned long flags;
 	static const char *signal[] = { "LOST","unknown","okay" };
 	struct eni_dev *eni_dev = ENI_DEV(dev);
 	struct atm_vcc *vcc;
@@ -2197,6 +2212,7 @@
 		return sprintf(page,"%10sbacklog %u packets\n","",
 		    skb_queue_len(&tx->backlog));
 	}
+	spin_lock_irqsave(&dev->lock, flags);
 	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
 		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
 		int length;
@@ -2215,8 +2231,10 @@
 			length += sprintf(page+length,"tx[%d], txing %d bytes",
 			    eni_vcc->tx->index,eni_vcc->txing);
 		page[length] = '\n';
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return length+1;
 	}
+	spin_unlock_irqrestore(&dev->lock, flags);
 	for (i = 0; i < eni_dev->free_len; i++) {
 		struct eni_free *fe = eni_dev->free_list+i;
 		unsigned long offset;
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Mon Jun 30 13:23:17 2003
+++ b/drivers/atm/fore200e.c	Mon Jun 30 13:23:17 2003
@@ -1077,13 +1077,16 @@
 static struct atm_vcc* 
 fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
 {
+    unsigned long flags;
     struct atm_vcc* vcc;
 
+    spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
     for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
 
 	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
 	    break;
     }
+    spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
     
     return vcc;
 }
@@ -1354,9 +1357,13 @@
 static int
 fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
 {
+    unsigned long flags;
     struct atm_vcc* walk;
 
     /* find a free VPI */
+
+    spin_lock_irqsave(&vcc->dev->lock, flags);
+
     if (*vpi == ATM_VPI_ANY) {
 
 	for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
@@ -1380,6 +1387,8 @@
 	}
     }
 
+    spin_unlock_irqrestore(&vcc->dev->lock, flags);
+
     return 0;
 }
 
@@ -2640,6 +2649,7 @@
 static int
 fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
 {
+    unsigned long flags;
     struct fore200e* fore200e  = FORE200E_DEV(dev);
     int              len, left = *pos;
 
@@ -2886,6 +2896,7 @@
 	len = sprintf(page,"\n"    
 		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
 	
+	spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
 	for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
@@ -2900,6 +2911,7 @@
 			   fore200e_vcc->rx_max_pdu
 		);
 	}
+	spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
 
 	return len;
     }
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Mon Jun 30 13:23:17 2003
+++ b/drivers/atm/he.c	Mon Jun 30 13:23:17 2003
@@ -329,6 +329,7 @@
 static __inline__ struct atm_vcc*
 he_find_vcc(struct he_dev *he_dev, unsigned cid)
 {
+	unsigned long flags;
 	struct atm_vcc *vcc;
 	short vpi;
 	int vci;
@@ -336,10 +337,15 @@
 	vpi = cid >> he_dev->vcibits;
 	vci = cid & ((1 << he_dev->vcibits) - 1);
 
+	spin_lock_irqsave(&he_dev->atm_dev->lock, flags);
 	for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next)
 		if (vcc->vci == vci && vcc->vpi == vpi
-			&& vcc->qos.rxtp.traffic_class != ATM_NONE) return vcc;
+			&& vcc->qos.rxtp.traffic_class != ATM_NONE) {
+				spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+				return vcc;
+			}
 
+	spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
 	return NULL;
 }
 
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Mon Jun 30 13:23:17 2003
+++ b/drivers/atm/idt77252.c	Mon Jun 30 13:23:17 2003
@@ -2404,8 +2404,10 @@
 static int
 idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
 {
+	unsigned long flags;
 	struct atm_vcc *walk;
 
+	spin_lock_irqsave(&vcc->dev->lock, flags);
 	if (*vpi == ATM_VPI_ANY) {
 		*vpi = 0;
 		walk = vcc->dev->vccs;
@@ -2432,6 +2434,7 @@
 		}
 	}
 
+	spin_unlock_irqrestore(&vcc->dev->lock, flags);
 	return 0;
 }
 
diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h	Mon Jun 30 13:23:17 2003
+++ b/include/linux/atmdev.h	Mon Jun 30 13:23:17 2003
@@ -341,6 +341,8 @@
 	struct k_atm_dev_stats stats;	/* statistics */
 	char		signal;		/* signal status (ATM_PHY_SIG_*) */
 	int		link_rate;	/* link rate (default: OC3) */
+	atomic_t	refcnt;		/* reference count */
+	spinlock_t	lock;		/* protect internal members */
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *proc_entry; /* proc entry */
 	char *proc_name;		/* proc entry name */
@@ -402,7 +404,7 @@
 
 struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
     int number,atm_dev_flags_t *flags); /* number == -1: pick first available */
-struct atm_dev *atm_find_dev(int number);
+struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
 void shutdown_atm_dev(struct atm_dev *dev);
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
@@ -413,27 +415,43 @@
  *
  */
 
-static __inline__ int atm_guess_pdu2truesize(int pdu_size)
+static inline int atm_guess_pdu2truesize(int pdu_size)
 {
 	return ((pdu_size+15) & ~15) + sizeof(struct sk_buff);
 }
 
 
-static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize)
+static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
 {
 	atomic_add(truesize, &vcc->sk->rmem_alloc);
 }
 
 
-static __inline__ void atm_return(struct atm_vcc *vcc,int truesize)
+static inline void atm_return(struct atm_vcc *vcc,int truesize)
 {
 	atomic_sub(truesize, &vcc->sk->rmem_alloc);
 }
 
 
-static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size)
+static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
 {
 	return (size + atomic_read(&vcc->sk->wmem_alloc)) < vcc->sk->sndbuf;
+}
+
+
+static inline void atm_dev_hold(struct atm_dev *dev)
+{
+	atomic_inc(&dev->refcnt);
+}
+
+
+static inline void atm_dev_release(struct atm_dev *dev)
+{
+	atomic_dec(&dev->refcnt);
+
+	if ((atomic_read(&dev->refcnt) == 1) &&
+	    test_bit(ATM_DF_CLOSE,&dev->flags))
+		shutdown_atm_dev(dev);
 }
 
 
diff -Nru a/net/atm/addr.c b/net/atm/addr.c
--- a/net/atm/addr.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/addr.c	Mon Jun 30 13:23:17 2003
@@ -36,14 +36,6 @@
 }
 
 
-/*
- * Avoid modification of any list of local interfaces while reading it
- * (which may involve page faults and therefore rescheduling)
- */
-
-static DECLARE_MUTEX(local_lock);
-extern  spinlock_t atm_dev_lock;
-
 static void notify_sigd(struct atm_dev *dev)
 {
 	struct sockaddr_atmpvc pvc;
@@ -52,46 +44,46 @@
 	sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
 }
 
-/*
- *	This is called from atm_ioctl only. You must hold the lock as a caller
- */
 
 void atm_reset_addr(struct atm_dev *dev)
 {
+	unsigned long flags;
 	struct atm_dev_addr *this;
 
-	down(&local_lock);
+	spin_lock_irqsave(&dev->lock, flags);
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	notify_sigd(dev);
 }
 
 
 int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
 {
+	unsigned long flags;
 	struct atm_dev_addr **walk;
 	int error;
 
 	error = check_addr(addr);
-	if (error) return error;
-	down(&local_lock);
+	if (error)
+		return error;
+	spin_lock_irqsave(&dev->lock, flags);
 	for (walk = &dev->local; *walk; walk = &(*walk)->next)
 		if (identical(&(*walk)->addr,addr)) {
-			up(&local_lock);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return -EEXIST;
 		}
-	*walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
+	*walk = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
 	if (!*walk) {
-		up(&local_lock);
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENOMEM;
 	}
 	(*walk)->addr = *addr;
 	(*walk)->next = NULL;
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	notify_sigd(dev);
 	return 0;
 }
@@ -99,22 +91,24 @@
 
 int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
 {
+	unsigned long flags;
 	struct atm_dev_addr **walk,*this;
 	int error;
 
 	error = check_addr(addr);
-	if (error) return error;
-	down(&local_lock);
+	if (error)
+		return error;
+	spin_lock_irqsave(&dev->lock, flags);
 	for (walk = &dev->local; *walk; walk = &(*walk)->next)
 		if (identical(&(*walk)->addr,addr)) break;
 	if (!*walk) {
-		up(&local_lock);
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENOENT;
 	}
 	this = *walk;
 	*walk = this->next;
 	kfree(this);
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	notify_sigd(dev);
 	return 0;
 }
@@ -122,24 +116,25 @@
 
 int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
 {
+	unsigned long flags;
 	struct atm_dev_addr *walk;
 	int total;
 
-	down(&local_lock);
+	spin_lock_irqsave(&dev->lock, flags);
 	total = 0;
 	for (walk = dev->local; walk; walk = walk->next) {
 		total += sizeof(struct sockaddr_atmsvc);
 		if (total > size) {
-			up(&local_lock);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return -E2BIG;
 		}
 		if (copy_to_user(u_buf,&walk->addr,
 		    sizeof(struct sockaddr_atmsvc))) {
-			up(&local_lock);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return -EFAULT;
 		}
 		u_buf++;
 	}
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	return total;
 }
diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/atm_misc.c	Mon Jun 30 13:23:17 2003
@@ -63,13 +63,19 @@
 
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
+	unsigned long flags;
 	static short p = 0; /* poor man's per-device cache */
 	static int c = 0;
 	short old_p;
 	int old_c;
+	int err;
 
-	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY)
-		return check_ci(vcc,*vpi,*vci);
+	spin_lock_irqsave(&vcc->dev->lock, flags);
+	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
+		err = check_ci(vcc,*vpi,*vci);
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		return err;
+	}
 	/* last scan may have left values out of bounds for current device */
 	if (*vpi != ATM_VPI_ANY) p = *vpi;
 	else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
@@ -82,6 +88,7 @@
 		if (!check_ci(vcc,p,c)) {
 			*vpi = p;
 			*vci = c;
+			spin_unlock_irqrestore(&vcc->dev->lock, flags);
 			return 0;
 		}
 		if (*vci == ATM_VCI_ANY) {
@@ -96,6 +103,7 @@
 		}
 	}
 	while (old_p != p || old_c != c);
+	spin_unlock_irqrestore(&vcc->dev->lock, flags);
 	return -EADDRINUSE;
 }
 
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/clip.c	Mon Jun 30 13:23:17 2003
@@ -713,9 +713,10 @@
 
 
 static struct atm_dev atmarpd_dev = {
-	.ops =			&atmarpd_dev_ops,
-	.type =			"arpd",
-	.number =		999,
+	.ops =		&atmarpd_dev_ops,
+	.type =		"arpd",
+	.number =	999,
+	.lock =		SPIN_LOCK_UNLOCKED
 };
 
 
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/common.c	Mon Jun 30 13:23:17 2003
@@ -116,7 +116,6 @@
 #define DPRINTK(format,args...)
 #endif
 
-spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -178,19 +177,18 @@
 			atm_return(vcc,skb->truesize);
 			kfree_skb(skb);
 		}
-		spin_lock (&atm_dev_lock);	
-		fops_put (vcc->dev->ops);
+
+		if (vcc->dev->ops->owner)
+			__MOD_DEC_USE_COUNT(vcc->dev->ops->owner);
+		atm_dev_release(vcc->dev);
 		if (atomic_read(&vcc->sk->rmem_alloc))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rmem_alloc == %d after closing\n",
 			    atomic_read(&vcc->sk->rmem_alloc));
 		bind_vcc(vcc,NULL);
-	} else
-		spin_lock (&atm_dev_lock);	
+	}
 
 	if (free_sk) free_atm_vcc_sk(sk);
-
-	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -283,11 +281,13 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
-	fops_get (dev->ops);
+	if (!try_inc_mod_count(dev->ops->owner))
+		return -ENODEV;
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
-			fops_put (dev->ops);
+			if (dev->ops->owner)
+				__MOD_DEC_USE_COUNT(dev->ops->owner);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -301,14 +301,13 @@
 	struct atm_dev *dev;
 	int return_val;
 
-	spin_lock (&atm_dev_lock);
-	dev = atm_find_dev(itf);
+	dev = atm_dev_lookup(itf);
 	if (!dev)
 		return_val =  -ENODEV;
-	else
+	else {
 		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
-
-	spin_unlock (&atm_dev_lock);
+		if (return_val) atm_dev_release(dev);
+	}
 
 	return return_val;
 }
@@ -339,15 +338,20 @@
 	}
 	else {
 		struct atm_dev *dev = NULL;
-		struct list_head *p;
+		struct list_head *p, *next;
 
-		spin_lock (&atm_dev_lock);
-		list_for_each(p, &atm_devs) {
+		spin_lock(&atm_dev_lock);
+		list_for_each_safe(p, next, &atm_devs) {
 			dev = list_entry(p, struct atm_dev, dev_list);
-			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+			atm_dev_hold(dev);
+			spin_unlock(&atm_dev_lock);
+			if (!atm_do_connect_dev(vcc,dev,vpi,vci))
+				break;
+			atm_dev_release(dev);
 			dev = NULL;
+			spin_lock(&atm_dev_lock);
 		}
-		spin_unlock (&atm_dev_lock);
+		spin_unlock(&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -565,7 +569,6 @@
 	int error,len,size,number, ret_val;
 
 	ret_val = 0;
-	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
@@ -603,14 +606,17 @@
 				goto done;
 			}
 			size = 0;
+			spin_lock(&atm_dev_lock);
 			list_for_each(p, &atm_devs)
 				size += sizeof(int);
 			if (size > len) {
+				spin_unlock(&atm_dev_lock);
 				ret_val = -E2BIG;
 				goto done;
 			}
-			tmp_buf = kmalloc(size,GFP_KERNEL);
+			tmp_buf = kmalloc(size, GFP_ATOMIC);
 			if (!tmp_buf) {
+				spin_unlock(&atm_dev_lock);
 				ret_val = -ENOMEM;
 				goto done;
 			}
@@ -619,6 +625,7 @@
 				dev = list_entry(p, struct atm_dev, dev_list);
 				*tmp_p++ = dev->number;
 			}
+			spin_unlock(&atm_dev_lock);
 		        ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
 			    put_user(size, &((struct atm_iobuf *) arg)->length)
 			    ) ? -EFAULT : 0;
@@ -845,7 +852,7 @@
 		ret_val = -EFAULT;
 		goto done;
 	}
-	if (!(dev = atm_find_dev(number))) {
+	if (!(dev = atm_dev_lookup(number))) {
 		ret_val = -ENODEV;
 		goto done;
 	}
@@ -856,14 +863,14 @@
 			size = strlen(dev->type)+1;
 			if (copy_to_user(buf,dev->type,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
 			if (copy_to_user(buf,dev->esi,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_SETESI:
@@ -873,7 +880,7 @@
 				for (i = 0; i < ESI_LEN; i++)
 					if (dev->esi[i]) {
 						ret_val = -EEXIST;
-						goto done;
+						goto done_release;
 					}
 			}
 			/* fall through */
@@ -883,20 +890,20 @@
 
 				if (!capable(CAP_NET_ADMIN)) {
 					ret_val = -EPERM;
-					goto done;
+					goto done_release;
 				}
 				if (copy_from_user(esi,buf,ESI_LEN)) {
 					ret_val = -EFAULT;
-					goto done;
+					goto done_release;
 				}
 				memcpy(dev->esi,esi,ESI_LEN);
 				ret_val =  ESI_LEN;
-				goto done;
+				goto done_release;
 			}
 		case ATM_GETSTATZ:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			/* fall through */
 		case ATM_GETSTAT:
@@ -904,27 +911,27 @@
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
 			if (error) {
 				ret_val = error;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
 			if (copy_to_user(buf,&dev->ci_range,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
 			if (copy_to_user(buf,&dev->link_rate,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_RSTADDR:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			atm_reset_addr(dev);
 			break;
@@ -932,20 +939,20 @@
 		case ATM_DELADDR:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			{
 				struct sockaddr_atmsvc addr;
 
 				if (copy_from_user(&addr,buf,sizeof(addr))) {
 					ret_val = -EFAULT;
-					goto done;
+					goto done_release;
 				}
 				if (cmd == ATM_ADDADDR)
 					ret_val = atm_add_addr(dev,&addr);
 				else
 					ret_val = atm_del_addr(dev,&addr);
-				goto done;
+				goto done_release;
 			}
 		case ATM_GETADDR:
 			size = atm_get_addr(dev,buf,len);
@@ -956,13 +963,13 @@
 			   write the length" */
 				ret_val = put_user(size,
 						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
-			goto done;
+			goto done_release;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
 			    __ATM_LM_XTRMT((int) (long) buf)) {
 				ret_val = -EINVAL;
-				goto done;
+				goto done_release;
 			}
 			/* fall through */
 		case ATM_SETCIRANGE:
@@ -972,18 +979,18 @@
 		case SONET_SETFRAMING:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			/* fall through */
 		default:
 			if (!dev->ops->ioctl) {
 				ret_val = -EINVAL;
-				goto done;
+				goto done_release;
 			}
 			size = dev->ops->ioctl(dev,cmd,buf);
 			if (size < 0) {
 				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
-				goto done;
+				goto done_release;
 			}
 	}
 	
@@ -992,9 +999,10 @@
 			-EFAULT : 0;
 	else
 		ret_val = 0;
+done_release:
+	atm_dev_release(dev);
 
- done:
-	spin_unlock (&atm_dev_lock); 
+done:
 	return ret_val;
 }
 
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/lec.c	Mon Jun 30 13:23:17 2003
@@ -550,20 +550,15 @@
 }
 
 static struct atmdev_ops lecdev_ops = {
-        close:	lec_atm_close,
-        send:	lec_atm_send
+	.close	= lec_atm_close,
+	.send	= lec_atm_send
 };
 
 static struct atm_dev lecatm_dev = {
-        &lecdev_ops,
-        NULL,	    /*PHY*/
-        "lec",	    /*type*/
-        999,	    /*dummy device number*/
-        NULL,NULL,  /*no VCCs*/
-        NULL,NULL,  /*no data*/
-        { 0 },	    /*no flags*/
-        NULL,	    /* no local address*/
-        { 0 }	    /*no ESI or rest of the atm_dev struct things*/
+	.ops	= &lecdev_ops,
+	.type	= "lec",
+	.number	= 999,
+	.lock	= SPIN_LOCK_UNLOCKED
 };
 
 /*
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/mpc.c	Mon Jun 30 13:23:17 2003
@@ -736,22 +736,15 @@
 }
 
 static struct atmdev_ops mpc_ops = { /* only send is required */
-	close:	mpoad_close,
-	send:	msg_from_mpoad
+	.close	= mpoad_close,
+	.send	= msg_from_mpoad
 };
 
 static struct atm_dev mpc_dev = {
-	&mpc_ops,       /* device operations    */
-	NULL,           /* PHY operations       */
-	"mpc",          /* device type name     */
-	42,             /* device index (dummy) */
-	NULL,           /* VCC table            */
-	NULL,           /* last VCC             */
-	NULL,           /* per-device data      */
-	NULL,           /* private PHY data     */
-	{ 0 },          /* device flags         */
-	NULL,           /* local ATM address    */
-	{ 0 }           /* no ESI               */
+	.ops	= &mpc_ops,
+	.type	= "mpc",
+	.number	= 42,
+	.lock	= SPIN_LOCK_UNLOCKED
 	/* rest of the members will be 0 */
 };
 
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/proc.c	Mon Jun 30 13:23:17 2003
@@ -84,6 +84,7 @@
 	add_stats(buf,"0",&dev->stats.aal0);
 	strcat(buf,"  ");
 	add_stats(buf,"5",&dev->stats.aal5);
+	sprintf(strchr(buf,0), "\t[%d]", atomic_read(&dev->refcnt));
 	strcat(buf,"\n");
 }
 
@@ -161,7 +162,7 @@
 #endif
 
 
-static void pvc_info(struct atm_vcc *vcc,char *buf)
+static void pvc_info(struct atm_vcc *vcc, char *buf, int clip_info)
 {
 	static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
 	static const char *aal_name[] = {
@@ -178,20 +179,17 @@
 	    class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
 	    class_name[vcc->qos.txtp.traffic_class]);
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-	if (try_atm_clip_ops()) {
-		if (vcc->push == atm_clip_ops->clip_push) {
-			struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
-			struct net_device *dev;
-
-			dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
-			off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
-			    dev ? dev->name : "none?");
-			if (clip_vcc->encap)
-				off += sprintf(buf+off,"LLC/SNAP");
-			else
-				off += sprintf(buf+off,"None");
-		}
-		__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
+	if (clip_info && (vcc->push == atm_clip_ops->clip_push)) {
+		struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
+		struct net_device *dev;
+
+		dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
+		off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
+		    dev ? dev->name : "none?");
+		if (clip_vcc->encap)
+			off += sprintf(buf+off,"LLC/SNAP");
+		else
+			off += sprintf(buf+off,"None");
 	}
 #endif
 	strcpy(buf+off,"\n");
@@ -312,16 +310,19 @@
 
 	if (!pos) {
 		return sprintf(buf,"Itf Type    ESI/\"MAC\"addr "
-		    "AAL(TX,err,RX,err,drop) ...\n");
+		    "AAL(TX,err,RX,err,drop) ...               [refcnt]\n");
 	}
 	left = pos-1;
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
 		if (left-- == 0) {
 			dev_info(dev,buf);
+			spin_unlock(&atm_dev_lock);
 			return strlen(buf);
 		}
 	}
+	spin_unlock(&atm_dev_lock);
 	return 0;
 }
 
@@ -332,31 +333,50 @@
 
 static int atm_pvc_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 	struct atm_vcc *vcc;
-	int left;
+	int left, clip_info = 0;
 
 	if (!pos) {
 		return sprintf(buf,"Itf VPI VCI   AAL RX(PCR,Class) "
 		    "TX(PCR,Class)\n");
 	}
 	left = pos-1;
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+	if (try_atm_clip_ops())
+		clip_info = 1;
+#endif
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->family == PF_ATMPVC &&
-			    vcc->dev && !left--) {
-				pvc_info(vcc,buf);
+			if (vcc->sk->family == PF_ATMPVC && vcc->dev && !left--) {
+				pvc_info(vcc,buf,clip_info);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				spin_unlock(&atm_dev_lock);
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+				if (clip_info)
+					__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
+#endif
 				return strlen(buf);
 			}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
+	spin_unlock(&atm_dev_lock);
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+	if (clip_info)
+		__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
+#endif
 	return 0;
 }
 
 
 static int atm_vc_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 	struct atm_vcc *vcc;
@@ -367,19 +387,20 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
 			if (!left--) {
 				vc_info(vcc,buf);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				spin_unlock(&atm_dev_lock);
 				return strlen(buf);
 			}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	for (vcc = nodev_vccs; vcc; vcc = vcc->next)
-		if (!left--) {
-			vc_info(vcc,buf);
-			return strlen(buf);
-		}
+	spin_unlock(&atm_dev_lock);
 
 	return 0;
 }
@@ -387,6 +408,7 @@
 
 static int atm_svc_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 	struct atm_vcc *vcc;
@@ -395,19 +417,21 @@
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
 			if (vcc->sk->family == PF_ATMSVC && !left--) {
 				svc_info(vcc,buf);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				spin_unlock(&atm_dev_lock);
 				return strlen(buf);
 			}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	for (vcc = nodev_vccs; vcc; vcc = vcc->next)
-		if (vcc->sk->family == PF_ATMSVC && !left--) {
-			svc_info(vcc,buf);
-			return strlen(buf);
-		}
+	spin_unlock(&atm_dev_lock);
+
 	return 0;
 }
 
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/resources.c	Mon Jun 30 13:23:17 2003
@@ -23,67 +23,83 @@
 
 
 LIST_HEAD(atm_devs);
-struct atm_vcc *nodev_vccs = NULL;
-extern spinlock_t atm_dev_lock;
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 
-static struct atm_dev *alloc_atm_dev(const char *type)
+static struct atm_dev *__alloc_atm_dev(const char *type)
 {
 	struct atm_dev *dev;
 
 	dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
-	if (!dev) return NULL;
-	memset(dev,0,sizeof(*dev));
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
-	list_add_tail(&dev->dev_list, &atm_devs);
+	spin_lock_init(&dev->lock);
 
 	return dev;
 }
 
 
-static void free_atm_dev(struct atm_dev *dev)
+static void __free_atm_dev(struct atm_dev *dev)
 {
-	list_del(&dev->dev_list);
 	kfree(dev);
 }
 
-struct atm_dev *atm_find_dev(int number)
+static struct atm_dev *__atm_dev_lookup(int number)
 {
 	struct atm_dev *dev;
 	struct list_head *p;
 
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
-		if (dev->ops && dev->number == number)
+		if ((dev->ops) && (dev->number == number)) {
+			atm_dev_hold(dev);
 			return dev;
+		}
 	}
 	return NULL;
 }
 
-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
-    int number,atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_lookup(int number)
 {
-	struct atm_dev *dev = NULL;
+	struct atm_dev *dev;
 
 	spin_lock(&atm_dev_lock);
+	dev = __atm_dev_lookup(number);
+	spin_unlock(&atm_dev_lock);
+	return dev;
+}
 
-	dev = alloc_atm_dev(type);
+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+				 int number, atm_dev_flags_t *flags)
+{
+	struct atm_dev *dev, *inuse;
+
+
+	dev = __alloc_atm_dev(type);
 	if (!dev) {
 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
 		    type);
-		goto done;
+		return NULL;
 	}
+	spin_lock(&atm_dev_lock);
 	if (number != -1) {
-		if (atm_find_dev(number)) {
-			free_atm_dev(dev);
+		if ((inuse = __atm_dev_lookup(number))) {
+			atm_dev_release(inuse);
+			spin_unlock(&atm_dev_lock);
+			__free_atm_dev(dev);
 			return NULL;
 		}
 		dev->number = number;
 	} else {
 		dev->number = 0;
-		while (atm_find_dev(dev->number)) dev->number++;
+		while ((inuse = __atm_dev_lookup(dev->number))) {
+			atm_dev_release(inuse);
+			dev->number++;
+		}
 	}
 	dev->vccs = dev->last = NULL;
 	dev->dev_data = NULL;
@@ -92,41 +108,66 @@
 	if (flags) 
 		dev->flags = *flags;
 	else 
-		memset(&dev->flags,0,sizeof(dev->flags));
-	memset((void *) &dev->stats,0,sizeof(dev->stats));
+		memset(&dev->flags, 0, sizeof(dev->flags));
+	memset(&dev->stats, 0, sizeof(dev->stats));
+	atomic_set(&dev->refcnt, 1);
+	list_add_tail(&dev->dev_list, &atm_devs);
+	spin_unlock(&atm_dev_lock);
+
 #ifdef CONFIG_PROC_FS
-	if (ops->proc_read)
+	if (ops->proc_read) {
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
-			    "atm_proc_dev_register failed for dev %s\n",type);
-			free_atm_dev(dev);
-			goto done;
+			       "atm_proc_dev_register failed for dev %s\n",
+			       type);
+			spin_lock(&atm_dev_lock);
+			list_del(&dev->dev_list);
+			spin_unlock(&atm_dev_lock);
+			__free_atm_dev(dev);
+			return NULL;
 		}
+	}
 #endif
 
-done:
-	spin_unlock(&atm_dev_lock);
 	return dev;
 }
 
 
 void atm_dev_deregister(struct atm_dev *dev)
 {
+	unsigned long warning_time;
+
 #ifdef CONFIG_PROC_FS
 	if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
 #endif
 	spin_lock(&atm_dev_lock);
-	free_atm_dev(dev);
+	list_del(&dev->dev_list);
 	spin_unlock(&atm_dev_lock);
+
+	warning_time = jiffies;
+	while (atomic_read(&dev->refcnt) != 1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ / 4);
+		current->state = TASK_RUNNING;
+		if ((jiffies - warning_time) > 10 * HZ) {
+			printk(KERN_EMERG "atm_dev_deregister: waiting for "
+			       "dev %d to become free. Usage count = %d\n",
+			       dev->number, atomic_read(&dev->refcnt));
+			warning_time = jiffies;
+		}
+	}
+
+	__free_atm_dev(dev);
 }
 
 void shutdown_atm_dev(struct atm_dev *dev)
 {
-	if (dev->vccs) {
-		set_bit(ATM_DF_CLOSE,&dev->flags);
+	if (atomic_read(&dev->refcnt) > 1) {
+		set_bit(ATM_DF_CLOSE, &dev->flags);
 		return;
 	}
-	if (dev->ops->dev_close) dev->ops->dev_close(dev);
+	if (dev->ops->dev_close)
+		dev->ops->dev_close(dev);
 	atm_dev_deregister(dev);
 }
 
@@ -143,66 +184,69 @@
 	struct atm_vcc *vcc;
 
 	sk = sk_alloc(family, GFP_KERNEL, 1);
-	if (!sk) return NULL;
-	vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL);
+	if (!sk)
+		return NULL;
+	vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc), GFP_KERNEL);
 	if (!vcc) {
 		sk_free(sk);
 		return NULL;
 	}
-	sock_init_data(NULL,sk);
+	sock_init_data(NULL, sk);
 	sk->destruct = atm_free_sock;
-	memset(vcc,0,sizeof(*vcc));
+	memset(vcc, 0, sizeof(*vcc));
 	vcc->sk = sk;
-	if (nodev_vccs) nodev_vccs->prev = vcc;
-	vcc->prev = NULL;
-	vcc->next = nodev_vccs;
-	nodev_vccs = vcc;
+
 	return sk;
 }
 
 
-static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
+static void unlink_vcc(struct atm_vcc *vcc)
 {
-	if (vcc->prev) vcc->prev->next = vcc->next;
-	else if (vcc->dev) vcc->dev->vccs = vcc->next;
-	    else nodev_vccs = vcc->next;
-	if (vcc->next) vcc->next->prev = vcc->prev;
-	else if (vcc->dev) vcc->dev->last = vcc->prev;
-	if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
-	    test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
-		shutdown_atm_dev(vcc->dev);
+	unsigned long flags;
+	if (vcc->dev) {
+		spin_lock_irqsave(&vcc->dev->lock, flags);
+		if (vcc->prev)
+			vcc->prev->next = vcc->next;
+		else
+			vcc->dev->vccs = vcc->next;
+
+		if (vcc->next)
+			vcc->next->prev = vcc->prev;
+		else
+			vcc->dev->last = vcc->prev;
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	}
 }
 
 
+
 void free_atm_vcc_sk(struct sock *sk)
 {
-	unlink_vcc(sk->protinfo.af_atm,NULL);
+	unlink_vcc(sk->protinfo.af_atm);
 	sk_free(sk);
 }
 
 
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
 {
-	unlink_vcc(vcc,dev);
+	unsigned long flags;
+
+	unlink_vcc(vcc);
 	vcc->dev = dev;
 	if (dev) {
+		spin_lock_irqsave(&dev->lock, flags);
 		vcc->next = NULL;
 		vcc->prev = dev->last;
 		if (dev->vccs) dev->last->next = vcc;
 		else dev->vccs = vcc;
 		dev->last = vcc;
-	}
-	else {
-		if (nodev_vccs) nodev_vccs->prev = vcc;
-		vcc->next = nodev_vccs;
-		vcc->prev = NULL;
-		nodev_vccs = vcc;
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
 }
 
 
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
-EXPORT_SYMBOL(atm_find_dev);
+EXPORT_SYMBOL(atm_dev_lookup);
 EXPORT_SYMBOL(shutdown_atm_dev);
 EXPORT_SYMBOL(bind_vcc);
diff -Nru a/net/atm/resources.h b/net/atm/resources.h
--- a/net/atm/resources.h	Mon Jun 30 13:23:17 2003
+++ b/net/atm/resources.h	Mon Jun 30 13:23:17 2003
@@ -11,7 +11,7 @@
 
 
 extern struct list_head atm_devs;
-extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */
+extern spinlock_t atm_dev_lock;
 
 
 struct sock *alloc_atm_vcc_sk(int family);
diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c	Mon Jun 30 13:23:17 2003
+++ b/net/atm/signaling.c	Mon Jun 30 13:23:17 2003
@@ -33,7 +33,6 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
-extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -211,6 +210,7 @@
 
 static void sigd_close(struct atm_vcc *vcc)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 
@@ -219,33 +219,29 @@
 	if (skb_peek(&vcc->sk->receive_queue))
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	skb_queue_purge(&vcc->sk->receive_queue);
-	purge_vccs(nodev_vccs);
 
-	spin_lock (&atm_dev_lock);
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		purge_vccs(dev->vccs);
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	spin_unlock (&atm_dev_lock);
+	spin_unlock(&atm_dev_lock);
 }
 
 
 static struct atmdev_ops sigd_dev_ops = {
-	close:	sigd_close,
-	send:	sigd_send
+	.close =	sigd_close,
+	.send =		sigd_send
 };
 
 
 static struct atm_dev sigd_dev = {
-	&sigd_dev_ops,
-	NULL,		/* no PHY */
-    	"sig",		/* type */
-	999,		/* dummy device number */
-	NULL,NULL,	/* pretend not to have any VCCs */
-	NULL,NULL,	/* no data */
-	{ 0 },		/* no flags */
-	NULL,		/* no local address */
-	{ 0 }		/* no ESI, no statistics */
+	.ops =		&sigd_dev_ops,
+	.type =		"sig",
+	.number =	999,
+	.lock =		SPIN_LOCK_UNLOCKED
 };
 
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Copyright © 2003, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds