diff options
| author | Jody McIntyre <scjody@modernduck.com> | 2005-02-09 08:19:10 -0500 |
|---|---|---|
| committer | Jody McIntyre <scjody@modernduck.com> | 2005-02-09 08:19:10 -0500 |
| commit | 23750010bfa81de0867ddd4bd4bd7c9b2d27fe05 (patch) | |
| tree | 0b0b2ff8aab00bf3dcb5753a2e7a1217194c1312 | |
| parent | c5ff533d2618c3c26242551e2a9957763f126e2c (diff) | |
| parent | 245f9eba891010ed627fec5b83d0f7b575e3d5ce (diff) | |
Merge modernduck.com:/usr/src/bk/linux-2.5
into modernduck.com:/usr/src/bk/1394-2.6
48 files changed, 604 insertions, 340 deletions
diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt new file mode 100644 index 000000000000..fcf1c086f0ba --- /dev/null +++ b/Documentation/nommu-mmap.txt @@ -0,0 +1,141 @@ + ============================= + NO-MMU MEMORY MAPPING SUPPORT + ============================= + +The kernel has limited support for memory mapping under no-MMU conditions, such +as are used in uClinux environments. From the userspace point of view, memory +mapping is made use of in conjunction with the mmap() system call, the shmat() +call and the execve() system call. From the kernel's point of view, execve() +mapping is actually performed by the binfmt drivers, which call back into the +mmap() routines to do the actual work. + +Memory mapping behaviour also involves the way fork(), vfork(), clone() and +ptrace() work. Under uClinux there is no fork(), and clone() must be supplied +the CLONE_VM flag. + +The behaviour is similar between the MMU and no-MMU cases, but not identical; +and it's also much more restricted in the latter case: + + (*) Anonymous mapping, MAP_PRIVATE + + In the MMU case: VM regions backed by arbitrary pages; copy-on-write + across fork. + + In the no-MMU case: VM regions backed by arbitrary contiguous runs of + pages. + + (*) Anonymous mapping, MAP_SHARED + + These behave very much like private mappings, except that they're + shared across fork() or clone() without CLONE_VM in the MMU case. Since + the no-MMU case doesn't support these, behaviour is identical to + MAP_PRIVATE there. + + (*) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, !PROT_WRITE + + In the MMU case: VM regions backed by pages read from file; changes to + the underlying file are reflected in the mapping; copied across fork. + + In the no-MMU case: VM regions backed by arbitrary contiguous runs of + pages into which the appropriate bit of the file is read; any remaining + bit of the mapping is cleared; such mappings are shared if possible; + writes to the file do not affect the mapping; writes to the mapping are + visible in other processes (no MMU protection), but should not happen. + + (*) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, PROT_WRITE + + In the MMU case: like the non-PROT_WRITE case, except that the pages in + question get copied before the write actually happens. From that point + on writes to that page in the file no longer get reflected into the + mapping's backing pages. + + In the no-MMU case: works exactly as for the non-PROT_WRITE case. + + (*) Regular file / blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE + + In the MMU case: VM regions backed by pages read from file; changes to + pages written back to file; writes to file reflected into pages backing + mapping; shared across fork. + + In the no-MMU case: not supported. + + (*) Memory backed regular file, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE + + In the MMU case: As for ordinary regular files. + + In the no-MMU case: The filesystem providing the memory-backed file + (such as ramfs or tmpfs) may choose to honour an open, truncate, mmap + sequence by providing a contiguous sequence of pages to map. In that + case, a shared-writable memory mapping will be possible. It will work + as for the MMU case. If the filesystem does not provide any such + support, then the mapping request will be denied. + + (*) Memory backed chardev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE + + In the MMU case: As for ordinary regular files. + + In the no-MMU case: The character device driver may choose to honour + the mmap() by providing direct access to the underlying device if it + provides memory or quasi-memory that can be accessed directly. Examples + of such are frame buffers and flash devices. If the driver does not + provide any such support, then the mapping request will be denied. + + +============================ +FURTHER NOTES ON NO-MMU MMAP +============================ + + (*) A request for a private mapping of less than a page in size may not return + a page-aligned buffer. This is because the kernel calls kmalloc() to + allocate the buffer, not get_free_page(). + + (*) A list of all the mappings on the system is visible through /proc/maps in + no-MMU mode. + + (*) Supplying MAP_FIXED or a requesting a particular mapping address will + result in an error. + + (*) Files mapped privately must have a read method provided by the driver or + filesystem so that the contents can be read into the memory allocated. An + error will result if they don't. This is most likely to be encountered + with character device files, pipes, fifos and sockets. + + +============================================ +PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT +============================================ + +To provide shareable character device support, a driver must provide a +file->f_op->get_unmapped_area() operation. The mmap() routines will call this +to get a proposed address for the mapping. This may return an error if it +doesn't wish to honour the mapping because it's too long, at a weird offset, +under some unsupported combination of flags or whatever. + +The vm_ops->close() routine will be invoked when the last mapping on a chardev +is removed. An existing mapping will be shared, partially or not, if possible +without notifying the driver. + +It is permitted also for the file->f_op->get_unmapped_area() operation to +return -ENOSYS. This will be taken to mean that this operation just doesn't +want to handle it, despite the fact it's got an operation. For instance, it +might try directing the call to a secondary driver which turns out not to +implement it. Such is the case for the framebuffer driver which attempts to +direct the call to the device-specific driver. + + +============================================== +PROVIDING SHAREABLE MEMORY-BACKED FILE SUPPORT +============================================== + +Provision of shared mappings on memory backed files is similar to the provision +of support for shared mapped character devices. The main difference is that the +filesystem providing the service will probably allocate a contiguous collection +of pages and permit mappings to be made on that. + +It is recommended that a truncate operation applied to such a file that +increases the file size, if that file is empty, be taken as a request to gather +enough pages to honour a mapping. This is required to support POSIX shared +memory. + +Memory backed devices are indicated by the mapping's backing device info having +the memory_backed flag set. diff --git a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S index 0c7329f9c38a..db82ee468248 100644 --- a/arch/arm/mm/tlb-v4.S +++ b/arch/arm/mm/tlb-v4.S @@ -44,7 +44,7 @@ ENTRY(v4_flush_user_tlb_range) mov pc, lr /* - * v4_flush_kerm_tlb_range(start, end) + * v4_flush_kern_tlb_range(start, end) * * Invalidate a range of TLB entries in the specified kernel * address range. diff --git a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S index 15dc83d10397..7908d5f1f130 100644 --- a/arch/arm/mm/tlb-v4wb.S +++ b/arch/arm/mm/tlb-v4wb.S @@ -47,7 +47,7 @@ ENTRY(v4wb_flush_user_tlb_range) mov pc, lr /* - * v4_flush_kerm_tlb_range(start, end) + * v4_flush_kern_tlb_range(start, end) * * Invalidate a range of TLB entries in the specified kernel * address range. diff --git a/arch/mips/lib-32/dump_tlb.c b/arch/mips/lib-32/dump_tlb.c index b92fea6927ea..019ac8f005d7 100644 --- a/arch/mips/lib-32/dump_tlb.c +++ b/arch/mips/lib-32/dump_tlb.c @@ -32,6 +32,8 @@ static inline const char *msk2str(unsigned int mask) case PM_256M: return "256Mb"; #endif } + + return "unknown"; } #define BARRIER() \ diff --git a/arch/mips/lib-64/dump_tlb.c b/arch/mips/lib-64/dump_tlb.c index 2a422948c7dc..42f88e055b4c 100644 --- a/arch/mips/lib-64/dump_tlb.c +++ b/arch/mips/lib-64/dump_tlb.c @@ -32,6 +32,8 @@ static inline const char *msk2str(unsigned int mask) case PM_256M: return "256Mb"; #endif } + + return "unknown"; } #define BARRIER() \ diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 79917803c92d..5fe6aaabd05f 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.11-rc1 -# Fri Jan 21 20:03:21 2005 +# Linux kernel version: 2.6.11-rc3 +# Mon Feb 7 15:29:00 2005 # CONFIG_64BIT=y CONFIG_MMU=y @@ -845,6 +845,7 @@ CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_BCSP_TXCRC=y CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m CONFIG_BT_HCIVHCI=m CONFIG_NETDEVICES=y @@ -1245,7 +1246,12 @@ CONFIG_JFS_SECURITY=y # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set CONFIG_FS_POSIX_ACL=y + +# +# XFS support +# CONFIG_XFS_FS=m +CONFIG_XFS_EXPORT=y # CONFIG_XFS_RT is not set CONFIG_XFS_QUOTA=y CONFIG_XFS_SECURITY=y @@ -1520,6 +1526,11 @@ CONFIG_DVB_ATMEL_AT76C651=m CONFIG_DVB_VES1820=m CONFIG_DVB_TDA10021=m CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terresterial DTV) frontends +# +CONFIG_DVB_NXT2002=m CONFIG_VIDEO_SAA7146=m CONFIG_VIDEO_SAA7146_VV=m CONFIG_VIDEO_VIDEOBUF=m @@ -1527,6 +1538,7 @@ CONFIG_VIDEO_TUNER=m CONFIG_VIDEO_BUF=m CONFIG_VIDEO_BTCX=m CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m # # Sound diff --git a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c index 58ec56050b9e..0278e34125db 100644 --- a/arch/sparc64/lib/user_fixup.c +++ b/arch/sparc64/lib/user_fixup.c @@ -20,11 +20,12 @@ unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned l char *dst = to; const char __user *src = from; - while (size--) { + while (size) { if (__get_user(*dst, src)) break; dst++; src++; + size--; } if (size) @@ -38,11 +39,12 @@ unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned lon char __user *dst = to; const char *src = from; - while (size--) { + while (size) { if (__put_user(*src, dst)) break; dst++; src++; + size--; } return size; @@ -53,7 +55,7 @@ unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned lo char __user *dst = to; char __user *src = from; - while (size--) { + while (size) { char tmp; if (__get_user(tmp, src)) @@ -62,6 +64,7 @@ unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned lo break; dst++; src++; + size--; } return size; diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index c340c9cbf19b..867dff072934 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -11,3 +11,5 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +subdir- := util diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a3abfb89d7cb..06e791f3b65d 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -1748,12 +1748,16 @@ static int agp_intel_resume(struct pci_dev *pdev) if (bridge->driver == &intel_generic_driver) intel_configure(); + else if (bridge->driver == &intel_850_driver) + intel_850_configure(); else if (bridge->driver == &intel_845_driver) intel_845_configure(); else if (bridge->driver == &intel_830mp_driver) intel_830mp_configure(); else if (bridge->driver == &intel_915_driver) intel_i915_configure(); + else if (bridge->driver == &intel_830_driver) + intel_i830_configure(); return 0; } diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index d216c28fb669..5845d986e6ec 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -516,7 +516,7 @@ int drm_ioctl( struct inode *inode, struct file *filp, if (nr < DRIVER_IOCTL_COUNT) ioctl = &drm_ioctls[nr]; - else if ((nr >= DRM_COMMAND_BASE) || (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + else if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; else goto err_i1; diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 9870cc3283b1..3247e14b564f 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -96,9 +96,6 @@ static __inline__ int mtrr_del (int reg, unsigned long base, __copy_to_user(arg1, arg2, arg3) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ __get_user(val, uaddr) -#define DRM_PUT_USER_UNCHECKED(uaddr, val) \ - __put_user(val, uaddr) - #define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 4fdcc2836f69..ce4ea6969ea5 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -1027,25 +1027,27 @@ do { \ } while (0) -#define OUT_RING_USER_TABLE( tab, sz ) do { \ +#define OUT_RING_TABLE( tab, sz ) do { \ int _size = (sz); \ - int __user *_tab = (tab); \ + int *_tab = (int *)(tab); \ \ if (write + _size > mask) { \ - int i = (mask+1) - write; \ - if (DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \ - _tab, i*4 )) \ - return DRM_ERR(EFAULT); \ + int _i = (mask+1) - write; \ + _size -= _i; \ + while (_i > 0 ) { \ + *(int *)(ring + write) = *_tab++; \ + write++; \ + _i--; \ + } \ write = 0; \ - _size -= i; \ - _tab += i; \ + _tab += _i; \ } \ \ - if (_size && DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \ - _tab, _size*4 )) \ - return DRM_ERR(EFAULT); \ - \ - write += _size; \ + while (_size > 0) { \ + *(ring + write) = *_tab++; \ + write++; \ + _size--; \ + } \ write &= mask; \ } while (0) diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 6a0f129f7bc9..b8d38e106708 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -93,21 +93,6 @@ static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_p return 0; } -static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv, - drm_file_t *filp_priv, - u32 __user *offset ) { - u32 off; - - DRM_GET_USER_UNCHECKED( off, offset ); - - if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) ) - return DRM_ERR( EINVAL ); - - DRM_PUT_USER_UNCHECKED( offset, off ); - - return 0; -} - static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv, drm_file_t *filp_priv, int id, @@ -115,18 +100,18 @@ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_ switch ( id ) { case RADEON_EMIT_PP_MISC: - if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv, - &data[( RADEON_RB3D_DEPTHOFFSET - - RADEON_PP_MISC ) / 4] ) ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &data[( RADEON_RB3D_DEPTHOFFSET + - RADEON_PP_MISC ) / 4] ) ) { DRM_ERROR( "Invalid depth buffer offset\n" ); return DRM_ERR( EINVAL ); } break; case RADEON_EMIT_PP_CNTL: - if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv, - &data[( RADEON_RB3D_COLOROFFSET - - RADEON_PP_CNTL ) / 4] ) ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &data[( RADEON_RB3D_COLOROFFSET + - RADEON_PP_CNTL ) / 4] ) ) { DRM_ERROR( "Invalid colour buffer offset\n" ); return DRM_ERR( EINVAL ); } @@ -138,8 +123,8 @@ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_ case R200_EMIT_PP_TXOFFSET_3: case R200_EMIT_PP_TXOFFSET_4: case R200_EMIT_PP_TXOFFSET_5: - if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv, - &data[0] ) ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &data[0] ) ) { DRM_ERROR( "Invalid R200 texture offset\n" ); return DRM_ERR( EINVAL ); } @@ -148,9 +133,9 @@ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_ case RADEON_EMIT_PP_TXFILTER_0: case RADEON_EMIT_PP_TXFILTER_1: case RADEON_EMIT_PP_TXFILTER_2: - if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv, - &data[( RADEON_PP_TXOFFSET_0 - - RADEON_PP_TXFILTER_0 ) / 4] ) ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &data[( RADEON_PP_TXOFFSET_0 + - RADEON_PP_TXFILTER_0 ) / 4] ) ) { DRM_ERROR( "Invalid R100 texture offset\n" ); return DRM_ERR( EINVAL ); } @@ -164,9 +149,8 @@ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_ case R200_EMIT_PP_CUBIC_OFFSETS_5: { int i; for ( i = 0; i < 5; i++ ) { - if ( radeon_check_and_fixup_offset_user( dev_priv, - filp_priv, - &data[i] ) ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &data[i] ) ) { DRM_ERROR( "Invalid R200 cubic texture offset\n" ); return DRM_ERR( EINVAL ); } @@ -250,17 +234,11 @@ static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_ drm_file_t *filp_priv, drm_radeon_cmd_buffer_t *cmdbuf, unsigned int *cmdsz ) { - u32 tmp[4]; - u32 __user *cmd = (u32 __user *)cmdbuf->buf; - - if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) { - DRM_ERROR( "Failed to copy data from user space\n" ); - return DRM_ERR( EFAULT ); - } + u32 *cmd = (u32 *) cmdbuf->buf; - *cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 ); + *cmdsz = 2 + ( ( cmd[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 ); - if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) { + if ( ( cmd[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) { DRM_ERROR( "Not a type 3 packet\n" ); return DRM_ERR( EINVAL ); } @@ -271,32 +249,27 @@ static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_ } /* Check client state and fix it up if necessary */ - if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */ + if ( cmd[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */ u32 offset; - if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL + if ( cmd[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { - offset = tmp[2] << 10; + offset = cmd[2] << 10; if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) { DRM_ERROR( "Invalid first packet offset\n" ); return DRM_ERR( EINVAL ); } - tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10; + cmd[2] = ( cmd[2] & 0xffc00000 ) | offset >> 10; } - if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) && - ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { - offset = tmp[3] << 10; + if ( ( cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) && + ( cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { + offset = cmd[3] << 10; if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) { DRM_ERROR( "Invalid second packet offset\n" ); return DRM_ERR( EINVAL ); } - tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10; - } - - if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) { - DRM_ERROR( "Failed to copy data to user space\n" ); - return DRM_ERR( EFAULT ); + cmd[3] = ( cmd[3] & 0xffc00000 ) | offset >> 10; } } @@ -2473,7 +2446,7 @@ static int radeon_emit_packets( { int id = (int)header.packet.packet_id; int sz, reg; - int __user *data = (int __user *)cmdbuf->buf; + int *data = (int *)cmdbuf->buf; RING_LOCALS; if (id >= RADEON_MAX_STATE_PACKETS) @@ -2494,7 +2467,7 @@ static int radeon_emit_packets( BEGIN_RING(sz+1); OUT_RING( CP_PACKET0( reg, (sz-1) ) ); - OUT_RING_USER_TABLE( data, sz ); + OUT_RING_TABLE( data, sz ); ADVANCE_RING(); cmdbuf->buf += sz * sizeof(int); @@ -2508,7 +2481,6 @@ static __inline__ int radeon_emit_scalars( drm_radeon_cmd_buffer_t *cmdbuf ) { int sz = header.scalars.count; - int __user *data = (int __user *)cmdbuf->buf; int start = header.scalars.offset; int stride = header.scalars.stride; RING_LOCALS; @@ -2517,7 +2489,7 @@ static __inline__ int radeon_emit_scalars( OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) ); OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT)); OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) ); - OUT_RING_USER_TABLE( data, sz ); + OUT_RING_TABLE( cmdbuf->buf, sz ); ADVANCE_RING(); cmdbuf->buf += sz * sizeof(int); cmdbuf->bufsz -= sz * sizeof(int); @@ -2532,7 +2504,6 @@ static __inline__ int radeon_emit_scalars2( drm_radeon_cmd_buffer_t *cmdbuf ) { int sz = header.scalars.count; - int __user *data = (int __user *)cmdbuf->buf; int start = ((unsigned int)header.scalars.offset) + 0x100; int stride = header.scalars.stride; RING_LOCALS; @@ -2541,7 +2512,7 @@ static __inline__ int radeon_emit_scalars2( OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) ); OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT)); OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) ); - OUT_RING_USER_TABLE( data, sz ); + OUT_RING_TABLE( cmdbuf->buf, sz ); ADVANCE_RING(); cmdbuf->buf += sz * sizeof(int); cmdbuf->bufsz -= sz * sizeof(int); @@ -2554,7 +2525,6 @@ static __inline__ int radeon_emit_vectors( drm_radeon_cmd_buffer_t *cmdbuf ) { int sz = header.vectors.count; - int __user *data = (int __user *)cmdbuf->buf; int start = header.vectors.offset; int stride = header.vectors.stride; RING_LOCALS; @@ -2563,7 +2533,7 @@ static __inline__ int radeon_emit_vectors( OUT_RING( CP_PACKET0( RADEON_SE_TCL_VECTOR_INDX_REG, 0 ) ); OUT_RING( start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_VECTOR_DATA_REG, (sz-1) ) ); - OUT_RING_USER_TABLE( data, sz ); + OUT_RING_TABLE( cmdbuf->buf, sz ); ADVANCE_RING(); cmdbuf->buf += sz * sizeof(int); @@ -2578,7 +2548,6 @@ static int radeon_emit_packet3( drm_device_t *dev, { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int cmdsz; - int __user *cmd = (int __user *)cmdbuf->buf; int ret; RING_LOCALS; @@ -2591,7 +2560,7 @@ static int radeon_emit_packet3( drm_device_t *dev, } BEGIN_RING( cmdsz ); - OUT_RING_USER_TABLE( cmd, cmdsz ); + OUT_RING_TABLE( cmdbuf->buf, cmdsz ); ADVANCE_RING(); cmdbuf->buf += cmdsz * 4; @@ -2608,7 +2577,6 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev, drm_radeon_private_t *dev_priv = dev->dev_private; drm_clip_rect_t box; unsigned int cmdsz; - int __user *cmd = (int __user *)cmdbuf->buf; int ret; drm_clip_rect_t __user *boxes = cmdbuf->boxes; int i = 0; @@ -2627,7 +2595,7 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev, do { if ( i < cmdbuf->nbox ) { - if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) )) + if (DRM_COPY_FROM_USER( &box, &boxes[i], sizeof(box) )) return DRM_ERR(EFAULT); /* FIXME The second and subsequent times round * this loop, send a WAIT_UNTIL_3D_IDLE before @@ -2650,7 +2618,7 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev, } BEGIN_RING( cmdsz ); - OUT_RING_USER_TABLE( cmd, cmdsz ); + OUT_RING_TABLE( cmdbuf->buf, cmdsz ); ADVANCE_RING(); } while ( ++i < cmdbuf->nbox ); @@ -2703,7 +2671,8 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) int idx; drm_radeon_cmd_buffer_t cmdbuf; drm_radeon_cmd_header_t header; - int orig_nbox; + int orig_nbox, orig_bufsz; + char *kbuf=NULL; LOCK_TEST_WITH_RETURN( dev, filp ); @@ -2720,24 +2689,29 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); + if (cmdbuf.bufsz > 64*1024 || cmdbuf.bufsz<0) { + return DRM_ERR(EINVAL); + } - if (DRM_VERIFYAREA_READ( cmdbuf.buf, cmdbuf.bufsz )) - return DRM_ERR(EFAULT); - - if (cmdbuf.nbox && - DRM_VERIFYAREA_READ(cmdbuf.boxes, - cmdbuf.nbox * sizeof(drm_clip_rect_t))) - return DRM_ERR(EFAULT); + /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid + * races between checking values and using those values in other code, + * and simply to avoid a lot of function calls to copy in data. + */ + orig_bufsz = cmdbuf.bufsz; + if (orig_bufsz != 0) { + kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER); + if (kbuf == NULL) + return DRM_ERR(ENOMEM); + if (DRM_COPY_FROM_USER(kbuf, cmdbuf.buf, cmdbuf.bufsz)) + return DRM_ERR(EFAULT); + cmdbuf.buf = kbuf; + } orig_nbox = cmdbuf.nbox; while ( cmdbuf.bufsz >= sizeof(header) ) { - - if (DRM_GET_USER_UNCHECKED( header.i, (int __user *)cmdbuf.buf )) { - DRM_ERROR("__get_user %p\n", cmdbuf.buf); - return DRM_ERR(EFAULT); - } + header.i = *(int *)cmdbuf.buf; cmdbuf.buf += sizeof(header); cmdbuf.bufsz -= sizeof(header); @@ -2746,7 +2720,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_PACKET\n"); if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_packets failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; @@ -2754,7 +2728,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_SCALARS\n"); if (radeon_emit_scalars( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_scalars failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; @@ -2762,7 +2736,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_VECTORS\n"); if (radeon_emit_vectors( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_vectors failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; @@ -2772,14 +2746,14 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) if ( idx < 0 || idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", idx, dma->buf_count - 1 ); - return DRM_ERR(EINVAL); + goto err; } buf = dma->buflist[idx]; if ( buf->filp != filp || buf->pending ) { DRM_ERROR( "bad buffer %p %p %d\n", buf->filp, filp, buf->pending); - return DRM_ERR(EINVAL); + goto err; } radeon_cp_discard_buffer( dev, buf ); @@ -2789,7 +2763,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_PACKET3\n"); if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) { DRM_ERROR("radeon_emit_packet3 failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; @@ -2797,7 +2771,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) { DRM_ERROR("radeon_emit_packet3_clip failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; @@ -2805,7 +2779,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_SCALARS2\n"); if (radeon_emit_scalars2( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_scalars2 failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; @@ -2813,21 +2787,28 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_DEBUG("RADEON_CMD_WAIT\n"); if (radeon_emit_wait( dev, header.wait.flags )) { DRM_ERROR("radeon_emit_wait failed\n"); - return DRM_ERR(EINVAL); + goto err; } break; default: DRM_ERROR("bad cmd_type %d at %p\n", header.header.cmd_type, cmdbuf.buf - sizeof(header)); - return DRM_ERR(EINVAL); + goto err; } } + if (orig_bufsz != 0) + drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); DRM_DEBUG("DONE\n"); COMMIT_RING(); return 0; + +err: + if (orig_bufsz != 0) + drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + return DRM_ERR(EINVAL); } diff --git a/drivers/md/md.c b/drivers/md/md.c index 071b347b282b..68669ce10268 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -935,8 +935,8 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) max_dev = 0; ITERATE_RDEV(mddev,rdev2,tmp) - if (rdev2->desc_nr > max_dev) - max_dev = rdev2->desc_nr; + if (rdev2->desc_nr+1 > max_dev) + max_dev = rdev2->desc_nr+1; sb->max_dev = cpu_to_le32(max_dev); for (i=0; i<max_dev;i++) @@ -953,6 +953,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) } sb->recovery_offset = cpu_to_le64(0); /* not supported yet */ + sb->sb_csum = calc_sb_1_csum(sb); } @@ -1472,10 +1473,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) } disk->major = MAJOR(dev); disk->first_minor = unit << shift; - if (partitioned) + if (partitioned) { sprintf(disk->disk_name, "md_d%d", unit); - else + sprintf(disk->devfs_name, "md/d%d", unit); + } else { sprintf(disk->disk_name, "md%d", unit); + sprintf(disk->devfs_name, "md/%d", unit); + } disk->fops = &md_fops; disk->private_data = mddev; disk->queue = mddev->queue; @@ -2440,6 +2444,9 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev) { mdk_rdev_t *rdev; + if (mddev->pers == NULL) + return -ENODEV; + rdev = find_rdev(mddev, dev); if (!rdev) return -ENODEV; @@ -3362,10 +3369,12 @@ static void md_do_sync(mddev_t *mddev) init_waitqueue_head(&mddev->recovery_wait); last_check = 0; - if (j) + if (j>2) { printk(KERN_INFO "md: resuming recovery of %s from checkpoint.\n", mdname(mddev)); + mddev->curr_resync = j; + } while (j < max_sectors) { int sectors; @@ -3447,7 +3456,7 @@ static void md_do_sync(mddev_t *mddev) if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && mddev->curr_resync > 2 && - mddev->curr_resync > mddev->recovery_cp) { + mddev->curr_resync >= mddev->recovery_cp) { if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { printk(KERN_INFO "md: checkpointing recovery of %s.\n", @@ -3655,7 +3664,7 @@ int __init md_init(void) for (minor=0; minor < MAX_MD_DEVS; ++minor) devfs_mk_bdev(MKDEV(mdp_major, minor<<MdpMinorShift), S_IFBLK|S_IRUSR|S_IWUSR, - "md/d%d", minor); + "md/mdp%d", minor); register_reboot_notifier(&md_notifier); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 783ae7a5b218..5ee4c2b553e9 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -49,7 +49,7 @@ * This macro is used to determine the 'next' bio in the list, given the sector * of the current stripe+device */ -#define r5_next_bio(bio, sect) ( ( bio->bi_sector + (bio->bi_size>>9) < sect + STRIPE_SECTORS) ? bio->bi_next : NULL) +#define r5_next_bio(bio, sect) ( ( (bio)->bi_sector + ((bio)->bi_size>>9) < sect + STRIPE_SECTORS) ? (bio)->bi_next : NULL) /* * The following can be used to debug the driver */ @@ -232,6 +232,7 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector) } static void unplug_slaves(mddev_t *mddev); +static void raid5_unplug_device(request_queue_t *q); static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int pd_idx, int noblock) @@ -612,11 +613,10 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) /* - * Copy data between a page in the stripe cache, and one or more bion - * The page could align with the middle of the bio, or there could be - * several bion, each with several bio_vecs, which cover part of the page - * Multiple bion are linked together on bi_next. There may be extras - * at the end of this list. We ignore them. + * Copy data between a page in the stripe cache, and a bio. + * There are no alignment or size guarantees between the page or the + * bio except that there is some overlap. + * All iovecs in the bio must be considered. */ static void copy_data(int frombio, struct bio *bio, struct page *page, @@ -625,41 +625,38 @@ static void copy_data(int frombio, struct bio *bio, char *pa = page_address(page); struct bio_vec *bvl; int i; + int page_offset; - for (;bio && bio->bi_sector < sector+STRIPE_SECTORS; - bio = r5_next_bio(bio, sector) ) { - int page_offset; - if (bio->bi_sector >= sector) - page_offset = (signed)(bio->bi_sector - sector) * 512; - else - page_offset = (signed)(sector - bio->bi_sector) * -512; - bio_for_each_segment(bvl, bio, i) { - int len = bio_iovec_idx(bio,i)->bv_len; - int clen; - int b_offset = 0; - - if (page_offset < 0) { - b_offset = -page_offset; - page_offset += b_offset; - len -= b_offset; - } + if (bio->bi_sector >= sector) + page_offset = (signed)(bio->bi_sector - sector) * 512; + else + page_offset = (signed)(sector - bio->bi_sector) * -512; + bio_for_each_segment(bvl, bio, i) { + int len = bio_iovec_idx(bio,i)->bv_len; + int clen; + int b_offset = 0; + + if (page_offset < 0) { + b_offset = -page_offset; + page_offset += b_offset; + len -= b_offset; + } - if (len > 0 && page_offset + len > STRIPE_SIZE) - clen = STRIPE_SIZE - page_offset; - else clen = len; + if (len > 0 && page_offset + len > STRIPE_SIZE) + clen = STRIPE_SIZE - page_offset; + else clen = len; - if (clen > 0) { - char *ba = __bio_kmap_atomic(bio, i, KM_USER0); - if (frombio) - memcpy(pa+page_offset, ba+b_offset, clen); - else - memcpy(ba+b_offset, pa+page_offset, clen); - __bio_kunmap_atomic(ba, KM_USER0); - } - if (clen < len) /* hit end of page */ - break; - page_offset += len; + if (clen > 0) { + char *ba = __bio_kmap_atomic(bio, i, KM_USER0); + if (frombio) + memcpy(pa+page_offset, ba+b_offset, clen); + else + memcpy(ba+b_offset, pa+page_offset, clen); + __bio_kunmap_atomic(ba, KM_USER0); } + if (clen < len) /* hit end of page */ + break; + page_offset += len; } } @@ -725,6 +722,10 @@ static void compute_parity(struct stripe_head *sh, int method) ptr[count++] = page_address(sh->dev[i].page); chosen = sh->dev[i].towrite; sh->dev[i].towrite = NULL; + + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); + if (sh->dev[i].written) BUG(); sh->dev[i].written = chosen; check_xor(); @@ -737,6 +738,10 @@ static void compute_parity(struct stripe_head *sh, int method) if (i!=pd_idx && sh->dev[i].towrite) { chosen = sh->dev[i].towrite; sh->dev[i].towrite = NULL; + + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); + if (sh->dev[i].written) BUG(); sh->dev[i].written = chosen; } @@ -793,7 +798,7 @@ static void compute_parity(struct stripe_head *sh, int method) * toread/towrite point to the first in a chain. * The bi_next chain must be in order. */ -static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) +static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) { struct bio **bip; raid5_conf_t *conf = sh->raid_conf; @@ -810,10 +815,13 @@ static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, else bip = &sh->dev[dd_idx].toread; while (*bip && (*bip)->bi_sector < bi->bi_sector) { - BUG_ON((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector); + if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector) + goto overlap; bip = & (*bip)->bi_next; } -/* FIXME do I need to worry about overlapping bion */ + if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9)) + goto overlap; + if (*bip && bi->bi_next && (*bip) != bi->bi_next) BUG(); if (*bip) @@ -828,7 +836,7 @@ static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, (unsigned long long)sh->sector, dd_idx); if (forwrite) { - /* check if page is coverred */ + /* check if page is covered */ sector_t sector = sh->dev[dd_idx].sector; for (bi=sh->dev[dd_idx].towrite; sector < sh->dev[dd_idx].sector + STRIPE_SECTORS && @@ -840,6 +848,13 @@ static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS) set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags); } + return 1; + + overlap: + set_bit(R5_Overlap, &sh->dev[dd_idx].flags); + spin_unlock_irq(&conf->device_lock); + spin_unlock(&sh->lock); + return 0; } @@ -900,6 +915,8 @@ static void handle_stripe(struct stripe_head *sh) spin_lock_irq(&conf->device_lock); rbi = dev->toread; dev->toread = NULL; + if (test_and_clear_bit(R5_Overlap, &dev->flags)) + wake_up(&conf->wait_for_overlap); spin_unlock_irq(&conf->device_lock); while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) { copy_data(0, rbi, dev->page, dev->sector); @@ -947,6 +964,9 @@ static void handle_stripe(struct stripe_head *sh) sh->dev[i].towrite = NULL; if (bi) to_write--; + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); + while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -975,6 +995,8 @@ static void handle_stripe(struct stripe_head *sh) if (!test_bit(R5_Insync, &sh->dev[i].flags)) { bi = sh->dev[i].toread; sh->dev[i].toread = NULL; + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); if (bi) to_read--; while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); @@ -1402,6 +1424,7 @@ static int make_request (request_queue_t *q, struct bio * bi) if ( bio_data_dir(bi) == WRITE ) md_write_start(mddev); for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { + DEFINE_WAIT(w); new_sector = raid5_compute_sector(logical_sector, raid_disks, data_disks, &dd_idx, &pd_idx, conf); @@ -1410,17 +1433,28 @@ static int make_request (request_queue_t *q, struct bio * bi) (unsigned long long)new_sector, (unsigned long long)logical_sector); + retry: + prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); if (sh) { - - add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK)); - + if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) { + /* Add failed due to overlap. Flush everything + * and wait a while + */ + raid5_unplug_device(mddev->queue); + release_stripe(sh); + schedule(); + goto retry; + } + finish_wait(&conf->wait_for_overlap, &w); raid5_plug_device(conf); handle_stripe(sh); release_stripe(sh); + } else { /* cannot get stripe for read-ahead, just give-up */ clear_bit(BIO_UPTODATE, &bi->bi_flags); + finish_wait(&conf->wait_for_overlap, &w); break; } @@ -1568,6 +1602,7 @@ static int run (mddev_t *mddev) spin_lock_init(&conf->device_lock); init_waitqueue_head(&conf->wait_for_stripe); + init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); INIT_LIST_HEAD(&conf->delayed_list); INIT_LIST_HEAD(&conf->inactive_list); diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 8c52254c262f..0f82d85939e7 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -54,7 +54,7 @@ * This macro is used to determine the 'next' bio in the list, given the sector * of the current stripe+device */ -#define r5_next_bio(bio, sect) ( ( bio->bi_sector + (bio->bi_size>>9) < sect + STRIPE_SECTORS) ? bio->bi_next : NULL) +#define r5_next_bio(bio, sect) ( ( (bio)->bi_sector + ((bio)->bi_size>>9) < sect + STRIPE_SECTORS) ? (bio)->bi_next : NULL) /* * The following can be used to debug the driver */ @@ -670,41 +670,38 @@ static void copy_data(int frombio, struct bio *bio, char *pa = page_address(page); struct bio_vec *bvl; int i; + int page_offset; - for (;bio && bio->bi_sector < sector+STRIPE_SECTORS; - bio = r5_next_bio(bio, sector) ) { - int page_offset; - if (bio->bi_sector >= sector) - page_offset = (signed)(bio->bi_sector - sector) * 512; - else - page_offset = (signed)(sector - bio->bi_sector) * -512; - bio_for_each_segment(bvl, bio, i) { - int len = bio_iovec_idx(bio,i)->bv_len; - int clen; - int b_offset = 0; - - if (page_offset < 0) { - b_offset = -page_offset; - page_offset += b_offset; - len -= b_offset; - } + if (bio->bi_sector >= sector) + page_offset = (signed)(bio->bi_sector - sector) * 512; + else + page_offset = (signed)(sector - bio->bi_sector) * -512; + bio_for_each_segment(bvl, bio, i) { + int len = bio_iovec_idx(bio,i)->bv_len; + int clen; + int b_offset = 0; + + if (page_offset < 0) { + b_offset = -page_offset; + page_offset += b_offset; + len -= b_offset; + } - if (len > 0 && page_offset + len > STRIPE_SIZE) - clen = STRIPE_SIZE - page_offset; - else clen = len; - - if (clen > 0) { - char *ba = __bio_kmap_atomic(bio, i, KM_USER0); - if (frombio) - memcpy(pa+page_offset, ba+b_offset, clen); - else - memcpy(ba+b_offset, pa+page_offset, clen); - __bio_kunmap_atomic(ba, KM_USER0); - } - if (clen < len) /* hit end of page */ - break; - page_offset += len; + if (len > 0 && page_offset + len > STRIPE_SIZE) + clen = STRIPE_SIZE - page_offset; + else clen = len; + + if (clen > 0) { + char *ba = __bio_kmap_atomic(bio, i, KM_USER0); + if (frombio) + memcpy(pa+page_offset, ba+b_offset, clen); + else + memcpy(ba+b_offset, pa+page_offset, clen); + __bio_kunmap_atomic(ba, KM_USER0); } + if (clen < len) /* hit end of page */ + break; + page_offset += len; } } @@ -738,6 +735,10 @@ static void compute_parity(struct stripe_head *sh, int method) if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) { chosen = sh->dev[i].towrite; sh->dev[i].towrite = NULL; + + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); + if (sh->dev[i].written) BUG(); sh->dev[i].written = chosen; } @@ -900,7 +901,7 @@ static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) * toread/towrite point to the first in a chain. * The bi_next chain must be in order. */ -static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) +static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) { struct bio **bip; raid6_conf_t *conf = sh->raid_conf; @@ -917,10 +918,13 @@ static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, else bip = &sh->dev[dd_idx].toread; while (*bip && (*bip)->bi_sector < bi->bi_sector) { - BUG_ON((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector); - bip = & (*bip)->bi_next; + if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector) + goto overlap; + bip = &(*bip)->bi_next; } -/* FIXME do I need to worry about overlapping bion */ + if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9)) + goto overlap; + if (*bip && bi->bi_next && (*bip) != bi->bi_next) BUG(); if (*bip) @@ -935,7 +939,7 @@ static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, (unsigned long long)sh->sector, dd_idx); if (forwrite) { - /* check if page is coverred */ + /* check if page is covered */ sector_t sector = sh->dev[dd_idx].sector; for (bi=sh->dev[dd_idx].towrite; sector < sh->dev[dd_idx].sector + STRIPE_SECTORS && @@ -947,6 +951,13 @@ static void add_stripe_bio (struct stripe_head *sh, struct bio *bi, int dd_idx, if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS) set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags); } + return 1; + + overlap: + set_bit(R5_Overlap, &sh->dev[dd_idx].flags); + spin_unlock_irq(&conf->device_lock); + spin_unlock(&sh->lock); + return 0; } @@ -1010,6 +1021,8 @@ static void handle_stripe(struct stripe_head *sh) spin_lock_irq(&conf->device_lock); rbi = dev->toread; dev->toread = NULL; + if (test_and_clear_bit(R5_Overlap, &dev->flags)) + wake_up(&conf->wait_for_overlap); spin_unlock_irq(&conf->device_lock); while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) { copy_data(0, rbi, dev->page, dev->sector); @@ -1059,6 +1072,9 @@ static void handle_stripe(struct stripe_head *sh) sh->dev[i].towrite = NULL; if (bi) to_write--; + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); + while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -1087,6 +1103,8 @@ static void handle_stripe(struct stripe_head *sh) if (!test_bit(R5_Insync, &sh->dev[i].flags)) { bi = sh->dev[i].toread; sh->dev[i].toread = NULL; + if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) + wake_up(&conf->wait_for_overlap); if (bi) to_read--; while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); @@ -1566,6 +1584,7 @@ static int make_request (request_queue_t *q, struct bio * bi) if ( bio_data_dir(bi) == WRITE ) md_write_start(mddev); for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { + DEFINE_WAIT(w); new_sector = raid6_compute_sector(logical_sector, raid_disks, data_disks, &dd_idx, &pd_idx, conf); @@ -1574,17 +1593,27 @@ static int make_request (request_queue_t *q, struct bio * bi) (unsigned long long)new_sector, (unsigned long long)logical_sector); + retry: + prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); if (sh) { - - add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK)); - + if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) { + /* Add failed due to overlap. Flush everything + * and wait a while + */ + raid6_unplug_device(mddev->queue); + release_stripe(sh); + schedule(); + goto retry; + } + finish_wait(&conf->wait_for_overlap, &w); raid6_plug_device(conf); handle_stripe(sh); release_stripe(sh); } else { /* cannot get stripe for read-ahead, just give-up */ clear_bit(BIO_UPTODATE, &bi->bi_flags); + finish_wait(&conf->wait_for_overlap, &w); break; } @@ -1732,6 +1761,7 @@ static int run (mddev_t *mddev) spin_lock_init(&conf->device_lock); init_waitqueue_head(&conf->wait_for_stripe); + init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); INIT_LIST_HEAD(&conf->delayed_list); INIT_LIST_HEAD(&conf->inactive_list); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0a09d933a770..789b9086b717 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -60,8 +60,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.20" -#define DRV_MODULE_RELDATE "February 2, 2005" +#define DRV_MODULE_VERSION "3.21" +#define DRV_MODULE_RELDATE "February 8, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -893,7 +893,7 @@ static void tg3_frob_aux_power(struct tg3 *tp) GRC_LCLCTRL_GPIO_OUTPUT1)); udelay(100); } else { - int no_gpio2; + u32 no_gpio2; u32 grc_local_ctrl; if (tp_peer != tp && @@ -901,8 +901,8 @@ static void tg3_frob_aux_power(struct tg3 *tp) return; /* On 5753 and variants, GPIO2 cannot be used. */ - no_gpio2 = (tp->nic_sram_data_cfg & - NIC_SRAM_DATA_CFG_NO_GPIO2) != 0; + no_gpio2 = tp->nic_sram_data_cfg & + NIC_SRAM_DATA_CFG_NO_GPIO2; grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | @@ -914,29 +914,17 @@ static void tg3_frob_aux_power(struct tg3 *tp) GRC_LCLCTRL_GPIO_OUTPUT2); } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - grc_local_ctrl); + grc_local_ctrl); udelay(100); - grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | - GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT0 | - GRC_LCLCTRL_GPIO_OUTPUT1 | - GRC_LCLCTRL_GPIO_OUTPUT2; - if (no_gpio2) { - grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT2); - } + grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0; + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - grc_local_ctrl); + grc_local_ctrl); udelay(100); - grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | - GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT0 | - GRC_LCLCTRL_GPIO_OUTPUT1; if (!no_gpio2) { + grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2; tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | grc_local_ctrl); udelay(100); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 3b20d4be6835..e709bad434f4 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -224,7 +224,7 @@ static int get_children_props(struct device_node *dn, int **drc_indexes, if (!indexes || !names || !types || !domains) { /* Slot does not have dynamically-removable children */ - return 1; + return -EINVAL; } if (drc_indexes) *drc_indexes = indexes; @@ -260,7 +260,7 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, } rc = get_children_props(dn->parent, &indexes, &names, &types, &domains); - if (rc) { + if (rc < 0) { return 1; } @@ -307,7 +307,7 @@ static int is_php_dn(struct device_node *dn, int **indexes, int **names, int rc; rc = get_children_props(dn, indexes, names, &drc_types, power_domains); - if (rc) { + if (rc >= 0) { if (is_php_type((char *) &drc_types[1])) { *types = drc_types; return 1; @@ -331,7 +331,7 @@ static int is_dr_dn(struct device_node *dn, int **indexes, int **names, rc = get_children_props(dn->parent, indexes, names, types, power_domains); - return (rc == 0); + return (rc >= 0); } static inline int is_vdevice_root(struct device_node *dn) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 540879308d32..22bdb841c8e4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -859,7 +859,7 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) * In all other cases we'll let an irq pick up our IO and submit it * to the controller to improve affinity. */ - if (smp_processor_id() == ha->last_irq_cpu || was_empty) + if (_smp_processor_id() == ha->last_irq_cpu || was_empty) qla2x00_next(ha); spin_lock_irq(ha->host->host_lock); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index d4e7733dbeb8..ec620e33fcf6 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -987,8 +987,11 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) /* The following is not allowed by the tty layer and unsafe. It should be fixed ASAP */ if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { - if(tty->low_latency) + if (tty->low_latency) { + spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); + } /* If this failed then we will throw away the bytes but must do so to clear interrupts */ } @@ -1059,7 +1062,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) ignore_char: lsr = serial_inp(up, UART_LSR); } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); + spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); *status = lsr; } diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index 416761fce324..c1516d013bf6 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h @@ -16,9 +16,30 @@ #define HOSTFS_ATTR_CTIME 64 #define HOSTFS_ATTR_ATIME_SET 128 #define HOSTFS_ATTR_MTIME_SET 256 + +/* These two are unused by hostfs. */ #define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ #define HOSTFS_ATTR_ATTR_FLAG 1024 +/* If you are very careful, you'll notice that these two are missing: + * + * #define ATTR_KILL_SUID 2048 + * #define ATTR_KILL_SGID 4096 + * + * and this is because they were added in 2.5 development in this patch: + * + * http://linux.bkbits.net:8080/linux-2.5/ + * cset@3caf4a12k4XgDzK7wyK-TGpSZ9u2Ww?nav=index.html + * |src/.|src/include|src/include/linux|related/include/linux/fs.h + * + * Actually, they are not needed by most ->setattr() methods - they are set by + * callers of notify_change() to notify that the setuid/setgid bits must be + * dropped. + * notify_change() will delete those flags, make sure attr->ia_valid & ATTR_MODE + * is on, and remove the appropriate bits from attr->ia_mode (attr is a + * "struct iattr *"). -BlaisorBlade + */ + struct hostfs_iattr { unsigned int ia_valid; mode_t ia_mode; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index f9759e012416..144ff70fbd55 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -823,6 +823,10 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr) char *name; int err; + err = inode_change_ok(dentry->d_inode, attr); + if (err) + return err; + if(append) attr->ia_valid &= ~ATTR_SIZE; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 70b32eac873c..f3bf5368551c 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -540,7 +540,7 @@ static struct svc_procedure nfsd_procedures2[18] = { PROC(symlink, symlinkargs, void, none, RC_REPLSTAT, ST), PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), PROC(rmdir, diropargs, void, none, RC_REPLSTAT, ST), - PROC(readdir, readdirargs, readdirres, none, RC_REPLBUFF, 0), + PROC(readdir, readdirargs, readdirres, none, RC_NOCACHE, 0), PROC(statfs, fhandle, statfsres, none, RC_NOCACHE, ST+5), }; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index f7ad9f759f83..a5a58a1dba0a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -656,12 +656,15 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, dentry = fhp->fh_dentry; inode = dentry->d_inode; - /* Disallow access to files with the append-only bit set or - * with mandatory locking enabled + /* Disallow write access to files with the append-only bit set + * or any access when mandatory locking enabled */ err = nfserr_perm; - if (IS_APPEND(inode) || IS_ISMNDLK(inode)) + if (IS_APPEND(inode) && (access & MAY_WRITE)) goto out; + if (IS_ISMNDLK(inode)) + goto out; + if (!inode->i_fop) goto out; diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 0e930601a821..7321db1c2fb4 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -531,6 +531,7 @@ struct file_operations linvfs_dir_operations = { static struct vm_operations_struct linvfs_file_vm_ops = { .nopage = filemap_nopage, + .populate = filemap_populate, #ifdef HAVE_VMOP_MPROTECT .mprotect = linvfs_mprotect, #endif diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index 1991944ddfd9..24770c011fd8 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -79,7 +79,8 @@ do { \ #define alloc_zeroed_user_highpage(vma, vaddr) \ ({ \ struct page *page = alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr); \ - flush_dcache_page(page); \ + if (page) \ + flush_dcache_page(page); \ page; \ }) diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h index e26d7d85c55a..da9c81a6af5a 100644 --- a/include/asm-sparc64/compat.h +++ b/include/asm-sparc64/compat.h @@ -133,6 +133,8 @@ static __inline__ void __user *compat_alloc_user_space(long len) if (!(test_thread_flag(TIF_32BIT))) usp += STACK_BIAS; + else + usp &= 0xffffffffUL; return (void __user *) (usp - len); } diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index 05acc62c2b61..c1710933828f 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -35,7 +35,7 @@ "thread_return:\n\t" \ "movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \ "movq %P[thread_info](%%rsi),%%r8\n\t" \ - "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ + LOCK "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ "movq %%rax,%%rdi\n\t" \ "jc ret_from_fork\n\t" \ RESTORE_CONTEXT \ diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 11d84c93af71..2a7e6c65c882 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -48,7 +48,9 @@ alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr) { struct page *page = alloc_page_vma(GFP_HIGHUSER, vma, vaddr); - clear_user_highpage(page, vaddr); + if (page) + clear_user_highpage(page, vaddr); + return page; } #endif diff --git a/include/linux/mm.h b/include/linux/mm.h index 10d011f464d6..3a8c47c5dc9c 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -756,7 +756,9 @@ extern unsigned long page_unuse(struct page *); extern void truncate_inode_pages(struct address_space *, loff_t); /* generic vm_area_ops exported for stackable file systems */ -struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int *); +extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int *); +extern int filemap_populate(struct vm_area_struct *, unsigned long, + unsigned long, pgprot_t, unsigned long, int); /* mm/page-writeback.c */ int write_one_page(struct page *page, int wait); diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index baf88d2ad986..d63ddcb4afad 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -152,6 +152,7 @@ struct stripe_head { #define R5_Wantread 4 /* want to schedule a read */ #define R5_Wantwrite 5 #define R5_Syncio 6 /* this io need to be accounted as resync io */ +#define R5_Overlap 7 /* There is a pending overlapping request on this block */ /* * Write method @@ -219,6 +220,7 @@ struct raid5_private_data { atomic_t active_stripes; struct list_head inactive_list; wait_queue_head_t wait_for_stripe; + wait_queue_head_t wait_for_overlap; int inactive_blocked; /* release of inactive stripes blocked, * waiting for 25% to be free */ diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c index 1b960c88cb58..3fbc3555ce96 100644 --- a/init/do_mounts_md.c +++ b/init/do_mounts_md.c @@ -232,6 +232,16 @@ static void __init md_setup_drive(void) err = sys_ioctl(fd, RUN_ARRAY, 0); if (err) printk(KERN_WARNING "md: starting md%d failed\n", minor); + else { + /* reread the partition table. + * I (neilb) and not sure why this is needed, but I cannot + * boot a kernel with devfs compiled in from partitioned md + * array without it + */ + sys_close(fd); + fd = sys_open(name, 0, 0); + sys_ioctl(fd, BLKRRPART, 0); + } sys_close(fd); } } diff --git a/kernel/sched.c b/kernel/sched.c index f708d10e7750..95042b27d30c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -867,7 +867,7 @@ void wait_task_inactive(task_t * p) repeat: rq = task_rq_lock(p, &flags); /* Must be off runqueue entirely, not preempted. */ - if (unlikely(p->array)) { + if (unlikely(p->array || task_running(rq, p))) { /* If it's preempted, we yield. It could be a while. */ preempted = !task_running(rq, p); task_rq_unlock(rq, &flags); @@ -885,6 +885,12 @@ repeat: * * Cause a process which is running on another CPU to enter * kernel-mode, without any delay. (to get signals handled.) + * + * NOTE: this function doesnt have to take the runqueue lock, + * because all it wants to ensure is that the remote task enters + * the kernel. If the IPI races and the task has been migrated + * to another CPU then no harm is done and the purpose has been + * achieved as well. */ void kick_process(task_t *p) { diff --git a/mm/filemap.c b/mm/filemap.c index e82fc19ee094..6d04b97fea14 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1458,12 +1458,9 @@ err: return NULL; } -static int filemap_populate(struct vm_area_struct *vma, - unsigned long addr, - unsigned long len, - pgprot_t prot, - unsigned long pgoff, - int nonblock) +int filemap_populate(struct vm_area_struct *vma, unsigned long addr, + unsigned long len, pgprot_t prot, unsigned long pgoff, + int nonblock) { struct file *file = vma->vm_file; struct address_space *mapping = file->f_mapping; @@ -1523,6 +1520,7 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma) vma->vm_ops = &generic_file_vm_ops; return 0; } +EXPORT_SYMBOL(filemap_populate); /* * This is for filesystems which do not implement ->writepage. diff --git a/mm/nommu.c b/mm/nommu.c index fcca232e4b9e..8e70b95a8d9f 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -4,7 +4,9 @@ * Replacement code for mm functions to support CPU's that don't * have any form of memory management unit (thus no virtual memory). * - * Copyright (c) 2004 David Howells <dhowells@redhat.com> + * See Documentation/nommu-mmap.txt + * + * Copyright (c) 2004-2005 David Howells <dhowells@redhat.com> * Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com> * Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org> * Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com> @@ -567,12 +569,14 @@ unsigned long do_mmap_pgoff(struct file *file, * that it represents a valid section of the address space * - this is the hook for quasi-memory character devices */ - if (file && file->f_op->get_unmapped_area) + if (file && file->f_op->get_unmapped_area) { addr = file->f_op->get_unmapped_area(file, addr, len, pgoff, flags); - - if (IS_ERR((void *) addr)) { - ret = addr; - goto error; + if (IS_ERR((void *) addr)) { + ret = addr; + if (ret == (unsigned long) -ENOSYS) + ret = (unsigned long) -ENODEV; + goto error; + } } /* we're going to need a VMA struct as well */ diff --git a/net/atm/addr.c b/net/atm/addr.c index 225f6843c32f..1c8867f7f54a 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -108,7 +108,7 @@ int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) } int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, - int size) + size_t size) { unsigned long flags; struct atm_dev_addr *this; diff --git a/net/atm/addr.h b/net/atm/addr.h index 2affa3a128ca..3099d21feeaa 100644 --- a/net/atm/addr.h +++ b/net/atm/addr.h @@ -13,6 +13,6 @@ void atm_reset_addr(struct atm_dev *dev); int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,int size); +int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,size_t size); #endif diff --git a/net/core/dev.c b/net/core/dev.c index 4dc01e26f158..5d4abaa85351 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -108,6 +108,7 @@ #include <linux/kallsyms.h> #include <linux/netpoll.h> #include <linux/rcupdate.h> +#include <linux/delay.h> #ifdef CONFIG_NET_RADIO #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ #include <net/iw_handler.h> @@ -2899,8 +2900,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rebroadcast_time = jiffies; } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 4); + msleep(250); if (time_after(jiffies, warning_time + 10 * HZ)) { printk(KERN_EMERG "unregister_netdevice: " diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index c542f2dab253..f2509034ce72 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -53,6 +53,7 @@ #include <linux/seq_file.h> #include <linux/major.h> #include <linux/root_dev.h> +#include <linux/delay.h> #include <net/arp.h> #include <net/ip.h> #include <net/ipconfig.h> @@ -84,8 +85,8 @@ #endif /* Define the friendly delay before and after opening net devices */ -#define CONF_PRE_OPEN (HZ/2) /* Before opening: 1/2 second */ -#define CONF_POST_OPEN (1*HZ) /* After opening: 1 second */ +#define CONF_PRE_OPEN 500 /* Before opening: 1/2 second */ +#define CONF_POST_OPEN 1 /* After opening: 1 second */ /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */ #define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */ @@ -1259,16 +1260,14 @@ static int __init ip_auto_config(void) try_try_again: #endif /* Give hardware a chance to settle */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(CONF_PRE_OPEN); + msleep(CONF_PRE_OPEN); /* Setup all network devices */ if (ic_open_devs() < 0) return -1; /* Give drivers a chance to settle */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(CONF_POST_OPEN); + ssleep(CONF_POST_OPEN); /* * If the config information is insufficient (e.g., our IP address or diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index da30bebbddc8..25c479550a32 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -23,7 +23,7 @@ #include <linux/slab.h> #include <linux/net.h> #include <linux/completion.h> - +#include <linux/delay.h> #include <linux/skbuff.h> #include <linux/in.h> #include <linux/igmp.h> /* for ip_mc_join_group */ @@ -647,8 +647,7 @@ static void sync_master_loop(void) if (stop_master_sync) break; - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); } /* clean up the sync_buff queue */ @@ -705,8 +704,7 @@ static void sync_backup_loop(void) if (stop_backup_sync) break; - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + ssleep(1); } /* release the sending multicast socket */ @@ -818,8 +816,7 @@ static int fork_sync_thread(void *startup) if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) { IP_VS_ERR("could not create sync_thread due to %d... " "retrying.\n", pid); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); + ssleep(1); goto repeat; } @@ -853,8 +850,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid) if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) { IP_VS_ERR("could not create fork_sync_thread due to %d... " "retrying.\n", pid); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); + ssleep(1); goto repeat; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bfcd43832cb0..9865091954f3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3760,8 +3760,7 @@ tcp_collapse(struct sock *sk, struct sk_buff *head, while (before(start, end)) { struct sk_buff *nskb; int header = skb_headroom(skb); - int copy = (PAGE_SIZE - sizeof(struct sk_buff) - - sizeof(struct skb_shared_info) - header - 31)&~15; + int copy = SKB_MAX_ORDER(header, 0); /* Too big header? This can happen with IPv6. */ if (copy < 0) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 8b870402bc96..821d3b9c5c55 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -91,6 +91,7 @@ struct tc_u_hnode { struct tc_u_hnode *next; u32 handle; + u32 prio; struct tc_u_common *tp_c; int refcnt; unsigned divisor; @@ -323,6 +324,7 @@ static int u32_init(struct tcf_proto *tp) root_ht->divisor = 0; root_ht->refcnt++; root_ht->handle = tp_c ? gen_new_htid(tp_c) : 0x80000000; + root_ht->prio = tp->prio; if (tp_c == NULL) { tp_c = kmalloc(sizeof(*tp_c), GFP_KERNEL); @@ -587,6 +589,7 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, ht->refcnt = 0; ht->divisor = divisor; ht->handle = handle; + ht->prio = tp->prio; ht->next = tp_c->hlist; tp_c->hlist = ht; *arg = (unsigned long)ht; @@ -703,6 +706,8 @@ static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg) return; for (ht = tp_c->hlist; ht; ht = ht->next) { + if (ht->prio != tp->prio) + continue; if (arg->count >= arg->skip) { if (arg->fn(tp, (unsigned long)ht, arg) < 0) { arg->stop = 1; diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index 12bf0f88616c..693aac1aa833 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile @@ -2,7 +2,6 @@ # Makefile for the XFRM subsystem. # -obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o \ - xfrm_export.o +obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o obj-$(CONFIG_XFRM_USER) += xfrm_user.o diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 74e995aed022..080aae243ce0 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -316,6 +316,7 @@ struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id) } return NULL; } +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid); struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id) { @@ -331,6 +332,7 @@ struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id) } return NULL; } +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid); struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id) { @@ -346,6 +348,7 @@ struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id) } return NULL; } +EXPORT_SYMBOL_GPL(xfrm_calg_get_byid); static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list, int entries, char *name, @@ -380,16 +383,19 @@ struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe) { return xfrm_get_byname(aalg_list, aalg_entries(), name, probe); } +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname); struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe) { return xfrm_get_byname(ealg_list, ealg_entries(), name, probe); } +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname); struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe) { return xfrm_get_byname(calg_list, calg_entries(), name, probe); } +EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx) { @@ -398,6 +404,7 @@ struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx) return &aalg_list[idx]; } +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byidx); struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx) { @@ -406,6 +413,7 @@ struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx) return &ealg_list[idx]; } +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx); /* * Probe for the availability of crypto algorithms, and set the available @@ -438,6 +446,7 @@ void xfrm_probe_algs(void) } #endif } +EXPORT_SYMBOL_GPL(xfrm_probe_algs); int xfrm_count_auth_supported(void) { @@ -448,6 +457,7 @@ int xfrm_count_auth_supported(void) n++; return n; } +EXPORT_SYMBOL_GPL(xfrm_count_auth_supported); int xfrm_count_enc_supported(void) { @@ -458,6 +468,7 @@ int xfrm_count_enc_supported(void) n++; return n; } +EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); /* Move to common area: it is shared with AH. */ @@ -532,6 +543,7 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, if (len) BUG(); } +EXPORT_SYMBOL_GPL(skb_icv_walk); #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) diff --git a/net/xfrm/xfrm_export.c b/net/xfrm/xfrm_export.c deleted file mode 100644 index 7ca0e889e54a..000000000000 --- a/net/xfrm/xfrm_export.c +++ /dev/null @@ -1,62 +0,0 @@ -#include <linux/module.h> -#include <net/xfrm.h> - -EXPORT_SYMBOL(xfrm_user_policy); -EXPORT_SYMBOL(km_waitq); -EXPORT_SYMBOL(km_new_mapping); -EXPORT_SYMBOL(xfrm_cfg_sem); -EXPORT_SYMBOL(xfrm_policy_alloc); -EXPORT_SYMBOL(__xfrm_policy_destroy); -EXPORT_SYMBOL(xfrm_lookup); -EXPORT_SYMBOL(__xfrm_policy_check); -EXPORT_SYMBOL(__xfrm_route_forward); -EXPORT_SYMBOL(xfrm_state_alloc); -EXPORT_SYMBOL(__xfrm_state_destroy); -EXPORT_SYMBOL(xfrm_state_insert); -EXPORT_SYMBOL(xfrm_state_add); -EXPORT_SYMBOL(xfrm_state_update); -EXPORT_SYMBOL(xfrm_state_check_expire); -EXPORT_SYMBOL(xfrm_state_check); -EXPORT_SYMBOL(xfrm_state_lookup); -EXPORT_SYMBOL(xfrm_state_register_afinfo); -EXPORT_SYMBOL(xfrm_state_unregister_afinfo); -EXPORT_SYMBOL(xfrm_state_delete_tunnel); -EXPORT_SYMBOL(xfrm_replay_check); -EXPORT_SYMBOL(xfrm_replay_advance); -EXPORT_SYMBOL(__secpath_destroy); -EXPORT_SYMBOL(secpath_dup); -EXPORT_SYMBOL(xfrm_get_acqseq); -EXPORT_SYMBOL(xfrm_parse_spi); -EXPORT_SYMBOL(xfrm_register_type); -EXPORT_SYMBOL(xfrm_unregister_type); -EXPORT_SYMBOL(xfrm_get_type); -EXPORT_SYMBOL(xfrm_register_km); -EXPORT_SYMBOL(xfrm_unregister_km); -EXPORT_SYMBOL(xfrm_state_delete); -EXPORT_SYMBOL(xfrm_state_walk); -EXPORT_SYMBOL(xfrm_find_acq_byseq); -EXPORT_SYMBOL(xfrm_find_acq); -EXPORT_SYMBOL(xfrm_alloc_spi); -EXPORT_SYMBOL(xfrm_state_flush); -EXPORT_SYMBOL(xfrm_policy_bysel); -EXPORT_SYMBOL(xfrm_policy_insert); -EXPORT_SYMBOL(xfrm_policy_walk); -EXPORT_SYMBOL(xfrm_policy_flush); -EXPORT_SYMBOL(xfrm_policy_byid); -EXPORT_SYMBOL(xfrm_policy_list); -EXPORT_SYMBOL(xfrm_dst_lookup); -EXPORT_SYMBOL(xfrm_policy_register_afinfo); -EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); - -EXPORT_SYMBOL_GPL(xfrm_probe_algs); -EXPORT_SYMBOL_GPL(xfrm_count_auth_supported); -EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); -EXPORT_SYMBOL_GPL(xfrm_aalg_get_byidx); -EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx); -EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid); -EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid); -EXPORT_SYMBOL_GPL(xfrm_calg_get_byid); -EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname); -EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname); -EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); -EXPORT_SYMBOL_GPL(skb_icv_walk); diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index abe2e674cabd..c58a6f05a0b6 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -8,6 +8,7 @@ */ #include <linux/slab.h> +#include <linux/module.h> #include <net/ip.h> #include <net/xfrm.h> @@ -20,6 +21,7 @@ void __secpath_destroy(struct sec_path *sp) xfrm_state_put(sp->x[i].xvec); kmem_cache_free(secpath_cachep, sp); } +EXPORT_SYMBOL(__secpath_destroy); struct sec_path *secpath_dup(struct sec_path *src) { @@ -40,6 +42,7 @@ struct sec_path *secpath_dup(struct sec_path *src) atomic_set(&sp->refcnt, 1); return sp; } +EXPORT_SYMBOL(secpath_dup); /* Fetch spi and seq from ipsec header */ @@ -73,6 +76,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) *seq = *(u32*)(skb->h.raw + offset_seq); return 0; } +EXPORT_SYMBOL(xfrm_parse_spi); void __init xfrm_input_init(void) { diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3ec936879f38..8d34ed106443 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -21,14 +21,17 @@ #include <linux/workqueue.h> #include <linux/notifier.h> #include <linux/netdevice.h> +#include <linux/module.h> #include <net/xfrm.h> #include <net/ip.h> DECLARE_MUTEX(xfrm_cfg_sem); +EXPORT_SYMBOL(xfrm_cfg_sem); static DEFINE_RWLOCK(xfrm_policy_lock); struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; +EXPORT_SYMBOL(xfrm_policy_list); static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; @@ -62,6 +65,7 @@ int xfrm_register_type(struct xfrm_type *type, unsigned short family) xfrm_policy_put_afinfo(afinfo); return err; } +EXPORT_SYMBOL(xfrm_register_type); int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) { @@ -82,6 +86,7 @@ int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) xfrm_policy_put_afinfo(afinfo); return err; } +EXPORT_SYMBOL(xfrm_unregister_type); struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) { @@ -112,6 +117,7 @@ retry: xfrm_policy_put_afinfo(afinfo); return type; } +EXPORT_SYMBOL(xfrm_get_type); int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family) @@ -129,6 +135,7 @@ int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, xfrm_policy_put_afinfo(afinfo); return err; } +EXPORT_SYMBOL(xfrm_dst_lookup); void xfrm_put_type(struct xfrm_type *type) { @@ -234,6 +241,7 @@ struct xfrm_policy *xfrm_policy_alloc(int gfp) } return policy; } +EXPORT_SYMBOL(xfrm_policy_alloc); /* Destroy xfrm_policy: descendant resources must be released to this moment. */ @@ -250,6 +258,7 @@ void __xfrm_policy_destroy(struct xfrm_policy *policy) kfree(policy); } +EXPORT_SYMBOL(__xfrm_policy_destroy); static void xfrm_policy_gc_kill(struct xfrm_policy *policy) { @@ -373,6 +382,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) } return 0; } +EXPORT_SYMBOL(xfrm_policy_insert); struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, int delete) @@ -396,6 +406,7 @@ struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, } return pol; } +EXPORT_SYMBOL(xfrm_policy_bysel); struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) { @@ -418,6 +429,7 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) } return pol; } +EXPORT_SYMBOL(xfrm_policy_byid); void xfrm_policy_flush(void) { @@ -438,6 +450,7 @@ void xfrm_policy_flush(void) atomic_inc(&flow_cache_genid); write_unlock_bh(&xfrm_policy_lock); } +EXPORT_SYMBOL(xfrm_policy_flush); int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *data) @@ -470,7 +483,7 @@ out: read_unlock_bh(&xfrm_policy_lock); return error; } - +EXPORT_SYMBOL(xfrm_policy_walk); /* Find policy to apply to this flow. */ @@ -845,6 +858,7 @@ error: *dst_p = NULL; return err; } +EXPORT_SYMBOL(xfrm_lookup); /* When skb is transformed back to its "native" form, we have to * check policy restrictions. At the moment we make this in maximally @@ -981,6 +995,7 @@ reject: xfrm_pol_put(pol); return 0; } +EXPORT_SYMBOL(__xfrm_policy_check); int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { @@ -991,6 +1006,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; } +EXPORT_SYMBOL(__xfrm_route_forward); /* Optimize later using cookies and generation ids. */ @@ -1163,6 +1179,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) write_unlock(&xfrm_policy_afinfo_lock); return err; } +EXPORT_SYMBOL(xfrm_policy_register_afinfo); int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) { @@ -1190,6 +1207,7 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) write_unlock(&xfrm_policy_afinfo_lock); return err; } +EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) { diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 5c9a57d6c09a..e43aa8c27483 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -17,6 +17,7 @@ #include <net/xfrm.h> #include <linux/pfkeyv2.h> #include <linux/ipsec.h> +#include <linux/module.h> #include <asm/uaccess.h> /* Each xfrm_state may be linked to two tables: @@ -38,6 +39,7 @@ static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE]; static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; DECLARE_WAIT_QUEUE_HEAD(km_waitq); +EXPORT_SYMBOL(km_waitq); static DEFINE_RWLOCK(xfrm_state_afinfo_lock); static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; @@ -193,6 +195,7 @@ struct xfrm_state *xfrm_state_alloc(void) } return x; } +EXPORT_SYMBOL(xfrm_state_alloc); void __xfrm_state_destroy(struct xfrm_state *x) { @@ -203,6 +206,7 @@ void __xfrm_state_destroy(struct xfrm_state *x) spin_unlock_bh(&xfrm_state_gc_lock); schedule_work(&xfrm_state_gc_work); } +EXPORT_SYMBOL(__xfrm_state_destroy); static void __xfrm_state_delete(struct xfrm_state *x) { @@ -241,6 +245,7 @@ void xfrm_state_delete(struct xfrm_state *x) __xfrm_state_delete(x); spin_unlock_bh(&x->lock); } +EXPORT_SYMBOL(xfrm_state_delete); void xfrm_state_flush(u8 proto) { @@ -267,6 +272,7 @@ restart: spin_unlock_bh(&xfrm_state_lock); wake_up(&km_waitq); } +EXPORT_SYMBOL(xfrm_state_flush); static int xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, @@ -392,6 +398,7 @@ void xfrm_state_insert(struct xfrm_state *x) __xfrm_state_insert(x); spin_unlock_bh(&xfrm_state_lock); } +EXPORT_SYMBOL(xfrm_state_insert); static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); @@ -444,6 +451,7 @@ out: return err; } +EXPORT_SYMBOL(xfrm_state_add); int xfrm_state_update(struct xfrm_state *x) { @@ -508,6 +516,7 @@ out: return err; } +EXPORT_SYMBOL(xfrm_state_update); int xfrm_state_check_expire(struct xfrm_state *x) { @@ -531,6 +540,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) km_state_expired(x, 0); return 0; } +EXPORT_SYMBOL(xfrm_state_check_expire); static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) { @@ -553,6 +563,7 @@ int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb) err: return err; } +EXPORT_SYMBOL(xfrm_state_check); struct xfrm_state * xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, @@ -569,6 +580,7 @@ xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, xfrm_state_put_afinfo(afinfo); return x; } +EXPORT_SYMBOL(xfrm_state_lookup); struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, @@ -586,6 +598,7 @@ xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_state_put_afinfo(afinfo); return x; } +EXPORT_SYMBOL(xfrm_find_acq); /* Silly enough, but I'm lazy to build resolution list */ @@ -614,7 +627,8 @@ struct xfrm_state *xfrm_find_acq_byseq(u32 seq) spin_unlock_bh(&xfrm_state_lock); return x; } - +EXPORT_SYMBOL(xfrm_find_acq_byseq); + u32 xfrm_get_acqseq(void) { u32 res; @@ -626,6 +640,7 @@ u32 xfrm_get_acqseq(void) spin_unlock_bh(&acqseq_lock); return res; } +EXPORT_SYMBOL(xfrm_get_acqseq); void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) @@ -666,6 +681,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) wake_up(&km_waitq); } } +EXPORT_SYMBOL(xfrm_alloc_spi); int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *data) @@ -700,7 +716,7 @@ out: spin_unlock_bh(&xfrm_state_lock); return err; } - +EXPORT_SYMBOL(xfrm_state_walk); int xfrm_replay_check(struct xfrm_state *x, u32 seq) { @@ -726,6 +742,7 @@ int xfrm_replay_check(struct xfrm_state *x, u32 seq) } return 0; } +EXPORT_SYMBOL(xfrm_replay_check); void xfrm_replay_advance(struct xfrm_state *x, u32 seq) { @@ -745,6 +762,7 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq) x->replay.bitmap |= (1U << diff); } } +EXPORT_SYMBOL(xfrm_replay_advance); static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); static DEFINE_RWLOCK(xfrm_km_lock); @@ -797,6 +815,7 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) read_unlock(&xfrm_km_lock); return err; } +EXPORT_SYMBOL(km_new_mapping); void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) { @@ -850,6 +869,7 @@ out: kfree(data); return err; } +EXPORT_SYMBOL(xfrm_user_policy); int xfrm_register_km(struct xfrm_mgr *km) { @@ -858,6 +878,7 @@ int xfrm_register_km(struct xfrm_mgr *km) write_unlock_bh(&xfrm_km_lock); return 0; } +EXPORT_SYMBOL(xfrm_register_km); int xfrm_unregister_km(struct xfrm_mgr *km) { @@ -866,6 +887,7 @@ int xfrm_unregister_km(struct xfrm_mgr *km) write_unlock_bh(&xfrm_km_lock); return 0; } +EXPORT_SYMBOL(xfrm_unregister_km); int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) { @@ -885,6 +907,7 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) write_unlock(&xfrm_state_afinfo_lock); return err; } +EXPORT_SYMBOL(xfrm_state_register_afinfo); int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) { @@ -906,6 +929,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) write_unlock(&xfrm_state_afinfo_lock); return err; } +EXPORT_SYMBOL(xfrm_state_unregister_afinfo); static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) { @@ -940,6 +964,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x) x->tunnel = NULL; } } +EXPORT_SYMBOL(xfrm_state_delete_tunnel); void __init xfrm_state_init(void) { |
