Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-04 22:45:44 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-04 22:45:44 -0700
commitee2b072ada7e2e8741609d962dc052ad2283fd90 (patch)
tree9fad4a9a3bcb0189ad7190f106301558eb581de4
parentea282989103079f2acf1aa11a3f2397154459add (diff)
parent619fdb17a600f3b49a9c467445c6549ad0caa9ba (diff)
Merge http://lia64.bkbits.net/to-linus-2.5
into ppc970.osdl.org:/home/torvalds/v2.6/linux
-rw-r--r--Documentation/filesystems/Exporting24
-rw-r--r--arch/arm/mm/fault.c2
-rw-r--r--arch/arm/mm/mmap.c2
-rw-r--r--arch/i386/kernel/traps.c4
-rw-r--r--arch/i386/mm/fault.c2
-rw-r--r--arch/x86_64/defconfig4
-rw-r--r--arch/x86_64/kernel/acpi/sleep.c1
-rw-r--r--arch/x86_64/kernel/head.S19
-rw-r--r--arch/x86_64/kernel/setup.c5
-rw-r--r--arch/x86_64/kernel/traps.c4
-rw-r--r--arch/x86_64/mm/fault.c3
-rw-r--r--arch/x86_64/mm/numa.c2
-rw-r--r--drivers/base/node.c7
-rw-r--r--drivers/cdrom/cdrom.c10
-rw-r--r--drivers/char/drm/drm_agpsupport.h2
-rw-r--r--drivers/char/drm/r128_state.c8
-rw-r--r--drivers/char/drm/radeon.h4
-rw-r--r--drivers/char/drm/radeon_drm.h3
-rw-r--r--drivers/char/drm/radeon_drv.h1
-rw-r--r--drivers/char/drm/radeon_mem.c4
-rw-r--r--drivers/char/drm/radeon_state.c2
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c58
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c4
-rw-r--r--drivers/char/pcmcia/synclink_cs.c76
-rw-r--r--drivers/char/synclink.c111
-rw-r--r--drivers/char/synclinkmp.c128
-rw-r--r--drivers/md/dm-ioctl.c4
-rw-r--r--drivers/md/md.c150
-rw-r--r--drivers/md/multipath.c47
-rw-r--r--drivers/md/raid1.c205
-rw-r--r--drivers/md/raid5.c31
-rw-r--r--drivers/md/raid6main.c29
-rw-r--r--drivers/mtd/chips/jedec_probe.c42
-rw-r--r--drivers/pcmcia/ds.c17
-rw-r--r--drivers/video/riva/fbdev.c21
-rw-r--r--fs/ext3/namei.c14
-rw-r--r--fs/nfs/direct.c2
-rw-r--r--fs/nfsd/nfs3proc.c1
-rw-r--r--fs/nfsd/nfs3xdr.c39
-rw-r--r--fs/nfsd/nfs4proc.c2
-rw-r--r--fs/nfsd/nfs4state.c45
-rw-r--r--fs/nfsd/nfs4xdr.c83
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/sysfs/file.c1
-rw-r--r--include/asm-arm/pgtable.h7
-rw-r--r--include/asm-ppc/spinlock.h2
-rw-r--r--include/asm-x86_64/desc.h3
-rw-r--r--include/asm-x86_64/page.h2
-rw-r--r--include/linux/nfsd/export.h3
-rw-r--r--include/linux/nfsd/nfsd.h2
-rw-r--r--include/linux/nfsd/xdr3.h1
-rw-r--r--include/linux/raid/md_k.h10
-rw-r--r--include/linux/raid/raid1.h16
-rw-r--r--include/linux/sunrpc/svcauth.h1
-rw-r--r--kernel/sched.c6
-rw-r--r--mm/memory.c10
-rw-r--r--mm/mmap.c51
-rw-r--r--mm/rmap.c46
-rw-r--r--mm/swap_state.c4
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c18
-rw-r--r--net/sunrpc/svcauth.c30
-rw-r--r--net/sunrpc/svcauth_unix.c3
62 files changed, 982 insertions, 458 deletions
diff --git a/Documentation/filesystems/Exporting b/Documentation/filesystems/Exporting
index 548dcf48e249..31047e0fe14b 100644
--- a/Documentation/filesystems/Exporting
+++ b/Documentation/filesystems/Exporting
@@ -32,7 +32,7 @@ tree. This means that if any filesystem object is in the dcache, then
all of the ancestors of that filesystem object are also in the dcache.
As normal access is by filename this prefix is created naturally and
maintained easily (by each object maintaining a reference count on
-it's parent).
+its parent).
However when objects are included into the dcache by interpreting a
filehandle fragment, there is no automatic creation of a path prefix
@@ -44,15 +44,15 @@ the dcache that are not needed for normal filesystem access.
2/ The dcache must be prepared for a newly found (via ->lookup) directory
to already have a (non-connected) dentry, and must be able to move
that dentry into place (based on the parent and name in the
- ->lookup). This is particuarly needed for directories as
+ ->lookup). This is particularly needed for directories as
it is a dcache invariant that directories only have one dentry.
To implement these features, the dcache has:
-a/ A dentry flag DCACHE_DISCONNECTED which is set on
- and dentry that might not be part of the proper prefix.
+a/ A dentry flag DCACHE_DISCONNECTED which is set on
+ any dentry that might not be part of the proper prefix.
This is set when anonymous dentries are created, and cleared when a
- dentry is noticed to be a child on a dentry which is in the proper
+ dentry is noticed to be a child of a dentry which is in the proper
prefix.
b/ A per-superblock list "s_anon" of dentries which are the roots of
@@ -123,9 +123,9 @@ filesystem:
get_name. When given a parent dentry and a child dentry, this
should find a name in the directory identified by the parent
dentry, which leads to the object identified by the child dentry.
- If no get_name function is supplied, a default implementation
- which used vfs_readdir to find potential names, and matches inode
- numbers to find the correct match.
+ If no get_name function is supplied, a default implementation is
+ provided which uses vfs_readdir to find potential names, and
+ matches inode numbers to find the correct match.
get_parent. When given a dentry for a directory, this should return
a dentry for the parent. Quite possibly the parent dentry will
@@ -135,7 +135,7 @@ filesystem:
->lookup("..") is *not* used as a default as it can leave ".."
entries in the dcache which are too messy to work with.
- get_dentry. When given a opaque datum, this should find the
+ get_dentry. When given an opaque datum, this should find the
implied object and create a dentry for it (possibly with
d_alloc_anon).
The opaque datum is whatever is passed down by the decode_fh
@@ -143,7 +143,7 @@ filesystem:
fragment.
decode_fh passes two datums through find_exported_dentry. One that
should be used to identify the target object, and one that can be
- used to identify the objects parent, should that be necessary.
+ used to identify the object's parent, should that be necessary.
The default get_dentry function assumes that the datum contains an
inode number and a generation number, and it attempts to get the
inode using "iget" and check it's validity by matching the
@@ -164,8 +164,8 @@ filehandle assuming the format used by the default encode_fh and
passed them to find_exported_dentry.
-A filehandle fragment consists of an array of 1 or more 4byte words.
-Together with a one byte "type".
+A filehandle fragment consists of an array of 1 or more 4byte words,
+together with a one byte "type".
The decode_fh routine should not depend on the stated size that is
passed to it. This size may be larger than the original filehandle
generated by encode_fh, in which case it will have been padded with
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index c306fc4699a4..c00061769123 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -348,7 +348,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
if (pmd_none(*pmd_k))
goto bad_area;
- set_pmd(pmd, *pmd_k);
+ copy_pmd(pmd, pmd_k);
return 0;
bad_area:
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index eec9d7b00fbf..32c4b0e35b37 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -40,7 +40,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
*/
cache_type = read_cpuid(CPUID_CACHETYPE);
if (cache_type != read_cpuid(CPUID_ID)) {
- aliasing = (cache_type | cache_type >> 12) & (1 << 9);
+ aliasing = (cache_type | cache_type >> 12) & (1 << 11);
if (aliasing)
do_align = filp || flags & MAP_SHARED;
}
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 4a6226309b49..f031de058808 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -283,7 +283,7 @@ static void handle_BUG(struct pt_regs *regs)
file = "<bad filename>";
printk("------------[ cut here ]------------\n");
- printk("kernel BUG at %s:%d!\n", file, line);
+ printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
no_bug:
return;
@@ -304,7 +304,7 @@ void die(const char * str, struct pt_regs * regs, long err)
spin_lock_irq(&die_lock);
bust_spinlocks(1);
handle_BUG(regs);
- printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+ printk(KERN_ALERT "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
#ifdef CONFIG_PREEMPT
printk("PREEMPT ");
nl = 1;
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index dcec5e732cf6..0c77e0b071eb 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -411,7 +411,7 @@ no_context:
else
printk(KERN_ALERT "Unable to handle kernel paging request");
printk(" at virtual address %08lx\n",address);
- printk(" printing eip:\n");
+ printk(KERN_ALERT " printing eip:\n");
printk("%08lx\n", regs->eip);
asm("movl %%cr3,%0":"=r" (page));
page = ((unsigned long *) __va(page))[address >> 22];
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index df768a0e925a..e569a1435457 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -34,6 +34,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_IOSCHED_NOOP=y
@@ -234,6 +235,7 @@ CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
CONFIG_IDEDMA_AUTO=y
@@ -258,7 +260,6 @@ CONFIG_BLK_DEV_SD=y
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -789,7 +790,6 @@ CONFIG_USB_HIDINPUT=y
# Firmware Drivers
#
# CONFIG_EDD is not set
-# CONFIG_SMBIOS is not set
#
# File systems
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index 73ddfc1eaf60..3331a564fb9e 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -114,7 +114,6 @@ void __init acpi_reserve_bootmem(void)
acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE);
if ((&wakeup_end - &wakeup_start) > PAGE_SIZE)
printk(KERN_CRIT "ACPI: Wakeup code way too big, will crash on attempt to suspend\n");
- Dprintk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address);
}
static int __init acpi_sleep_setup(char *str)
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 23acf2fbdfa3..23a2b5e0216c 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -255,7 +255,7 @@ temp_boot_pmds:
.org 0x5000
ENTRY(level2_kernel_pgt)
- /* 10MB kernel mapping. The kernel code cannot be bigger than that.
+ /* 40MB kernel mapping. The kernel code cannot be bigger than that.
When you change this change KERNEL_TEXT_SIZE in page.h too. */
/* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
.quad 0x0000000000000183
@@ -263,8 +263,21 @@ ENTRY(level2_kernel_pgt)
.quad 0x0000000000400183
.quad 0x0000000000600183
.quad 0x0000000000800183
- /* 10MB mapping for now to decrease the aliasing window */
- .fill 15,8,0
+ .quad 0x0000000000A00183
+ .quad 0x0000000000C00183
+ .quad 0x0000000000E00183
+ .quad 0x0000000001000183
+ .quad 0x0000000001200183
+ .quad 0x0000000001400183
+ .quad 0x0000000001600183
+ .quad 0x0000000001800183
+ .quad 0x0000000001A00183
+ .quad 0x0000000001C00183
+ .quad 0x0000000001E00183
+ .quad 0x0000000002000183
+ .quad 0x0000000002200183
+ .quad 0x0000000002400183
+ .quad 0x0000000002600183
/* Module mapping starts here */
.fill 492,8,0
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index fb3a8abdb852..14a25720fe4d 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -253,6 +253,8 @@ static __init void parse_cmdline_early (char ** cmdline_p)
/* acpi=ht just means: do ACPI MADT parsing
at bootup, but don't enable the full ACPI interpreter */
if (!memcmp(from, "acpi=ht", 7)) {
+ /* if (!acpi_force) */
+ disable_acpi();
acpi_ht = 1;
}
else if (!memcmp(from, "pci=noacpi", 10))
@@ -535,8 +537,7 @@ void __init setup_arch(char **cmdline_p)
* the bootmem allocator) but before get_smp_config (to allow parsing
* of MADT).
*/
- if (!acpi_disabled)
- acpi_boot_init();
+ acpi_boot_init();
#endif
#ifdef CONFIG_X86_LOCAL_APIC
/*
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 70a170032211..d82da80d8613 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -302,7 +302,7 @@ void handle_BUG(struct pt_regs *regs)
if (__get_user(tmp, f.filename))
f.filename = "unmapped filename";
printk("----------- [cut here ] --------- [please bite here ] ---------\n");
- printk("Kernel BUG at %.50s:%d\n", f.filename, f.line);
+ printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line);
}
void out_of_line_bug(void)
@@ -356,7 +356,7 @@ void __die(const char * str, struct pt_regs * regs, long err)
notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
show_registers(regs);
/* Executive summary in case the oops scrolled away */
- printk("RIP ");
+ printk(KERN_ALERT "RIP ");
printk_address(regs->rip);
printk(" RSP <%016lx>\n", regs->rsp);
}
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index e5fd0d44551f..f5edd302a548 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -423,8 +423,9 @@ no_context:
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
else
printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at %016lx RIP: \n",address);
+ printk(" at %016lx RIP: \n" KERN_ALERT,address);
printk_address(regs->rip);
+ printk("\n");
dump_pagetable(address);
__die("Oops", regs, error_code);
/* Executive summary in case the body of the oops scrolled away */
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index e891e9dc3fc4..36743bf531b0 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -124,7 +124,7 @@ void __init setup_node_zones(int nodeid)
start_pfn = node_start_pfn(nodeid);
end_pfn = node_end_pfn(nodeid);
- printk(KERN_INFO "setting up node %d %lx-%lx\n", nodeid, start_pfn, end_pfn);
+ Dprintk(KERN_INFO "setting up node %d %lx-%lx\n", nodeid, start_pfn, end_pfn);
/* All nodes > 0 have a zero length zone DMA */
dma_end_pfn = __pa(MAX_DMA_ADDRESS) >> PAGE_SHIFT;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 7508df3731cc..b5aa9dc6cdb7 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -21,9 +21,10 @@ static ssize_t node_read_cpumap(struct sys_device * dev, char * buf)
cpumask_t mask = node_dev->cpumap;
int len;
- /* FIXME - someone should pass us a buffer size (count) or
- * use seq_file or something to avoid buffer overrun risk. */
- len = cpumask_scnprintf(buf, 99 /* XXX FIXME */, mask);
+ /* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */
+ BUILD_BUG_ON(NR_CPUS/4 > PAGE_SIZE/2);
+
+ len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask);
len += sprintf(buf + len, "\n");
return len;
}
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 01867107d947..c1afb811270b 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -651,7 +651,6 @@ int cdrom_get_random_writable(struct cdrom_device_info *cdi,
{
struct packet_command cgc;
char buffer[24];
- struct feature_header *fh;
int ret;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
@@ -664,14 +663,7 @@ int cdrom_get_random_writable(struct cdrom_device_info *cdi,
if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
return ret;
- fh = (struct feature_header *)&buffer[0];
- if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+
- sizeof(struct rwrt_feature_desc)))
- memcpy(rfd, &buffer[sizeof(struct feature_header)],
- sizeof (*rfd));
- else
- memset(rfd, 0, sizeof(*rfd));
-
+ memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd));
return 0;
}
diff --git a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h
index 2abb7fa017ec..aa7fd54bbf9a 100644
--- a/drivers/char/drm/drm_agpsupport.h
+++ b/drivers/char/drm/drm_agpsupport.h
@@ -109,8 +109,6 @@ int DRM(agp_acquire)(struct inode *inode, struct file *filp,
return -EBUSY;
if (!drm_agp->acquire)
return -EINVAL;
- if ( dev->agp->cant_use_aperture )
- return -EINVAL;
if ((retcode = drm_agp->acquire()))
return retcode;
dev->agp->acquired = 1;
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index 81d2209964f5..6ec11b0254d9 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -916,7 +916,7 @@ static int r128_cce_dispatch_write_span( drm_device_t *dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return -EMSGSIZE;
+ return DRM_ERR(EMSGSIZE);
if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) {
return DRM_ERR(EFAULT);
@@ -1012,7 +1012,7 @@ static int r128_cce_dispatch_write_pixels( drm_device_t *dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return -EMSGSIZE;
+ return DRM_ERR(EMSGSIZE);
xbuf_size = count * sizeof(*x);
ybuf_size = count * sizeof(*y);
@@ -1131,7 +1131,7 @@ static int r128_cce_dispatch_read_span( drm_device_t *dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return -EMSGSIZE;
+ return DRM_ERR(EMSGSIZE);
if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) {
return DRM_ERR(EFAULT);
@@ -1176,7 +1176,7 @@ static int r128_cce_dispatch_read_pixels( drm_device_t *dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return -EMSGSIZE;
+ return DRM_ERR(EMSGSIZE);
if ( count > dev_priv->depth_pitch ) {
count = dev_priv->depth_pitch;
diff --git a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h
index 9a22c0604755..54fac7940015 100644
--- a/drivers/char/drm/radeon.h
+++ b/drivers/char/drm/radeon.h
@@ -51,7 +51,7 @@
#define DRIVER_DATE "20020828"
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 10
+#define DRIVER_MINOR 11
#define DRIVER_PATCHLEVEL 0
/* Interface history:
@@ -84,6 +84,8 @@
* 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which
* clients use to tell the DRM where they think the framebuffer is
* located in the card's address space
+ * 1.11- Add packet R200_EMIT_RB3D_BLENDCOLOR to support GL_EXT_blend_color
+ * and GL_EXT_blend_[func|equation]_separate on r200
*/
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index c60c09fd4ba9..735e04ef4ab7 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -144,7 +144,8 @@
#define RADEON_EMIT_PP_TEX_SIZE_0 73
#define RADEON_EMIT_PP_TEX_SIZE_1 74
#define RADEON_EMIT_PP_TEX_SIZE_2 75
-#define RADEON_MAX_STATE_PACKETS 76
+#define R200_EMIT_RB3D_BLENDCOLOR 76
+#define RADEON_MAX_STATE_PACKETS 77
/* Commands understood by cmd_buffer ioctl. More can be added but
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index afa516e8b950..45eafd056d28 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -690,6 +690,7 @@ extern void radeon_do_release(drm_device_t *dev);
#define R200_SE_VTX_FMT_1 0x208c
#define R200_RE_CNTL 0x1c50
+#define R200_RB3D_BLENDCOLOR 0x3218
/* Constants */
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c
index 3a3bf011a741..83e2f6c04256 100644
--- a/drivers/char/drm/radeon_mem.c
+++ b/drivers/char/drm/radeon_mem.c
@@ -137,12 +137,12 @@ static int init_heap(struct mem_block **heap, int start, int size)
struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks));
if (!blocks)
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
*heap = DRM_MALLOC(sizeof(**heap));
if (!*heap) {
DRM_FREE( blocks, sizeof(*blocks) );
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
blocks->start = start;
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index a8780bc90523..64143d190c16 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -201,6 +201,7 @@ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_
case RADEON_EMIT_PP_TEX_SIZE_0:
case RADEON_EMIT_PP_TEX_SIZE_1:
case RADEON_EMIT_PP_TEX_SIZE_2:
+ case R200_EMIT_RB3D_BLENDCOLOR:
/* These packets don't contain memory offsets */
break;
@@ -563,6 +564,7 @@ static struct {
{ RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0" },
{ RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1" },
{ RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_1" },
+ { R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR" },
};
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index c1e4abf1463b..aa0fe2dbfaf0 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -123,6 +123,12 @@ struct ipmi_channel
unsigned char protocol;
};
+struct ipmi_proc_entry
+{
+ char *name;
+ struct ipmi_proc_entry *next;
+};
+
#define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 8
struct ipmi_smi
@@ -149,6 +155,11 @@ struct ipmi_smi
struct ipmi_smi_handlers *handlers;
void *send_info;
+ /* A list of proc entries for this interface. This does not
+ need a lock, only one thread creates it and only one thread
+ destroys it. */
+ struct ipmi_proc_entry *proc_entries;
+
/* A table of sequence numbers for this interface. We use the
sequence numbers for IPMB messages that go out of the
interface to match them up with their responses. A routine
@@ -1515,18 +1526,36 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
read_proc_t *read_proc, write_proc_t *write_proc,
void *data, struct module *owner)
{
- struct proc_dir_entry *file;
- int rv = 0;
+ struct proc_dir_entry *file;
+ int rv = 0;
+ struct ipmi_proc_entry *entry;
+
+ /* Create a list element. */
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
+ if (!entry->name) {
+ kfree(entry);
+ return -ENOMEM;
+ }
+ strcpy(entry->name, name);
file = create_proc_entry(name, 0, smi->proc_dir);
- if (!file)
+ if (!file) {
+ kfree(entry->name);
+ kfree(entry);
rv = -ENOMEM;
- else {
+ } else {
file->nlink = 1;
file->data = data;
file->read_proc = read_proc;
file->write_proc = write_proc;
file->owner = owner;
+
+ /* Stick it on the list. */
+ entry->next = smi->proc_entries;
+ smi->proc_entries = entry;
}
return rv;
@@ -1562,6 +1591,21 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
return rv;
}
+static void remove_proc_entries(ipmi_smi_t smi)
+{
+ struct ipmi_proc_entry *entry;
+
+ while (smi->proc_entries) {
+ entry = smi->proc_entries;
+ smi->proc_entries = entry->next;
+
+ remove_proc_entry(entry->name, smi->proc_dir);
+ kfree(entry->name);
+ kfree(entry);
+ }
+ remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
+}
+
static int
send_channel_info_cmd(ipmi_smi_t intf, int chan)
{
@@ -1749,8 +1793,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
if (rv) {
if (new_intf->proc_dir)
- remove_proc_entry(new_intf->proc_dir_name,
- proc_ipmi_root);
+ remove_proc_entries(new_intf);
kfree(new_intf);
}
@@ -1806,8 +1849,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
{
for (i=0; i<MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == intf) {
- remove_proc_entry(intf->proc_dir_name,
- proc_ipmi_root);
+ remove_proc_entries(intf);
spin_lock_irqsave(&interfaces_lock, flags);
ipmi_interfaces[i] = NULL;
clean_up_interface_data(intf);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 34ceaeed6890..8a1fd40d5b48 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -905,10 +905,10 @@ MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the"
" has an interrupt. Otherwise, set it to zero or leave"
" it blank.");
-
-#if defined(CONFIG_ACPI_INTERPETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)
#define IPMI_MEM_ADDR_SPACE 1
#define IPMI_IO_ADDR_SPACE 2
+
+#if defined(CONFIG_ACPI_INTERPETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)
static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr)
{
int i;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index ae29bf14c1e6..970e2331a4fb 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/pcmcia/synclink_cs.c
*
- * $Id: synclink_cs.c,v 4.21 2004/03/08 15:29:23 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.22 2004/06/01 20:27:46 paulkf Exp $
*
* Device driver for Microgate SyncLink PC Card
* multiprotocol serial adapter.
@@ -489,7 +489,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
MODULE_LICENSE("GPL");
static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.21 $";
+static char *driver_version = "$Revision: 4.22 $";
static struct tty_driver *serial_driver;
@@ -3133,9 +3133,35 @@ static struct tty_operations mgslpc_ops = {
.tiocmset = tiocmset,
};
+static void synclink_cs_cleanup(void)
+{
+ int rc;
+
+ printk("Unloading %s: version %s\n", driver_name, driver_version);
+
+ while(mgslpc_device_list)
+ mgslpc_remove_device(mgslpc_device_list);
+
+ if (serial_driver) {
+ if ((rc = tty_unregister_driver(serial_driver)))
+ printk("%s(%d) failed to unregister tty driver err=%d\n",
+ __FILE__,__LINE__,rc);
+ put_tty_driver(serial_driver);
+ }
+
+ pcmcia_unregister_driver(&mgslpc_driver);
+
+ /* XXX: this really needs to move into generic code.. */
+ while (dev_list != NULL) {
+ if (dev_list->state & DEV_CONFIG)
+ mgslpc_release((u_long)dev_list);
+ mgslpc_detach(dev_list);
+ }
+}
+
static int __init synclink_cs_init(void)
{
- int error;
+ int rc;
if (break_on_load) {
mgslpc_get_text_ptr();
@@ -3144,14 +3170,13 @@ static int __init synclink_cs_init(void)
printk("%s %s\n", driver_name, driver_version);
- serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
- if (!serial_driver)
- return -ENOMEM;
+ if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
+ return rc;
- error = pcmcia_register_driver(&mgslpc_driver);
- if (error) {
- put_tty_driver(serial_driver);
- return error;
+ serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
+ if (!serial_driver) {
+ rc = -ENOMEM;
+ goto error;
}
/* Initialize the tty_driver structure */
@@ -3169,39 +3194,28 @@ static int __init synclink_cs_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &mgslpc_ops);
- if (tty_register_driver(serial_driver) < 0)
+ if ((rc = tty_register_driver(serial_driver)) < 0) {
printk("%s(%d):Couldn't register serial driver\n",
__FILE__,__LINE__);
+ put_tty_driver(serial_driver);
+ serial_driver = NULL;
+ goto error;
+ }
printk("%s %s, tty major#%d\n",
driver_name, driver_version,
serial_driver->major);
return 0;
+
+error:
+ synclink_cs_cleanup();
+ return rc;
}
static void __exit synclink_cs_exit(void)
{
- int rc;
-
- printk("Unloading %s: version %s\n", driver_name, driver_version);
-
- while(mgslpc_device_list)
- mgslpc_remove_device(mgslpc_device_list);
-
- if ((rc = tty_unregister_driver(serial_driver)))
- printk("%s(%d) failed to unregister tty driver err=%d\n",
- __FILE__,__LINE__,rc);
- put_tty_driver(serial_driver);
-
- pcmcia_unregister_driver(&mgslpc_driver);
-
- /* XXX: this really needs to move into generic code.. */
- while (dev_list != NULL) {
- if (dev_list->state & DEV_CONFIG)
- mgslpc_release((u_long)dev_list);
- mgslpc_detach(dev_list);
- }
+ synclink_cs_cleanup();
}
module_init(synclink_cs_init);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 9463f585fc06..55bea6b2e503 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/synclink.c
*
- * $Id: synclink.c,v 4.21 2004/03/08 15:29:22 paulkf Exp $
+ * $Id: synclink.c,v 4.24 2004/06/03 14:50:09 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
@@ -782,7 +782,6 @@ int mgsl_claim_resources(struct mgsl_struct *info);
void mgsl_release_resources(struct mgsl_struct *info);
void mgsl_add_device(struct mgsl_struct *info);
struct mgsl_struct* mgsl_allocate_device(void);
-int mgsl_enum_isa_devices(void);
/*
* DMA buffer manupulation functions.
@@ -866,6 +865,9 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info );
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+/* set non-zero on successful registration with PCI subsystem */
+static int pci_registered;
+
/*
* Global linked list of SyncLink devices
*/
@@ -909,7 +911,7 @@ MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.21 $";
+static char *driver_version = "$Revision: 4.24 $";
static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
@@ -4487,9 +4489,11 @@ static struct tty_operations mgsl_ops = {
/*
* perform tty device initialization
*/
-int mgsl_init_tty(void)
+static int mgsl_init_tty(void)
{
- serial_driver = alloc_tty_driver(mgsl_device_count);
+ int rc;
+
+ serial_driver = alloc_tty_driver(128);
if (!serial_driver)
return -ENOMEM;
@@ -4505,9 +4509,13 @@ int mgsl_init_tty(void)
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &mgsl_ops);
- if (tty_register_driver(serial_driver) < 0)
+ if ((rc = tty_register_driver(serial_driver)) < 0) {
printk("%s(%d):Couldn't register serial driver\n",
__FILE__,__LINE__);
+ put_tty_driver(serial_driver);
+ serial_driver = NULL;
+ return rc;
+ }
printk("%s %s, tty major#%d\n",
driver_name, driver_version,
@@ -4517,7 +4525,7 @@ int mgsl_init_tty(void)
/* enumerate user specified ISA adapters
*/
-int mgsl_enum_isa_devices(void)
+static int mgsl_enum_isa_devices(void)
{
struct mgsl_struct *info;
int i;
@@ -4548,51 +4556,9 @@ int mgsl_enum_isa_devices(void)
mgsl_add_device( info );
}
-
- return 0;
}
-/* mgsl_init()
- *
- * Driver initialization entry point.
- *
- * Arguments: None
- * Return Value: 0 if success, otherwise error code
- */
-int __init mgsl_init(void)
-{
- int rc;
-
- printk("%s %s\n", driver_name, driver_version);
-
- mgsl_enum_isa_devices();
- pci_register_driver(&synclink_pci_driver);
-
- if ( !mgsl_device_list ) {
- printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__);
- return -ENODEV;
- }
- if ((rc = mgsl_init_tty()))
- return rc;
-
- return 0;
-}
-
-static int __init synclink_init(void)
-{
-/* Uncomment this to kernel debug module.
- * mgsl_get_text_ptr() leaves the .text address in eax
- * which can be used with add-symbol-file with gdb.
- */
- if (break_on_load) {
- mgsl_get_text_ptr();
- BREAKPOINT();
- }
-
- return mgsl_init();
-}
-
-static void __exit synclink_exit(void)
+static void synclink_cleanup(void)
{
int rc;
struct mgsl_struct *info;
@@ -4600,11 +4566,13 @@ static void __exit synclink_exit(void)
printk("Unloading %s: %s\n", driver_name, driver_version);
- if ((rc = tty_unregister_driver(serial_driver)))
- printk("%s(%d) failed to unregister tty driver err=%d\n",
- __FILE__,__LINE__,rc);
+ if (serial_driver) {
+ if ((rc = tty_unregister_driver(serial_driver)))
+ printk("%s(%d) failed to unregister tty driver err=%d\n",
+ __FILE__,__LINE__,rc);
+ put_tty_driver(serial_driver);
+ }
- put_tty_driver(serial_driver);
info = mgsl_device_list;
while(info) {
#ifdef CONFIG_SYNCLINK_SYNCPPP
@@ -4622,7 +4590,40 @@ static void __exit synclink_exit(void)
tmp_buf = NULL;
}
- pci_unregister_driver(&synclink_pci_driver);
+ if (pci_registered)
+ pci_unregister_driver(&synclink_pci_driver);
+}
+
+static int __init synclink_init(void)
+{
+ int rc;
+
+ if (break_on_load) {
+ mgsl_get_text_ptr();
+ BREAKPOINT();
+ }
+
+ printk("%s %s\n", driver_name, driver_version);
+
+ mgsl_enum_isa_devices();
+ if ((rc = pci_register_driver(&synclink_pci_driver)) < 0)
+ printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc);
+ else
+ pci_registered = 1;
+
+ if ((rc = mgsl_init_tty()) < 0)
+ goto error;
+
+ return 0;
+
+error:
+ synclink_cleanup();
+ return rc;
+}
+
+static void __exit synclink_exit(void)
+{
+ synclink_cleanup();
}
module_init(synclink_init);
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index d82335ed7b04..e76454311129 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1,5 +1,5 @@
/*
- * $Id: synclinkmp.c,v 4.19 2004/03/08 15:29:23 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.22 2004/06/03 14:50:10 paulkf Exp $
*
* Device driver for Microgate SyncLink Multiport
* high speed multiprotocol serial adapter.
@@ -494,7 +494,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.19 $";
+static char *driver_version = "$Revision: 4.22 $";
static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -3781,56 +3781,7 @@ static struct tty_operations ops = {
.tiocmset = tiocmset,
};
-/* Driver initialization entry point.
- */
-
-static int __init synclinkmp_init(void)
-{
- if (break_on_load) {
- synclinkmp_get_text_ptr();
- BREAKPOINT();
- }
-
- printk("%s %s\n", driver_name, driver_version);
-
- synclinkmp_adapter_count = -1;
- pci_register_driver(&synclinkmp_pci_driver);
-
- if ( !synclinkmp_device_list ) {
- printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__);
- return -ENODEV;
- }
-
- serial_driver = alloc_tty_driver(synclinkmp_device_count);
- if (!serial_driver)
- return -ENOMEM;
-
- /* Initialize the tty_driver structure */
-
- serial_driver->owner = THIS_MODULE;
- serial_driver->driver_name = "synclinkmp";
- serial_driver->name = "ttySLM";
- serial_driver->major = ttymajor;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &ops);
- if (tty_register_driver(serial_driver) < 0)
- printk("%s(%d):Couldn't register serial driver\n",
- __FILE__,__LINE__);
-
- printk("%s %s, tty major#%d\n",
- driver_name, driver_version,
- serial_driver->major);
-
- return 0;
-}
-
-static void __exit synclinkmp_exit(void)
+static void synclinkmp_cleanup(void)
{
unsigned long flags;
int rc;
@@ -3839,10 +3790,12 @@ static void __exit synclinkmp_exit(void)
printk("Unloading %s %s\n", driver_name, driver_version);
- if ((rc = tty_unregister_driver(serial_driver)))
- printk("%s(%d) failed to unregister tty driver err=%d\n",
- __FILE__,__LINE__,rc);
- put_tty_driver(serial_driver);
+ if (serial_driver) {
+ if ((rc = tty_unregister_driver(serial_driver)))
+ printk("%s(%d) failed to unregister tty driver err=%d\n",
+ __FILE__,__LINE__,rc);
+ put_tty_driver(serial_driver);
+ }
info = synclinkmp_device_list;
while(info) {
@@ -3882,6 +3835,69 @@ static void __exit synclinkmp_exit(void)
pci_unregister_driver(&synclinkmp_pci_driver);
}
+/* Driver initialization entry point.
+ */
+
+static int __init synclinkmp_init(void)
+{
+ int rc;
+
+ if (break_on_load) {
+ synclinkmp_get_text_ptr();
+ BREAKPOINT();
+ }
+
+ printk("%s %s\n", driver_name, driver_version);
+
+ if ((rc = pci_register_driver(&synclinkmp_pci_driver)) < 0) {
+ printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc);
+ return rc;
+ }
+
+ serial_driver = alloc_tty_driver(128);
+ if (!serial_driver) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ /* Initialize the tty_driver structure */
+
+ serial_driver->owner = THIS_MODULE;
+ serial_driver->driver_name = "synclinkmp";
+ serial_driver->name = "ttySLM";
+ serial_driver->major = ttymajor;
+ serial_driver->minor_start = 64;
+ serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_driver->init_termios = tty_std_termios;
+ serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(serial_driver, &ops);
+ if ((rc = tty_register_driver(serial_driver)) < 0) {
+ printk("%s(%d):Couldn't register serial driver\n",
+ __FILE__,__LINE__);
+ put_tty_driver(serial_driver);
+ serial_driver = NULL;
+ goto error;
+ }
+
+ printk("%s %s, tty major#%d\n",
+ driver_name, driver_version,
+ serial_driver->major);
+
+ return 0;
+
+error:
+ synclinkmp_cleanup();
+ return rc;
+}
+
+static void __exit synclinkmp_exit(void)
+{
+ synclinkmp_cleanup();
+}
+
module_init(synclinkmp_init);
module_exit(synclinkmp_exit);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index c699c70e825c..e1703f77c196 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -417,9 +417,9 @@ static int list_devices(struct dm_ioctl *param, size_t param_size)
return 0;
}
-static void list_version_get_needed(struct target_type *tt, void *param)
+static void list_version_get_needed(struct target_type *tt, void *needed_param)
{
- int *needed = param;
+ size_t *needed = needed_param;
*needed += strlen(tt->name);
*needed += sizeof(tt->version);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d6a0258afc78..77cd6e9f3acd 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2251,7 +2251,12 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
return -EINVAL;
}
- rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
+ if (mddev->persistent)
+ rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
+ else
+ rdev->sb_offset =
+ rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+
size = calc_dev_size(rdev, mddev->chunk_size);
rdev->size = size;
@@ -2372,6 +2377,103 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
return 0;
}
+/*
+ * update_array_info is used to change the configuration of an
+ * on-line array.
+ * The version, ctime,level,size,raid_disks,not_persistent, layout,chunk_size
+ * fields in the info are checked against the array.
+ * Any differences that cannot be handled will cause an error.
+ * Normally, only one change can be managed at a time.
+ */
+static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
+{
+ int rv = 0;
+ int cnt = 0;
+
+ if (mddev->major_version != info->major_version ||
+ mddev->minor_version != info->minor_version ||
+/* mddev->patch_version != info->patch_version || */
+ mddev->ctime != info->ctime ||
+ mddev->level != info->level ||
+ mddev->layout != info->layout ||
+ !mddev->persistent != info->not_persistent||
+ mddev->chunk_size != info->chunk_size )
+ return -EINVAL;
+ /* Check there is only one change */
+ if (mddev->size != info->size) cnt++;
+ if (mddev->raid_disks != info->raid_disks) cnt++;
+ if (cnt == 0) return 0;
+ if (cnt > 1) return -EINVAL;
+
+ if (mddev->size != info->size) {
+ mdk_rdev_t * rdev;
+ struct list_head *tmp;
+ if (mddev->pers->resize == NULL)
+ return -EINVAL;
+ /* The "size" is the amount of each device that is used.
+ * This can only make sense for arrays with redundancy.
+ * linear and raid0 always use whatever space is available
+ * We can only consider changing the size of no resync
+ * or reconstruction is happening, and if the new size
+ * is acceptable. It must fit before the sb_offset or,
+ * if that is <data_offset, it must fit before the
+ * size of each device.
+ * If size is zero, we find the largest size that fits.
+ */
+ if (mddev->sync_thread)
+ return -EBUSY;
+ ITERATE_RDEV(mddev,rdev,tmp) {
+ sector_t avail;
+ int fit = (info->size == 0);
+ if (rdev->sb_offset > rdev->data_offset)
+ avail = (rdev->sb_offset*2) - rdev->data_offset;
+ else
+ avail = get_capacity(rdev->bdev->bd_disk)
+ - rdev->data_offset;
+ if (fit && (info->size == 0 || info->size > avail/2))
+ info->size = avail/2;
+ if (avail < ((sector_t)info->size << 1))
+ return -ENOSPC;
+ }
+ rv = mddev->pers->resize(mddev, (sector_t)info->size *2);
+ if (!rv) {
+ struct block_device *bdev;
+
+ bdev = bdget_disk(mddev->gendisk, 0);
+ if (bdev) {
+ down(&bdev->bd_inode->i_sem);
+ i_size_write(bdev->bd_inode, mddev->array_size << 10);
+ up(&bdev->bd_inode->i_sem);
+ bdput(bdev);
+ }
+ }
+ }
+ if (mddev->raid_disks != info->raid_disks) {
+ /* change the number of raid disks */
+ if (mddev->pers->reshape == NULL)
+ return -EINVAL;
+ if (info->raid_disks <= 0 ||
+ info->raid_disks >= mddev->max_disks)
+ return -EINVAL;
+ if (mddev->sync_thread)
+ return -EBUSY;
+ rv = mddev->pers->reshape(mddev, info->raid_disks);
+ if (!rv) {
+ struct block_device *bdev;
+
+ bdev = bdget_disk(mddev->gendisk, 0);
+ if (bdev) {
+ down(&bdev->bd_inode->i_sem);
+ i_size_write(bdev->bd_inode, mddev->array_size << 10);
+ up(&bdev->bd_inode->i_sem);
+ bdput(bdev);
+ }
+ }
+ }
+ md_update_sb(mddev);
+ return rv;
+}
+
static int set_disk_faulty(mddev_t *mddev, dev_t dev)
{
mdk_rdev_t *rdev;
@@ -2464,21 +2566,6 @@ static int md_ioctl(struct inode *inode, struct file *file,
switch (cmd)
{
case SET_ARRAY_INFO:
-
- if (!list_empty(&mddev->disks)) {
- printk(KERN_WARNING
- "md: array %s already has disks!\n",
- mdname(mddev));
- err = -EBUSY;
- goto abort_unlock;
- }
- if (mddev->raid_disks) {
- printk(KERN_WARNING
- "md: array %s already initialised!\n",
- mdname(mddev));
- err = -EBUSY;
- goto abort_unlock;
- }
{
mdu_array_info_t info;
if (!arg)
@@ -2487,10 +2574,33 @@ static int md_ioctl(struct inode *inode, struct file *file,
err = -EFAULT;
goto abort_unlock;
}
+ if (mddev->pers) {
+ err = update_array_info(mddev, &info);
+ if (err) {
+ printk(KERN_WARNING "md: couldn't update"
+ " array info. %d\n", err);
+ goto abort_unlock;
+ }
+ goto done_unlock;
+ }
+ if (!list_empty(&mddev->disks)) {
+ printk(KERN_WARNING
+ "md: array %s already has disks!\n",
+ mdname(mddev));
+ err = -EBUSY;
+ goto abort_unlock;
+ }
+ if (mddev->raid_disks) {
+ printk(KERN_WARNING
+ "md: array %s already initialised!\n",
+ mdname(mddev));
+ err = -EBUSY;
+ goto abort_unlock;
+ }
err = set_array_info(mddev, &info);
if (err) {
printk(KERN_WARNING "md: couldn't set"
- " array info. %d\n", err);
+ " array info. %d\n", err);
goto abort_unlock;
}
}
@@ -3279,7 +3389,7 @@ static void md_do_sync(mddev_t *mddev)
j += sectors;
if (j>1) mddev->curr_resync = j;
- if (last_check + window > j)
+ if (last_check + window > j || j == max_sectors)
continue;
last_check = j;
@@ -3445,8 +3555,8 @@ void md_check_recovery(mddev_t *mddev)
if (rdev->raid_disk >= 0 &&
rdev->faulty &&
atomic_read(&rdev->nr_pending)==0) {
- mddev->pers->hot_remove_disk(mddev, rdev->raid_disk);
- rdev->raid_disk = -1;
+ if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0)
+ rdev->raid_disk = -1;
}
if (!rdev->faulty && rdev->raid_disk >= 0 && !rdev->in_sync)
spares++;
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 8f675d17f9d0..3d8790135a05 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -54,9 +54,8 @@ static void mp_pool_free(void *mpb, void *data)
kfree(mpb);
}
-static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
+static int multipath_map (multipath_conf_t *conf)
{
- multipath_conf_t *conf = mddev_to_conf(mddev);
int i, disks = conf->raid_disks;
/*
@@ -68,10 +67,9 @@ static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
for (i = 0; i < disks; i++) {
mdk_rdev_t *rdev = conf->multipaths[i].rdev;
if (rdev && rdev->in_sync) {
- *rdevp = rdev;
atomic_inc(&rdev->nr_pending);
spin_unlock_irq(&conf->device_lock);
- return 0;
+ return i;
}
}
spin_unlock_irq(&conf->device_lock);
@@ -133,25 +131,7 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error)
(unsigned long long)bio->bi_sector);
multipath_reschedule_retry(mp_bh);
}
- atomic_dec(&rdev->nr_pending);
- return 0;
-}
-
-/*
- * This routine returns the disk from which the requested read should
- * be done.
- */
-
-static int multipath_read_balance (multipath_conf_t *conf)
-{
- int disk;
-
- for (disk = 0; disk < conf->raid_disks; disk++) {
- mdk_rdev_t *rdev = conf->multipaths[disk].rdev;
- if (rdev && rdev->in_sync)
- return disk;
- }
- BUG();
+ rdev_dec_pending(rdev, conf->mddev);
return 0;
}
@@ -204,14 +184,14 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
disk_stat_inc(mddev->gendisk, reads);
disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio));
}
- /*
- * read balancing logic:
- */
- spin_lock_irq(&conf->device_lock);
- mp_bh->path = multipath_read_balance(conf);
+
+ mp_bh->path = multipath_map(conf);
+ if (mp_bh->path < 0) {
+ bio_endio(bio, bio->bi_size, -EIO);
+ mempool_free(mp_bh, conf->pool);
+ return 0;
+ }
multipath = conf->multipaths + mp_bh->path;
- atomic_inc(&multipath->rdev->nr_pending);
- spin_unlock_irq(&conf->device_lock);
mp_bh->bio = *bio;
mp_bh->bio.bi_bdev = multipath->rdev->bdev;
@@ -375,7 +355,7 @@ static void multipathd (mddev_t *mddev)
struct multipath_bh *mp_bh;
struct bio *bio;
unsigned long flags;
- mdk_rdev_t *rdev;
+ multipath_conf_t *conf = mddev_to_conf(mddev);
md_check_recovery(mddev);
for (;;) {
@@ -391,8 +371,7 @@ static void multipathd (mddev_t *mddev)
bio = &mp_bh->bio;
bio->bi_sector = mp_bh->master_bio->bi_sector;
- rdev = NULL;
- if (multipath_map (mddev, &rdev)<0) {
+ if ((mp_bh->path = multipath_map (conf))<0) {
printk(KERN_ALERT "multipath: %s: unrecoverable IO read"
" error for block %llu\n",
bdevname(bio->bi_bdev,b),
@@ -403,7 +382,7 @@ static void multipathd (mddev_t *mddev)
" to another IO path\n",
bdevname(bio->bi_bdev,b),
(unsigned long long)bio->bi_sector);
- bio->bi_bdev = rdev->bdev;
+ bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev;
generic_make_request(bio);
}
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index c600b1b2da85..1b80c5b68f54 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -42,16 +42,17 @@ static void unplug_slaves(mddev_t *mddev);
static void * r1bio_pool_alloc(int gfp_flags, void *data)
{
- mddev_t *mddev = data;
+ struct pool_info *pi = data;
r1bio_t *r1_bio;
/* allocate a r1bio with room for raid_disks entries in the bios array */
- r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*mddev->raid_disks,
+ r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*pi->raid_disks,
gfp_flags);
if (r1_bio)
- memset(r1_bio, 0, sizeof(*r1_bio) + sizeof(struct bio*)*mddev->raid_disks);
+ memset(r1_bio, 0, sizeof(*r1_bio) +
+ sizeof(struct bio*) * pi->raid_disks);
else
- unplug_slaves(mddev);
+ unplug_slaves(pi->mddev);
return r1_bio;
}
@@ -69,22 +70,22 @@ static void r1bio_pool_free(void *r1_bio, void *data)
static void * r1buf_pool_alloc(int gfp_flags, void *data)
{
- conf_t *conf = data;
+ struct pool_info *pi = data;
struct page *page;
r1bio_t *r1_bio;
struct bio *bio;
int i, j;
- r1_bio = r1bio_pool_alloc(gfp_flags, conf->mddev);
+ r1_bio = r1bio_pool_alloc(gfp_flags, pi);
if (!r1_bio) {
- unplug_slaves(conf->mddev);
+ unplug_slaves(pi->mddev);
return NULL;
}
/*
* Allocate bios : 1 for reading, n-1 for writing
*/
- for (j = conf->raid_disks ; j-- ; ) {
+ for (j = pi->raid_disks ; j-- ; ) {
bio = bio_alloc(gfp_flags, RESYNC_PAGES);
if (!bio)
goto out_free_bio;
@@ -111,16 +112,16 @@ out_free_pages:
for ( ; i > 0 ; i--)
__free_page(bio->bi_io_vec[i-1].bv_page);
out_free_bio:
- while ( ++j < conf->raid_disks )
+ while ( ++j < pi->raid_disks )
bio_put(r1_bio->bios[j]);
- r1bio_pool_free(r1_bio, conf->mddev);
+ r1bio_pool_free(r1_bio, data);
return NULL;
}
static void r1buf_pool_free(void *__r1_bio, void *data)
{
+ struct pool_info *pi = data;
int i;
- conf_t *conf = data;
r1bio_t *r1bio = __r1_bio;
struct bio *bio = r1bio->bios[0];
@@ -128,10 +129,10 @@ static void r1buf_pool_free(void *__r1_bio, void *data)
__free_page(bio->bi_io_vec[i].bv_page);
bio->bi_io_vec[i].bv_page = NULL;
}
- for (i=0 ; i < conf->raid_disks; i++)
+ for (i=0 ; i < pi->raid_disks; i++)
bio_put(r1bio->bios[i]);
- r1bio_pool_free(r1bio, conf->mddev);
+ r1bio_pool_free(r1bio, data);
}
static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
@@ -296,7 +297,7 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
reschedule_retry(r1_bio);
}
- atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
+ rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
return 0;
}
@@ -343,7 +344,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
raid_end_bio_io(r1_bio);
}
- atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
+ rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
return 0;
}
@@ -510,7 +511,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mirror_info_t *mirror;
r1bio_t *r1_bio;
struct bio *read_bio;
- int i, disks = conf->raid_disks;
+ int i, disks;
/*
* Register the new request and wait if the reconstruction
@@ -570,6 +571,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
* inc refcount on their rdev. Record them by setting
* bios[x] to bio
*/
+ disks = conf->raid_disks;
spin_lock_irq(&conf->device_lock);
for (i = 0; i < disks; i++) {
if (conf->mirrors[i].rdev &&
@@ -805,7 +807,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
conf->mirrors[r1_bio->read_disk].rdev);
else
set_bit(R1BIO_Uptodate, &r1_bio->state);
- atomic_dec(&conf->mirrors[r1_bio->read_disk].rdev->nr_pending);
+ rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev);
reschedule_retry(r1_bio);
return 0;
}
@@ -835,7 +837,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
md_done_sync(mddev, r1_bio->sectors, uptodate);
put_buf(r1_bio);
}
- atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
+ rdev_dec_pending(conf->mirrors[mirror].rdev, mddev);
return 0;
}
@@ -953,7 +955,8 @@ static int init_resync(conf_t *conf)
buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
if (conf->r1buf_pool)
BUG();
- conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, conf);
+ conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free,
+ conf->poolinfo);
if (!conf->r1buf_pool)
return -ENOMEM;
conf->next_resync = 0;
@@ -979,6 +982,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
sector_t max_sector, nr_sectors;
int disk;
int i;
+ int write_targets = 0;
if (!conf->r1buf_pool)
if (init_resync(conf))
@@ -1055,12 +1059,24 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
sector_nr + RESYNC_SECTORS > mddev->recovery_cp)) {
bio->bi_rw = WRITE;
bio->bi_end_io = end_sync_write;
+ write_targets ++;
} else
continue;
bio->bi_sector = sector_nr + conf->mirrors[i].rdev->data_offset;
bio->bi_bdev = conf->mirrors[i].rdev->bdev;
bio->bi_private = r1_bio;
}
+ if (write_targets == 0) {
+ /* There is nowhere to write, so all non-sync
+ * drives must be failed - so we are finished
+ */
+ int rv = max_sector - sector_nr;
+ md_done_sync(mddev, rv, 1);
+ put_buf(r1_bio);
+ atomic_dec(&conf->mirrors[disk].rdev->nr_pending);
+ return rv;
+ }
+
nr_sectors = 0;
do {
struct page *page;
@@ -1123,28 +1139,28 @@ static int run(mddev_t *mddev)
*/
conf = kmalloc(sizeof(conf_t), GFP_KERNEL);
mddev->private = conf;
- if (!conf) {
- printk(KERN_ERR "raid1: couldn't allocate memory for %s\n",
- mdname(mddev));
- goto out;
- }
+ if (!conf)
+ goto out_no_mem;
+
memset(conf, 0, sizeof(*conf));
conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks,
GFP_KERNEL);
- if (!conf->mirrors) {
- printk(KERN_ERR "raid1: couldn't allocate memory for %s\n",
- mdname(mddev));
- goto out_free_conf;
- }
+ if (!conf->mirrors)
+ goto out_no_mem;
+
memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks);
+ conf->poolinfo = kmalloc(sizeof(*conf->poolinfo), GFP_KERNEL);
+ if (!conf->poolinfo)
+ goto out_no_mem;
+ conf->poolinfo->mddev = mddev;
+ conf->poolinfo->raid_disks = mddev->raid_disks;
conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
- r1bio_pool_free, mddev);
- if (!conf->r1bio_pool) {
- printk(KERN_ERR "raid1: couldn't allocate memory for %s\n",
- mdname(mddev));
- goto out_free_conf;
- }
+ r1bio_pool_free,
+ conf->poolinfo);
+ if (!conf->r1bio_pool)
+ goto out_no_mem;
+
mddev->queue->unplug_fn = raid1_unplug;
@@ -1230,13 +1246,21 @@ static int run(mddev_t *mddev)
return 0;
+out_no_mem:
+ printk(KERN_ERR "raid1: couldn't allocate memory for %s\n",
+ mdname(mddev));
+
out_free_conf:
- if (conf->r1bio_pool)
- mempool_destroy(conf->r1bio_pool);
- if (conf->mirrors)
- kfree(conf->mirrors);
- kfree(conf);
- mddev->private = NULL;
+ if (conf) {
+ if (conf->r1bio_pool)
+ mempool_destroy(conf->r1bio_pool);
+ if (conf->mirrors)
+ kfree(conf->mirrors);
+ if (conf->poolinfo)
+ kfree(conf->poolinfo);
+ kfree(conf);
+ mddev->private = NULL;
+ }
out:
return -EIO;
}
@@ -1251,11 +1275,108 @@ static int stop(mddev_t *mddev)
mempool_destroy(conf->r1bio_pool);
if (conf->mirrors)
kfree(conf->mirrors);
+ if (conf->poolinfo)
+ kfree(conf->poolinfo);
kfree(conf);
mddev->private = NULL;
return 0;
}
+static int raid1_resize(mddev_t *mddev, sector_t sectors)
+{
+ /* no resync is happening, and there is enough space
+ * on all devices, so we can resize.
+ * We need to make sure resync covers any new space.
+ * If the array is shrinking we should possibly wait until
+ * any io in the removed space completes, but it hardly seems
+ * worth it.
+ */
+ mddev->array_size = sectors>>1;
+ set_capacity(mddev->gendisk, mddev->array_size << 1);
+ mddev->changed = 1;
+ if (mddev->array_size > mddev->size && mddev->recovery_cp == MaxSector) {
+ mddev->recovery_cp = mddev->size << 1;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ }
+ mddev->size = mddev->array_size;
+ return 0;
+}
+
+static int raid1_reshape(mddev_t *mddev, int raid_disks)
+{
+ /* We need to:
+ * 1/ resize the r1bio_pool
+ * 2/ resize conf->mirrors
+ *
+ * We allocate a new r1bio_pool if we can.
+ * Then raise a device barrier and wait until all IO stops.
+ * Then resize conf->mirrors and swap in the new r1bio pool.
+ */
+ mempool_t *newpool, *oldpool;
+ struct pool_info *newpoolinfo;
+ mirror_info_t *newmirrors;
+ conf_t *conf = mddev_to_conf(mddev);
+
+ int d;
+
+ for (d= raid_disks; d < conf->raid_disks; d++)
+ if (conf->mirrors[d].rdev)
+ return -EBUSY;
+
+ newpoolinfo = kmalloc(sizeof(newpoolinfo), GFP_KERNEL);
+ if (!newpoolinfo)
+ return -ENOMEM;
+ newpoolinfo->mddev = mddev;
+ newpoolinfo->raid_disks = raid_disks;
+
+ newpool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
+ r1bio_pool_free, newpoolinfo);
+ if (!newpool) {
+ kfree(newpoolinfo);
+ return -ENOMEM;
+ }
+ newmirrors = kmalloc(sizeof(struct mirror_info) * raid_disks, GFP_KERNEL);
+ if (!newmirrors) {
+ kfree(newpoolinfo);
+ mempool_destroy(newpool);
+ return -ENOMEM;
+ }
+ memset(newmirrors, 0, sizeof(struct mirror_info)*raid_disks);
+
+ spin_lock_irq(&conf->resync_lock);
+ conf->barrier++;
+ wait_event_lock_irq(conf->wait_idle, !conf->nr_pending,
+ conf->resync_lock, unplug_slaves(mddev));
+ spin_unlock_irq(&conf->resync_lock);
+
+ /* ok, everything is stopped */
+ oldpool = conf->r1bio_pool;
+ conf->r1bio_pool = newpool;
+ for (d=0; d < raid_disks && d < conf->raid_disks; d++)
+ newmirrors[d] = conf->mirrors[d];
+ kfree(conf->mirrors);
+ conf->mirrors = newmirrors;
+ kfree(conf->poolinfo);
+ conf->poolinfo = newpoolinfo;
+
+ mddev->degraded += (raid_disks - conf->raid_disks);
+ conf->raid_disks = mddev->raid_disks = raid_disks;
+
+ spin_lock_irq(&conf->resync_lock);
+ conf->barrier--;
+ spin_unlock_irq(&conf->resync_lock);
+ wake_up(&conf->wait_resume);
+ wake_up(&conf->wait_idle);
+
+
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+
+ mempool_destroy(oldpool);
+ return 0;
+}
+
+
static mdk_personality_t raid1_personality =
{
.name = "raid1",
@@ -1269,6 +1390,8 @@ static mdk_personality_t raid1_personality =
.hot_remove_disk= raid1_remove_disk,
.spare_active = raid1_spare_active,
.sync_request = sync_request,
+ .resize = raid1_resize,
+ .reshape = raid1_reshape,
};
static int __init raid_init(void)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 402edd5e3eb8..773f9bfe78fa 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -395,7 +395,7 @@ static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
md_error(conf->mddev, conf->disks[i].rdev);
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
}
- atomic_dec(&conf->disks[i].rdev->nr_pending);
+ rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
#if 0
/* must restore b_page before unlocking buffer... */
if (sh->bh_page[i] != bh->b_page) {
@@ -438,7 +438,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
if (!uptodate)
md_error(conf->mddev, conf->disks[i].rdev);
- atomic_dec(&conf->disks[i].rdev->nr_pending);
+ rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
@@ -1037,7 +1037,7 @@ static void handle_stripe(struct stripe_head *sh)
* parity, or to satisfy requests
* or to load a block that is being partially written.
*/
- if (to_read || non_overwrite || (syncing && (uptodate+failed < disks))) {
+ if (to_read || non_overwrite || (syncing && (uptodate < disks))) {
for (i=disks; i--;) {
dev = &sh->dev[i];
if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
@@ -1577,6 +1577,9 @@ static int run (mddev_t *mddev)
conf->algorithm = mddev->layout;
conf->max_nr_stripes = NR_STRIPES;
+ /* device size must be a multiple of chunk size */
+ mddev->size &= ~(mddev->chunk_size/1024 -1);
+
if (!conf->chunk_size || conf->chunk_size % 4) {
printk(KERN_ERR "raid5: invalid chunk size %d for %s\n",
conf->chunk_size, mdname(mddev));
@@ -1828,6 +1831,27 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
return found;
}
+static int raid5_resize(mddev_t *mddev, sector_t sectors)
+{
+ /* no resync is happening, and there is enough space
+ * on all devices, so we can resize.
+ * We need to make sure resync covers any new space.
+ * If the array is shrinking we should possibly wait until
+ * any io in the removed space completes, but it hardly seems
+ * worth it.
+ */
+ sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
+ mddev->array_size = (sectors * (mddev->raid_disks-1))>>1;
+ set_capacity(mddev->gendisk, mddev->array_size << 1);
+ mddev->changed = 1;
+ if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
+ mddev->recovery_cp = mddev->size << 1;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ }
+ mddev->size = sectors /2;
+ return 0;
+}
+
static mdk_personality_t raid5_personality=
{
.name = "raid5",
@@ -1841,6 +1865,7 @@ static mdk_personality_t raid5_personality=
.hot_remove_disk= raid5_remove_disk,
.spare_active = raid5_spare_active,
.sync_request = sync_request,
+ .resize = raid5_resize,
};
static int __init raid5_init (void)
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index ceaec272efab..06071c35cce5 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -414,7 +414,7 @@ static int raid6_end_read_request (struct bio * bi, unsigned int bytes_done,
md_error(conf->mddev, conf->disks[i].rdev);
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
}
- atomic_dec(&conf->disks[i].rdev->nr_pending);
+ rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
#if 0
/* must restore b_page before unlocking buffer... */
if (sh->bh_page[i] != bh->b_page) {
@@ -457,7 +457,7 @@ static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done,
if (!uptodate)
md_error(conf->mddev, conf->disks[i].rdev);
- atomic_dec(&conf->disks[i].rdev->nr_pending);
+ rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
@@ -1741,6 +1741,9 @@ static int run (mddev_t *mddev)
conf->algorithm = mddev->layout;
conf->max_nr_stripes = NR_STRIPES;
+ /* device size must be a multiple of chunk size */
+ mddev->size &= ~(mddev->chunk_size/1024 -1);
+
if (conf->raid_disks < 4) {
printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
mdname(mddev), conf->raid_disks);
@@ -1997,6 +2000,27 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
return found;
}
+static int raid6_resize(mddev_t *mddev, sector_t sectors)
+{
+ /* no resync is happening, and there is enough space
+ * on all devices, so we can resize.
+ * We need to make sure resync covers any new space.
+ * If the array is shrinking we should possibly wait until
+ * any io in the removed space completes, but it hardly seems
+ * worth it.
+ */
+ sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
+ mddev->array_size = (sectors * (mddev->raid_disks-2))>>1;
+ set_capacity(mddev->gendisk, mddev->array_size << 1);
+ mddev->changed = 1;
+ if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
+ mddev->recovery_cp = mddev->size << 1;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ }
+ mddev->size = sectors /2;
+ return 0;
+}
+
static mdk_personality_t raid6_personality=
{
.name = "raid6",
@@ -2010,6 +2034,7 @@ static mdk_personality_t raid6_personality=
.hot_remove_disk= raid6_remove_disk,
.spare_active = raid6_spare_active,
.sync_request = sync_request,
+ .resize = raid6_resize,
};
static int __init raid6_init (void)
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index ce539ba17a27..159ccc0b6eaa 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -108,6 +108,9 @@
#define M29W160DT 0x22C4
#define M29W160DB 0x2249
#define M29W040B 0x00E3
+#define M50FW040 0x002C
+#define M50FW080 0x002D
+#define M50FW016 0x002E
/* SST */
#define SST29EE512 0x005d
@@ -1233,6 +1236,45 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x10000,8),
}
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M50FW040,
+ .name = "ST M50FW040",
+ .uaddr = {
+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_INTEL_EXT,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,8),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M50FW080,
+ .name = "ST M50FW080",
+ .uaddr = {
+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_INTEL_EXT,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,16),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M50FW016,
+ .name = "ST M50FW016",
+ .uaddr = {
+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
+ },
+ .DevSize = SIZE_2MiB,
+ .CmdSet = P_ID_INTEL_EXT,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,32),
+ }
}, {
.mfr_id = MANUFACTURER_TOSHIBA,
.dev_id = TC58FVT160,
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7e93bfccbbc4..d5d487e79b79 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -797,7 +797,7 @@ out:
/*====================================================================*/
-static ssize_t ds_read(struct file *file, char *buf,
+static ssize_t ds_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct pcmcia_bus_socket *s;
@@ -819,14 +819,14 @@ static ssize_t ds_read(struct file *file, char *buf,
ret = wait_event_interruptible(s->queue, !queue_empty(user));
if (ret == 0)
- ret = put_user(get_queued_event(user), (int *)buf) ? -EFAULT : 4;
+ ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
return ret;
} /* ds_read */
/*====================================================================*/
-static ssize_t ds_write(struct file *file, const char *buf,
+static ssize_t ds_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct pcmcia_bus_socket *s;
@@ -849,7 +849,7 @@ static ssize_t ds_write(struct file *file, const char *buf,
if (s->req_pending) {
s->req_pending--;
- get_user(s->req_result, (int *)buf);
+ get_user(s->req_result, (int __user *)buf);
if ((s->req_result != 0) || (s->req_pending == 0))
wake_up_interruptible(&s->request);
} else
@@ -888,6 +888,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
u_int cmd, u_long arg)
{
struct pcmcia_bus_socket *s;
+ void __user *uarg = (char __user *)arg;
u_int size;
int ret, err;
ds_ioctl_arg_t buf;
@@ -911,14 +912,14 @@ static int ds_ioctl(struct inode * inode, struct file * file,
return -EPERM;
if (cmd & IOC_IN) {
- err = verify_area(VERIFY_READ, (char *)arg, size);
+ err = verify_area(VERIFY_READ, uarg, size);
if (err) {
ds_dbg(3, "ds_ioctl(): verify_read = %d\n", err);
return err;
}
}
if (cmd & IOC_OUT) {
- err = verify_area(VERIFY_WRITE, (char *)arg, size);
+ err = verify_area(VERIFY_WRITE, uarg, size);
if (err) {
ds_dbg(3, "ds_ioctl(): verify_write = %d\n", err);
return err;
@@ -927,7 +928,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
err = ret = 0;
- if (cmd & IOC_IN) __copy_from_user((char *)&buf, (char *)arg, size);
+ if (cmd & IOC_IN) __copy_from_user((char *)&buf, uarg, size);
switch (cmd) {
case DS_ADJUST_RESOURCE_INFO:
@@ -1042,7 +1043,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
}
}
- if (cmd & IOC_OUT) __copy_to_user((char *)arg, (char *)&buf, size);
+ if (cmd & IOC_OUT) __copy_to_user(uarg, (char *)&buf, size);
return err;
} /* ds_ioctl */
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 1dc6e9555c21..1df67bcbcdb5 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -1620,14 +1620,27 @@ static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
struct riva_par *par = (struct riva_par *) info->par;
struct device_node *dp;
unsigned char *pedid = NULL;
+ unsigned char *disptype = NULL;
+ static char *propnames[] = {
+ "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL };
+ int i;
dp = pci_device_to_OF_node(pd);
- pedid = (unsigned char *)get_property(dp, "EDID,B", 0);
-
- if (pedid) {
+ for (; dp != NULL; dp = dp->child) {
+ disptype = (unsigned char *)get_property(dp, "display-type", NULL);
+ if (disptype == NULL)
+ continue;
+ if (strncmp(disptype, "LCD", 3) != 0)
+ continue;
+ for (i = 0; propnames[i] != NULL; ++i) {
+ pedid = (unsigned char *)
+ get_property(dp, propnames[i], NULL);
+ if (pedid != NULL) {
par->EDID = pedid;
return 1;
- } else
+ }
+ }
+ }
return 0;
}
#endif /* CONFIG_PPC_OF */
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 4e8dae3ca585..d2ad34e13907 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -2262,11 +2262,15 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
/*
* ok, that's it
*/
- retval = ext3_delete_entry(handle, old_dir, old_de, old_bh);
- if (retval == -ENOENT) {
- /*
- * old_de could have moved out from under us.
- */
+ if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
+ old_de->name_len != old_dentry->d_name.len ||
+ strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
+ (retval = ext3_delete_entry(handle, old_dir,
+ old_de, old_bh)) == -ENOENT) {
+ /* old_de could have moved from under us during htree split, so
+ * make sure that we are deleting the right entry. We might
+ * also be pointing to a stale entry in the unused part of
+ * old_bh so just checking inum and the name isn't enough. */
struct buffer_head *old_bh2;
struct ext3_dir_entry_2 *old_de2;
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index e4e228ea968a..77f051eef086 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -475,7 +475,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
struct iovec iov = {
- .iov_base = buf,
+ .iov_base = (char *)buf,
.iov_len = count,
};
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 1541cbb5544b..941ceaec1a1d 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -436,7 +436,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
resp->buflen = count;
resp->common.err = nfs_ok;
resp->buffer = argp->buffer;
- resp->offset = NULL;
resp->rqstp = rqstp;
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
&resp->common, nfs3svc_encode_entry);
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 1e3af06b7a8e..f5df8304ff65 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -847,8 +847,18 @@ encode_entry(struct readdir_cd *ccd, const char *name,
int elen; /* estimated entry length in words */
int num_entry_words = 0; /* actual number of words */
- if (cd->offset)
- xdr_encode_hyper(cd->offset, (u64) offset);
+ if (cd->offset) {
+ u64 offset64 = offset;
+
+ if (unlikely(cd->offset1)) {
+ /* we ended up with offset on a page boundary */
+ *cd->offset = htonl(offset64 >> 32);
+ *cd->offset1 = htonl(offset64 & 0xffffffff);
+ cd->offset1 = NULL;
+ } else {
+ xdr_encode_hyper(cd->offset, (u64) offset);
+ }
+ }
/*
dprintk("encode_entry(%.*s @%ld%s)\n",
@@ -929,17 +939,32 @@ encode_entry(struct readdir_cd *ccd, const char *name,
/* update offset */
cd->offset = cd->buffer + (cd->offset - tmp);
} else {
+ unsigned int offset_r = (cd->offset - tmp) << 2;
+
+ /* update pointer to offset location.
+ * This is a 64bit quantity, so we need to
+ * deal with 3 cases:
+ * - entirely in first page
+ * - entirely in second page
+ * - 4 bytes in each page
+ */
+ if (offset_r + 8 <= len1) {
+ cd->offset = p + (cd->offset - tmp);
+ } else if (offset_r >= len1) {
+ cd->offset -= len1 >> 2;
+ } else {
+ /* sitting on the fence */
+ BUG_ON(offset_r != len1 - 4);
+ cd->offset = p + (cd->offset - tmp);
+ cd->offset1 = tmp;
+ }
+
len2 = (num_entry_words << 2) - len1;
/* move from temp page to current and next pages */
memmove(p, tmp, len1);
memmove(tmp, (caddr_t)tmp+len1, len2);
- /* update offset */
- if (((cd->offset - tmp) << 2) < len1)
- cd->offset = p + (cd->offset - tmp);
- else
- cd->offset -= len1 >> 2;
p = tmp + (len2 >> 2);
}
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index d8765a09327f..d54c85adef89 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -389,7 +389,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
break;
default:
- BUG();
+ status = nfserr_badtype;
}
if (!status) {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 73a8944ad96e..848c4851d43d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -495,15 +495,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
gen_clid(new);
gen_confirm(new);
add_to_unconfirmed(new, strhashval);
- } else if (!cmp_clid(&conf->cl_clientid, &unconf->cl_clientid) &&
- !cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
+ } else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
/*
* CASE3:
* confirmed found (name, principal match)
* confirmed verifier does not match input clverifier
*
* unconfirmed found (name match)
- * confirmed->cl_clientid != unconfirmed->cl_clientid and
* confirmed->cl_confirm != unconfirmed->cl_confirm
*
* remove unconfirmed.
@@ -2334,28 +2332,27 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
/* find the lockowner */
status = nfs_ok;
- for (i=0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_entry(local, &lock_ownerstr_hashtbl[i], so_strhash) {
- if(cmp_owner_str(local, owner, clid))
- break;
- }
- }
- if (local) {
- struct nfs4_stateid *stp;
-
- /* check for any locks held by any stateid associated with the
- * (lock) stateowner */
- status = nfserr_locks_held;
- list_for_each_entry(stp, &local->so_perfilestate, st_perfilestate) {
- if(stp->st_vfs_set) {
- if (check_for_locks(&stp->st_vfs_file, local))
- goto out;
+ for (i=0; i < LOCK_HASH_SIZE; i++)
+ list_for_each_entry(local, &lock_ownerstr_hashtbl[i], so_strhash)
+ if(cmp_owner_str(local, owner, clid)) {
+ struct nfs4_stateid *stp;
+
+ /* check for any locks held by any stateid
+ * associated with the (lock) stateowner */
+ status = nfserr_locks_held;
+ list_for_each_entry(stp, &local->so_perfilestate,
+ st_perfilestate) {
+ if(stp->st_vfs_set) {
+ if (check_for_locks(&stp->st_vfs_file,
+ local))
+ goto out;
+ }
+ }
+ /* no locks held by (lock) stateowner */
+ status = nfs_ok;
+ release_stateowner(local);
+ goto out;
}
- }
- /* no locks held by (lock) stateowner */
- status = nfs_ok;
- release_stateowner(local);
- }
out:
nfs4_unlock_state();
return status;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index bb0c72fc7ff6..2fc81bcbb720 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -538,9 +538,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
case NF4SOCK:
case NF4FIFO:
case NF4DIR:
- break;
default:
- goto xdr_error;
+ break;
}
READ_BUF(4);
@@ -1289,6 +1288,49 @@ static u32 nfs4_ftypes[16] = {
NF4SOCK, NF4BAD, NF4LNK, NF4BAD,
};
+static inline int
+xdr_padding(int l)
+{
+ return 3 - ((l - 1) & 3); /* smallest i>=0 such that (l+i)%4 = 0 */
+}
+
+static int
+nfsd4_encode_name(struct svc_rqst *rqstp, int group, uid_t id,
+ u32 **p, int *buflen)
+{
+ int status;
+ u32 len;
+
+ if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
+ return nfserr_resource;
+ if (group)
+ status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));
+ else
+ status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));
+ if (status < 0)
+ return nfserrno(status);
+ len = (unsigned)status;
+ *(*p)++ = htonl(len);
+ memset((u8 *)*p + len, 0, xdr_padding(len));
+ *p += XDR_QUADLEN(len);
+ *buflen -= (XDR_QUADLEN(len) << 2) + 4;
+ BUG_ON(*buflen < 0);
+ return 0;
+}
+
+static inline int
+nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen)
+{
+ return nfsd4_encode_name(rqstp, uid, 0, p, buflen);
+}
+
+static inline int
+nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen)
+{
+ return nfsd4_encode_name(rqstp, gid, 1, p, buflen);
+}
+
+
/*
* Note: @fhp can be NULL; in this case, we might have to compose the filehandle
* ourselves.
@@ -1304,10 +1346,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
u32 bmval0 = bmval[0];
u32 bmval1 = bmval[1];
struct kstat stat;
- char owner[IDMAP_NAMESZ];
- u32 ownerlen = 0;
- char group[IDMAP_NAMESZ];
- u32 grouplen = 0;
struct svc_fh tempfh;
struct kstatfs statfs;
int buflen = *countp << 2;
@@ -1338,23 +1376,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
goto out;
fhp = &tempfh;
}
- if (bmval1 & FATTR4_WORD1_OWNER) {
- int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner);
- if (temp < 0) {
- status = temp;
- goto out_nfserr;
- }
- ownerlen = (unsigned) temp;
- }
- if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
- int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group);
- if (temp < 0) {
- status = temp;
- goto out_nfserr;
- }
- grouplen = (unsigned) temp;
- }
-
if ((buflen -= 16) < 0)
goto out_resource;
@@ -1536,18 +1557,18 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
WRITE32(stat.nlink);
}
if (bmval1 & FATTR4_WORD1_OWNER) {
- buflen -= (XDR_QUADLEN(ownerlen) << 2) + 4;
- if (buflen < 0)
+ status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
+ if (status == nfserr_resource)
goto out_resource;
- WRITE32(ownerlen);
- WRITEMEM(owner, ownerlen);
+ if (status)
+ goto out;
}
if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
- buflen -= (XDR_QUADLEN(grouplen) << 2) + 4;
- if (buflen < 0)
+ status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
+ if (status == nfserr_resource)
goto out_resource;
- WRITE32(grouplen);
- WRITEMEM(group, grouplen);
+ if (status)
+ goto out;
}
if (bmval1 & FATTR4_WORD1_RAWDEV) {
if ((buflen -= 8) < 0)
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index aaa367feb2d9..8e8c2342b184 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -56,7 +56,7 @@ int nfsd_acceptable(void *expv, struct dentry *dentry)
/* make sure parents give x permission to user */
int err;
parent = dget_parent(tdentry);
- err = permission(parent->d_inode, S_IXOTH, NULL);
+ err = permission(parent->d_inode, MAY_EXEC, NULL);
if (err < 0) {
dput(parent);
break;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 47c98d0224ef..72cd7076cc50 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -89,6 +89,7 @@ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
return -ENOMEM;
count = ops->show(kobj,attr,buffer->page);
+ BUG_ON(count > PAGE_SIZE);
if (count >= 0)
buffer->count = count;
else
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index c561da379b2b..14ac954a1c52 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -312,6 +312,13 @@ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG);
flush_pmd_entry(pmdp); \
} while (0)
+#define copy_pmd(pmdpd,pmdps) \
+ do { \
+ pmdpd[0] = pmdps[0]; \
+ pmdpd[1] = pmdps[1]; \
+ flush_pmd_entry(pmdpd); \
+ } while (0)
+
#define pmd_clear(pmdp) \
do { \
pmdp[0] = __pmd(0); \
diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
index e8923e80c49c..d91ba524d8fd 100644
--- a/include/asm-ppc/spinlock.h
+++ b/include/asm-ppc/spinlock.h
@@ -140,7 +140,7 @@ static __inline__ int _raw_write_trylock(rwlock_t *rw)
unsigned int tmp;
__asm__ __volatile__(
-"2: lwarx %0,0,%1\n\ # write_trylock\n\
+"2: lwarx %0,0,%1 # write_trylock\n\
cmpwi 0,%0,0\n\
bne- 1f\n"
PPC405_ERR77(0,%1)
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index 9bb2b94ee2ca..b4543649b44e 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -118,7 +118,6 @@ static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned
d.base1 = PTR_MIDDLE(tss) & 0xFF;
d.type = type;
d.p = 1;
- d.g = 1;
d.limit1 = (size >> 16) & 0xF;
d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF;
d.base3 = PTR_HIGH(tss);
@@ -135,7 +134,7 @@ static inline void set_tss_desc(unsigned cpu, void *addr)
static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
{
set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (unsigned long)addr,
- DESC_LDT, size);
+ DESC_LDT, size * 8);
}
static inline void set_seg_base(unsigned cpu, int entry, void *base)
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 381661952334..c5c2b01cfcfa 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -84,7 +84,7 @@ extern unsigned long vm_force_exec32;
#define __VIRTUAL_MASK_SHIFT 48
#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
-#define KERNEL_TEXT_SIZE (10UL*1024*1024)
+#define KERNEL_TEXT_SIZE (40UL*1024*1024)
#define KERNEL_TEXT_START 0xffffffff80000000UL
#ifndef __ASSEMBLY__
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index b1a6f23b517a..6bad4766d3d9 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -124,8 +124,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
int err;
exp_get(exp);
expkey_put(&ek->h, &svc_expkey_cache);
- if (exp &&
- (err = cache_check(&svc_export_cache, &exp->h, reqp)))
+ if ((err = cache_check(&svc_export_cache, &exp->h, reqp)))
exp = ERR_PTR(err);
return exp;
} else
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 2997e2306a15..e1818525627b 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -281,7 +281,7 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh)
| FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \
| FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
| FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \
- | FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
+ | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
| FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index 1240afe79da9..13afff34607f 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -170,6 +170,7 @@ struct nfsd3_readdirres {
u32 * buffer;
int buflen;
u32 * offset;
+ u32 * offset1;
struct svc_rqst * rqstp;
};
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index 0b6b5e6f34eb..faa400cf25e4 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -255,6 +255,14 @@ struct mddev_s
struct list_head all_mddevs;
};
+
+static inline void rdev_dec_pending(mdk_rdev_t *rdev, mddev_t *mddev)
+{
+ int faulty = rdev->faulty;
+ if (atomic_dec_and_test(&rdev->nr_pending) && faulty)
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+}
+
struct mdk_personality_s
{
char *name;
@@ -271,6 +279,8 @@ struct mdk_personality_s
int (*hot_remove_disk) (mddev_t *mddev, int number);
int (*spare_active) (mddev_t *mddev);
int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
+ int (*resize) (mddev_t *mddev, sector_t sectors);
+ int (*reshape) (mddev_t *mddev, int raid_disks);
};
diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
index 96abcad3a307..50965d9680b6 100644
--- a/include/linux/raid/raid1.h
+++ b/include/linux/raid/raid1.h
@@ -10,6 +10,20 @@ struct mirror_info {
sector_t head_position;
};
+/*
+ * memory pools need a pointer to the mddev, so they can force an unplug
+ * when memory is tight, and a count of the number of drives that the
+ * pool was allocated for, so they know how much to allocate and free.
+ * mddev->raid_disks cannot be used, as it can change while a pool is active
+ * These two datums are stored in a kmalloced struct.
+ */
+
+struct pool_info {
+ mddev_t *mddev;
+ int raid_disks;
+};
+
+
typedef struct r1bio_s r1bio_t;
struct r1_private_data_s {
@@ -31,6 +45,8 @@ struct r1_private_data_s {
wait_queue_head_t wait_idle;
wait_queue_head_t wait_resume;
+ struct pool_info *poolinfo;
+
mempool_t *r1bio_pool;
mempool_t *r1buf_pool;
};
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 36bcc5ed72d0..30689cc5734f 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -87,6 +87,7 @@ struct auth_domain {
*/
struct auth_ops {
char * name;
+ struct module *owner;
int flavour;
int (*accept)(struct svc_rqst *rq, u32 *authp);
int (*release)(struct svc_rqst *rq);
diff --git a/kernel/sched.c b/kernel/sched.c
index 019e0db3e0bf..e632c92fd80f 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -763,7 +763,8 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
this_load = target_load(this_cpu);
/* Don't pull the task off an idle CPU to a busy one */
- if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2)
+ if (load < SCHED_LOAD_SCALE && load + this_load > SCHED_LOAD_SCALE
+ && this_load > load)
goto out_set_cpu;
new_cpu = this_cpu; /* Wake to this CPU if we can */
@@ -1625,8 +1626,7 @@ nextgroup:
return busiest;
out_balanced:
- if (busiest && (idle == NEWLY_IDLE ||
- (idle == IDLE && max_load > SCHED_LOAD_SCALE)) ) {
+ if (busiest && idle != NOT_IDLE && max_load > SCHED_LOAD_SCALE) {
*imbalance = 1;
return busiest;
}
diff --git a/mm/memory.c b/mm/memory.c
index 578070758905..3df1f05e76b8 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -637,15 +637,11 @@ follow_page(struct mm_struct *mm, unsigned long address, int write)
if (pte_present(pte)) {
if (write && !pte_write(pte))
goto out;
- if (write && !pte_dirty(pte)) {
- struct page *page = pte_page(pte);
- if (!PageDirty(page))
- set_page_dirty(page);
- }
pfn = pte_pfn(pte);
if (pfn_valid(pfn)) {
- struct page *page = pfn_to_page(pfn);
-
+ page = pfn_to_page(pfn);
+ if (write && !pte_dirty(pte) && !PageDirty(page))
+ set_page_dirty(page);
mark_page_accessed(page);
return page;
}
diff --git a/mm/mmap.c b/mm/mmap.c
index a930fd4f56a5..d6fd2fe13319 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -293,10 +293,8 @@ __vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct rb_node **rb_link,
struct rb_node *rb_parent)
{
- vma_prio_tree_init(vma);
__vma_link_list(mm, vma, prev, rb_parent);
__vma_link_rb(mm, vma, rb_link, rb_parent);
- __vma_link_file(vma);
__anon_vma_link(vma);
}
@@ -312,7 +310,10 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
if (mapping)
spin_lock(&mapping->i_mmap_lock);
anon_vma_lock(vma);
+
__vma_link(mm, vma, prev, rb_link, rb_parent);
+ __vma_link_file(vma);
+
anon_vma_unlock(vma);
if (mapping)
spin_unlock(&mapping->i_mmap_lock);
@@ -323,9 +324,9 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
}
/*
- * Insert vm structure into process list sorted by address and into the
- * inode's i_mmap tree. The caller should hold mm->mmap_sem and
- * ->f_mappping->i_mmap_lock if vm_file is non-NULL.
+ * Helper for vma_adjust in the split_vma insert case:
+ * insert vm structure into list and rbtree and anon_vma,
+ * but it has already been inserted into prio_tree earlier.
*/
static void
__insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
@@ -337,9 +338,7 @@ __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
if (__vma && __vma->vm_start < vma->vm_end)
BUG();
__vma_link(mm, vma, prev, rb_link, rb_parent);
- mark_mm_hugetlb(mm, vma);
mm->map_count++;
- validate_mm(mm);
}
static inline void
@@ -373,20 +372,27 @@ void vma_adjust(struct vm_area_struct *vma, unsigned long start,
if (next && !insert) {
if (end >= next->vm_end) {
+ /*
+ * vma expands, overlapping all the next, and
+ * perhaps the one after too (mprotect case 6).
+ */
again: remove_next = 1 + (end > next->vm_end);
end = next->vm_end;
anon_vma = next->anon_vma;
- } else if (end < vma->vm_end || end > next->vm_start) {
+ } else if (end > next->vm_start) {
/*
- * vma shrinks, and !insert tells it's not
- * split_vma inserting another: so it must
- * be mprotect shifting the boundary down.
- * Or:
* vma expands, overlapping part of the next:
- * must be mprotect shifting the boundary up.
+ * mprotect case 5 shifting the boundary up.
+ */
+ adjust_next = (end - next->vm_start) >> PAGE_SHIFT;
+ anon_vma = next->anon_vma;
+ } else if (end < vma->vm_end) {
+ /*
+ * vma shrinks, and !insert tells it's not
+ * split_vma inserting another: so it must be
+ * mprotect case 4 shifting the boundary down.
*/
- BUG_ON(vma->vm_end != next->vm_start);
- adjust_next = end - next->vm_start;
+ adjust_next = - ((vma->vm_end - end) >> PAGE_SHIFT);
anon_vma = next->anon_vma;
}
}
@@ -396,6 +402,15 @@ again: remove_next = 1 + (end > next->vm_end);
if (!(vma->vm_flags & VM_NONLINEAR))
root = &mapping->i_mmap;
spin_lock(&mapping->i_mmap_lock);
+ if (insert) {
+ /*
+ * Put into prio_tree now, so instantiated pages
+ * are visible to arm/parisc __flush_dcache_page
+ * throughout; but we cannot insert into address
+ * space until vma start or end is updated.
+ */
+ __vma_link_file(insert);
+ }
}
/*
@@ -418,8 +433,8 @@ again: remove_next = 1 + (end > next->vm_end);
vma->vm_end = end;
vma->vm_pgoff = pgoff;
if (adjust_next) {
- next->vm_start += adjust_next;
- next->vm_pgoff += adjust_next >> PAGE_SHIFT;
+ next->vm_start += adjust_next << PAGE_SHIFT;
+ next->vm_pgoff += adjust_next;
}
if (root) {
@@ -1456,6 +1471,7 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
/* most fields are the same, copy all, and then fixup */
*new = *vma;
+ vma_prio_tree_init(new);
if (new_below)
new->vm_end = addr;
@@ -1768,6 +1784,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (new_vma) {
*new_vma = *vma;
+ vma_prio_tree_init(new_vma);
pol = mpol_copy(vma_policy(vma));
if (IS_ERR(pol)) {
kmem_cache_free(vm_area_cachep, new_vma);
diff --git a/mm/rmap.c b/mm/rmap.c
index 871e76b9c25e..1f3c84f8c393 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -193,7 +193,7 @@ vma_address(struct page *page, struct vm_area_struct *vma)
* repeatedly from either page_referenced_anon or page_referenced_file.
*/
static int page_referenced_one(struct page *page,
- struct vm_area_struct *vma, unsigned int *mapcount, int *failed)
+ struct vm_area_struct *vma, unsigned int *mapcount)
{
struct mm_struct *mm = vma->vm_mm;
unsigned long address;
@@ -208,14 +208,8 @@ static int page_referenced_one(struct page *page,
if (address == -EFAULT)
goto out;
- if (!spin_trylock(&mm->page_table_lock)) {
- /*
- * For debug we're currently warning if not all found,
- * but in this case that's expected: suppress warning.
- */
- (*failed)++;
+ if (!spin_trylock(&mm->page_table_lock))
goto out;
- }
pgd = pgd_offset(mm, address);
if (!pgd_present(*pgd))
@@ -251,18 +245,14 @@ static inline int page_referenced_anon(struct page *page)
struct anon_vma *anon_vma = (struct anon_vma *) page->mapping;
struct vm_area_struct *vma;
int referenced = 0;
- int failed = 0;
spin_lock(&anon_vma->lock);
BUG_ON(list_empty(&anon_vma->head));
list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
- referenced += page_referenced_one(page, vma,
- &mapcount, &failed);
+ referenced += page_referenced_one(page, vma, &mapcount);
if (!mapcount)
- goto out;
+ break;
}
- WARN_ON(!failed);
-out:
spin_unlock(&anon_vma->lock);
return referenced;
}
@@ -289,7 +279,6 @@ static inline int page_referenced_file(struct page *page)
struct vm_area_struct *vma = NULL;
struct prio_tree_iter iter;
int referenced = 0;
- int failed = 0;
if (!spin_trylock(&mapping->i_mmap_lock))
return 0;
@@ -299,17 +288,13 @@ static inline int page_referenced_file(struct page *page)
if ((vma->vm_flags & (VM_LOCKED|VM_MAYSHARE))
== (VM_LOCKED|VM_MAYSHARE)) {
referenced++;
- goto out;
+ break;
}
- referenced += page_referenced_one(page, vma,
- &mapcount, &failed);
+ referenced += page_referenced_one(page, vma, &mapcount);
if (!mapcount)
- goto out;
+ break;
}
- if (list_empty(&mapping->i_mmap_nonlinear))
- WARN_ON(!failed);
-out:
spin_unlock(&mapping->i_mmap_lock);
return referenced;
}
@@ -485,6 +470,23 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
goto out_unmap;
}
+ /*
+ * Don't pull an anonymous page out from under get_user_pages.
+ * GUP carefully breaks COW and raises page count (while holding
+ * page_table_lock, as we have here) to make sure that the page
+ * cannot be freed. If we unmap that page here, a user write
+ * access to the virtual address will bring back the page, but
+ * its raised count will (ironically) be taken to mean it's not
+ * an exclusive swap page, do_wp_page will replace it by a copy
+ * page, and the user never get to see the data GUP was holding
+ * the original page for.
+ */
+ if (PageSwapCache(page) &&
+ page_count(page) != page->mapcount + 2) {
+ ret = SWAP_FAIL;
+ goto out_unmap;
+ }
+
/* Nuke the page table entry. */
flush_cache_page(vma, address);
pteval = ptep_clear_flush(vma, address, pte);
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 13832c945fb1..5717135766d9 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -19,7 +19,8 @@
/*
* swapper_space is a fiction, retained to simplify the path through
- * vmscan's shrink_list. Only those fields initialized below are used.
+ * vmscan's shrink_list, to make sync_page look nicer, and to allow
+ * future use of radix_tree tags in the swap cache.
*/
static struct address_space_operations swap_aops = {
.writepage = swap_writepage,
@@ -36,6 +37,7 @@ struct address_space swapper_space = {
.page_tree = RADIX_TREE_INIT(GFP_ATOMIC),
.tree_lock = SPIN_LOCK_UNLOCKED,
.a_ops = &swap_aops,
+ .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear),
.backing_dev_info = &swap_backing_dev_info,
};
EXPORT_SYMBOL(swapper_space);
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 03bd7bd8c7d8..55b2fd104893 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -333,6 +333,7 @@ rsc_init(struct rsc *new, struct rsc *tmp)
new->handle.data = tmp->handle.data;
tmp->handle.data = NULL;
new->mechctx = NULL;
+ new->cred.cr_group_info = NULL;
}
static inline void
@@ -453,8 +454,11 @@ gss_svc_searchbyctx(struct xdr_netobj *handle)
struct rsc rsci;
struct rsc *found;
- rsci.handle = *handle;
+ memset(&rsci, 0, sizeof(rsci));
+ if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
+ return NULL;
found = rsc_lookup(&rsci, 0);
+ rsc_free(&rsci);
if (!found)
return NULL;
if (cache_check(&rsc_cache, &found->h, NULL))
@@ -1045,6 +1049,7 @@ svcauth_gss_domain_release(struct auth_domain *dom)
struct auth_ops svcauthops_gss = {
.name = "rpcsec_gss",
+ .owner = THIS_MODULE,
.flavour = RPC_AUTH_GSS,
.accept = svcauth_gss_accept,
.release = svcauth_gss_release,
@@ -1054,10 +1059,12 @@ struct auth_ops svcauthops_gss = {
int
gss_svc_init(void)
{
- cache_register(&rsc_cache);
- cache_register(&rsi_cache);
- svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
- return 0;
+ int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
+ if (rv == 0) {
+ cache_register(&rsc_cache);
+ cache_register(&rsi_cache);
+ }
+ return rv;
}
void
@@ -1065,4 +1072,5 @@ gss_svc_shutdown(void)
{
cache_unregister(&rsc_cache);
cache_unregister(&rsi_cache);
+ svc_auth_unregister(RPC_AUTH_GSS);
}
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index db78e727d1eb..54ea89629628 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/module.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svcsock.h>
@@ -27,6 +28,7 @@
extern struct auth_ops svcauth_null;
extern struct auth_ops svcauth_unix;
+static spinlock_t authtab_lock = SPIN_LOCK_UNLOCKED;
static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = {
[0] = &svcauth_null,
[1] = &svcauth_unix,
@@ -43,10 +45,15 @@ svc_authenticate(struct svc_rqst *rqstp, u32 *authp)
flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0]));
dprintk("svc: svc_authenticate (%d)\n", flavor);
- if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])) {
+
+ spin_lock(&authtab_lock);
+ if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])
+ || !try_module_get(aops->owner)) {
+ spin_unlock(&authtab_lock);
*authp = rpc_autherr_badcred;
return SVC_DENIED;
}
+ spin_unlock(&authtab_lock);
rqstp->rq_authop = aops;
return aops->accept(rqstp, authp);
@@ -63,28 +70,35 @@ int svc_authorise(struct svc_rqst *rqstp)
rqstp->rq_authop = NULL;
- if (aops)
+ if (aops) {
rv = aops->release(rqstp);
-
- /* FIXME should I count and release authops */
+ module_put(aops->owner);
+ }
return rv;
}
int
svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
{
- if (flavor >= RPC_AUTH_MAXFLAVOR || authtab[flavor])
- return -EINVAL;
- authtab[flavor] = aops;
- return 0;
+ int rv = -EINVAL;
+ spin_lock(&authtab_lock);
+ if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
+ authtab[flavor] = aops;
+ rv = 0;
+ }
+ spin_unlock(&authtab_lock);
+ return rv;
}
void
svc_auth_unregister(rpc_authflavor_t flavor)
{
+ spin_lock(&authtab_lock);
if (flavor < RPC_AUTH_MAXFLAVOR)
authtab[flavor] = NULL;
+ spin_unlock(&authtab_lock);
}
+EXPORT_SYMBOL(svc_auth_unregister);
/**************************************************
* cache for domain name to auth_domain
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 082684ddf3bc..ab5164b6dab3 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -1,5 +1,6 @@
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/module.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svcsock.h>
@@ -411,6 +412,7 @@ svcauth_null_release(struct svc_rqst *rqstp)
struct auth_ops svcauth_null = {
.name = "null",
+ .owner = THIS_MODULE,
.flavour = RPC_AUTH_NULL,
.accept = svcauth_null_accept,
.release = svcauth_null_release,
@@ -515,6 +517,7 @@ svcauth_unix_release(struct svc_rqst *rqstp)
struct auth_ops svcauth_unix = {
.name = "unix",
+ .owner = THIS_MODULE,
.flavour = RPC_AUTH_UNIX,
.accept = svcauth_unix_accept,
.release = svcauth_unix_release,