Commit 77e0102e authored by Len Brown's avatar Len Brown

Merge intel.com:/home/lenb/bk/linux-2.6.8

into intel.com:/home/lenb/src/linux-acpi-test-2.6.8
parents ec3b0367 7588ab97
......@@ -19,18 +19,23 @@ fmask=### -- The permission mask for files.
codepage=### -- Sets the codepage number for converting to shortname
characters on FAT filesystem.
By default, FAT_DEFAULT_CODEPAGE setting is used.
NOTE: If this option was not specified, the file name
may not be read/written rightly, also filesystem is
mounted as read-only.
iocharset=name -- Character set to use for converting between the
encoding is used for user visible filename and 16 bit
Unicode characters. Long filenames are stored on disk
in Unicode format, but Unix for the most part doesn't
know how to deal with Unicode.
By default, FAT_DEFAULT_IOCHARSET setting is used.
There is also an option of doing UTF8 translations
with the utf8 option.
NOTE: If this option was not specified, the file name
may not be read/written rightly, also filesystem is
mounted as read-only.
NOTE: "iocharset=utf8" is not recommended. If unsure,
you should consider the following option instead.
......
......@@ -1177,6 +1177,8 @@ _GLOBAL(giveup_spe)
evmwumiaa evr6, evr6, evr6 /* evr6 <- ACC = 0 * 0 + ACC */
li r4,THREAD_ACC
evstddx evr6, r4, r3 /* save off accumulator */
mfspr r6,SPRN_SPEFSCR
stw r6,THREAD_SPEFSCR(r3) /* save spefscr register value */
beq 1f
lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5)
lis r3,MSR_SPE@h
......
......@@ -171,7 +171,12 @@ setup_irq(unsigned int irq, struct irqaction * new)
if (!shared) {
desc->depth = 0;
desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
unmask_irq(irq);
if (desc->handler) {
if (desc->handler->startup)
desc->handler->startup(irq);
else if (desc->handler->enable)
desc->handler->enable(irq);
}
}
spin_unlock_irqrestore(&desc->lock,flags);
......
......@@ -144,6 +144,22 @@ static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
/* When an irq gets requested for the first client, if it's an
* edge interrupt, we clear any previous one on the controller
*/
static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr)
{
unsigned long bit = 1UL << (irq_nr & 0x1f);
int i = irq_nr >> 5;
if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
out_le32(&pmac_irq_hw[i]->ack, bit);
set_bit(irq_nr, ppc_cached_irq_mask);
pmac_set_irq_mask(irq_nr, 0);
return 0;
}
static void __pmac pmac_mask_irq(unsigned int irq_nr)
{
clear_bit(irq_nr, ppc_cached_irq_mask);
......@@ -168,25 +184,21 @@ static void __pmac pmac_end_irq(unsigned int irq_nr)
struct hw_interrupt_type pmac_pic = {
" PMAC-PIC ",
NULL,
NULL,
pmac_unmask_irq,
pmac_mask_irq,
pmac_mask_and_ack_irq,
pmac_end_irq,
NULL
.typename = " PMAC-PIC ",
.startup = pmac_startup_irq,
.enable = pmac_unmask_irq,
.disable = pmac_mask_irq,
.ack = pmac_mask_and_ack_irq,
.end = pmac_end_irq,
};
struct hw_interrupt_type gatwick_pic = {
" GATWICK ",
NULL,
NULL,
pmac_unmask_irq,
pmac_mask_irq,
pmac_mask_and_ack_irq,
pmac_end_irq,
NULL
.typename = " GATWICK ",
.startup = pmac_startup_irq,
.enable = pmac_unmask_irq,
.disable = pmac_mask_irq,
.ack = pmac_mask_and_ack_irq,
.end = pmac_end_irq,
};
static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
......
......@@ -1823,50 +1823,43 @@ EXPORT_SYMBOL(blk_insert_request);
struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf,
unsigned int len)
{
struct request *rq = NULL;
char *buf = NULL;
unsigned long uaddr;
struct request *rq;
struct bio *bio;
int ret;
if (len > (q->max_sectors << 9))
return ERR_PTR(-EINVAL);
if ((!len && ubuf) || (len && !ubuf))
return ERR_PTR(-EINVAL);
rq = blk_get_request(q, rw, __GFP_WAIT);
if (!rq)
return ERR_PTR(-ENOMEM);
bio = bio_map_user(q, NULL, (unsigned long) ubuf, len, rw == READ);
if (!bio) {
int bytes = (len + 511) & ~511;
buf = kmalloc(bytes, q->bounce_gfp | GFP_USER);
if (!buf) {
ret = -ENOMEM;
goto fault;
}
if (rw == WRITE) {
if (copy_from_user(buf, ubuf, len)) {
ret = -EFAULT;
goto fault;
}
} else
memset(buf, 0, len);
}
/*
* if alignment requirement is satisfied, map in user pages for
* direct dma. else, set up kernel bounce buffers
*/
uaddr = (unsigned long) ubuf;
if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q)))
bio = bio_map_user(q, NULL, uaddr, len, rw == READ);
else
bio = bio_copy_user(q, uaddr, len, rw == READ);
if (!IS_ERR(bio)) {
rq->bio = rq->biotail = bio;
if (rq->bio)
blk_rq_bio_prep(q, rq, bio);
rq->buffer = rq->data = buf;
rq->buffer = rq->data = NULL;
rq->data_len = len;
return rq;
fault:
if (buf)
kfree(buf);
if (bio)
bio_unmap_user(bio, 1);
if (rq)
blk_put_request(rq);
}
return ERR_PTR(ret);
/*
* bio is the err-ptr
*/
blk_put_request(rq);
return (struct request *) bio;
}
EXPORT_SYMBOL(blk_rq_map_user);
......@@ -1880,18 +1873,15 @@ EXPORT_SYMBOL(blk_rq_map_user);
* Description:
* Unmap a request previously mapped by blk_rq_map_user().
*/
int blk_rq_unmap_user(struct request *rq, void __user *ubuf, struct bio *bio,
unsigned int ulen)
int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen)
{
const int read = rq_data_dir(rq) == READ;
int ret = 0;
if (bio)
bio_unmap_user(bio, read);
if (rq->buffer) {
if (read && copy_to_user(ubuf, rq->buffer, ulen))
ret = -EFAULT;
kfree(rq->buffer);
if (bio) {
if (bio_flagged(bio, BIO_USER_MAPPED))
bio_unmap_user(bio);
else
ret = bio_uncopy_user(bio);
}
blk_put_request(rq);
......
......@@ -211,7 +211,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk,
hdr->sb_len_wr = len;
}
if (blk_rq_unmap_user(rq, hdr->dxferp, bio, hdr->dxfer_len))
if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len))
return -EFAULT;
/* may not have succeeded, but output values written to control
......
......@@ -2015,7 +2015,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
cdi->last_sense = s->sense_key;
}
if (blk_rq_unmap_user(rq, ubuf, bio, len))
if (blk_rq_unmap_user(rq, bio, len))
ret = -EFAULT;
if (ret)
......
......@@ -1959,13 +1959,17 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
* sg request
*/
if (rq->bio) {
if (rq->data_len & 3) {
printk("%s: block pc not aligned, len=%d\n", drive->name, rq->data_len);
cdrom_end_request(drive, 0);
return ide_stopped;
}
info->dma = drive->using_dma;
int mask = drive->queue->dma_alignment;
unsigned long addr = (unsigned long) page_address(bio_page(rq->bio));
info->cmd = rq_data_dir(rq);
info->dma = drive->using_dma;
/*
* check if dma is safe
*/
if ((rq->data_len & mask) || (addr & mask))
info->dma = 0;
}
/* Start sending the command to the drive. */
......@@ -3133,7 +3137,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
int nslots;
blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
blk_queue_dma_alignment(drive->queue, 3);
blk_queue_dma_alignment(drive->queue, 31);
drive->queue->unplug_delay = (1 * HZ) / 1000;
if (!drive->queue->unplug_delay)
drive->queue->unplug_delay = 1;
......
......@@ -554,44 +554,6 @@ menu "DOS/FAT/NT Filesystems"
config FAT_FS
tristate
select NLS
help
If you want to use one of the FAT-based file systems (the MS-DOS,
VFAT (Windows 95) and UMSDOS (used to run Linux on top of an
ordinary DOS partition) file systems), then you must say Y or M here
to include FAT support. You will then be able to mount partitions or
diskettes with FAT-based file systems and transparently access the
files on them, i.e. MSDOS files will look and behave just like all
other Unix files.
This FAT support is not a file system in itself, it only provides
the foundation for the other file systems. You will have to say Y or
M to at least one of "MSDOS fs support" or "VFAT fs support" in
order to make use of it.
Another way to read and write MSDOS floppies and hard drive
partitions from within Linux (but not transparently) is with the
mtools ("man mtools") program suite. You don't need to say Y here in
order to do that.
If you need to move large files on floppies between a DOS and a
Linux box, say Y here, mount the floppy under Linux with an MSDOS
file system and use GNU tar's M option. GNU tar is a program
available for Unix and DOS ("man tar" or "info tar").
It is now also becoming possible to read and write compressed FAT
file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
details.
The FAT support will enlarge your kernel by about 37 KB. If unsure,
say Y.
To compile this as a module, choose M here: the module will be called
fat. Note that if you compile the FAT support as a module, you
cannot compile any of the FAT-based file systems into the kernel
-- they will have to be modules as well.
The file system of your root partition (the one containing the
directory /) cannot be a module, so don't say M here if you intend
to use UMSDOS as your root file system.
config MSDOS_FS
tristate "MSDOS fs support"
......@@ -644,25 +606,6 @@ config VFAT_FS
To compile this as a module, choose M here: the module will be called
vfat.
config FAT_DEFAULT_CODEPAGE
int "Default codepage for FAT"
depends on MSDOS_FS || VFAT_FS
default 437
help
This option should be set to the codepage of your FAT filesystems.
It can be overridden with the 'codepage' mount option.
config FAT_DEFAULT_IOCHARSET
string "Default iocharset for FAT"
depends on VFAT_FS
default "iso8859-1"
help
Set this to the default I/O character set you'd like FAT to use.
It should probably match the character set that most of your
FAT filesystems use, and can be overridded with the 'iocharset'
mount option for FAT filesystems. Note that UTF8 is *not* a
supported charset for FAT filesystems.
config UMSDOS_FS
#dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
# UMSDOS is temprory broken
......
......@@ -376,6 +376,115 @@ int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
len, offset);
}
/**
* bio_uncopy_user - finish previously mapped bio
* @bio: bio being terminated
*
* Free pages allocated from bio_copy_user() and write back data
* to user space in case of a read.
*/
int bio_uncopy_user(struct bio *bio)
{
struct bio_vec *bvec;
int i, ret = 0;
if (bio_data_dir(bio) == READ) {
char *uaddr = bio->bi_private;
__bio_for_each_segment(bvec, bio, i, 0) {
char *addr = page_address(bvec->bv_page);
if (!ret && copy_to_user(uaddr, addr, bvec->bv_len))
ret = -EFAULT;
__free_page(bvec->bv_page);
uaddr += bvec->bv_len;
}
}
bio_put(bio);
return ret;
}
/**
* bio_copy_user - copy user data to bio
* @q: destination block queue
* @uaddr: start of user address
* @len: length in bytes
* @write_to_vm: bool indicating writing to pages or not
*
* Prepares and returns a bio for indirect user io, bouncing data
* to/from kernel pages as necessary. Must be paired with
* call bio_uncopy_user() on io completion.
*/
struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr,
unsigned int len, int write_to_vm)
{
unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
unsigned long start = uaddr >> PAGE_SHIFT;
struct bio_vec *bvec;
struct page *page;
struct bio *bio;
int i, ret;
bio = bio_alloc(GFP_KERNEL, end - start);
if (!bio)
return ERR_PTR(-ENOMEM);
ret = 0;
while (len) {
unsigned int bytes = PAGE_SIZE;
if (bytes > len)
bytes = len;
page = alloc_page(q->bounce_gfp | GFP_KERNEL);
if (!page) {
ret = -ENOMEM;
break;
}
if (__bio_add_page(q, bio, page, bytes, 0) < bytes) {
ret = -EINVAL;
break;
}
len -= bytes;
}
/*
* success
*/
if (!ret) {
if (!write_to_vm) {
bio->bi_rw |= (1 << BIO_RW);
/*
* for a write, copy in data to kernel pages
*/
ret = -EFAULT;
bio_for_each_segment(bvec, bio, i) {
char *addr = page_address(bvec->bv_page);
if (copy_from_user(addr, (char *) uaddr, bvec->bv_len))
goto cleanup;
}
}
bio->bi_private = (void *) uaddr;
return bio;
}
/*
* cleanup
*/
cleanup:
bio_for_each_segment(bvec, bio, i)
__free_page(bvec->bv_page);
bio_put(bio);
return ERR_PTR(ret);
}
static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev,
unsigned long uaddr, unsigned int len,
int write_to_vm)
......@@ -392,12 +501,13 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev,
* size for now, in the future we can relax this restriction
*/
if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q)))
return NULL;
return ERR_PTR(-EINVAL);
bio = bio_alloc(GFP_KERNEL, nr_pages);
if (!bio)
return NULL;
return ERR_PTR(-ENOMEM);
ret = -ENOMEM;
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
if (!pages)
goto out;
......@@ -446,11 +556,12 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev,
if (!write_to_vm)
bio->bi_rw |= (1 << BIO_RW);
bio->bi_flags |= (1 << BIO_USER_MAPPED);
return bio;
out:
kfree(pages);
bio_put(bio);
return NULL;
return ERR_PTR(ret);
}
/**
......@@ -461,7 +572,7 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev,
* @write_to_vm: bool indicating writing to pages or not
*
* Map the user space address into a bio suitable for io to a block
* device.
* device. Returns an error pointer in case of error.
*/
struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev,
unsigned long uaddr, unsigned int len, int write_to_vm)
......@@ -470,7 +581,9 @@ struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev,
bio = __bio_map_user(q, bdev, uaddr, len, write_to_vm);
if (bio) {
if (IS_ERR(bio))
return bio;
/*
* subtle -- if __bio_map_user() ended up bouncing a bio,
* it would normally disappear when its bi_end_io is run.
......@@ -479,17 +592,18 @@ struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev,
*/
bio_get(bio);
if (bio->bi_size < len) {
bio_endio(bio, bio->bi_size, 0);
bio_unmap_user(bio, 0);
return NULL;
}
}
if (bio->bi_size == len)
return bio;
/*
* don't support partial mappings
*/
bio_endio(bio, bio->bi_size, 0);
bio_unmap_user(bio);
return ERR_PTR(-EINVAL);
}
static void __bio_unmap_user(struct bio *bio, int write_to_vm)
static void __bio_unmap_user(struct bio *bio)
{
struct bio_vec *bvec;
int i;
......@@ -510,7 +624,7 @@ static void __bio_unmap_user(struct bio *bio, int write_to_vm)
* make sure we dirty pages we wrote to
*/
__bio_for_each_segment(bvec, bio, i, 0) {
if (write_to_vm)
if (bio_data_dir(bio) == READ)
set_page_dirty_lock(bvec->bv_page);
page_cache_release(bvec->bv_page);
......@@ -522,17 +636,15 @@ static void __bio_unmap_user(struct bio *bio, int write_to_vm)
/**
* bio_unmap_user - unmap a bio
* @bio: the bio being unmapped
* @write_to_vm: bool indicating whether pages were written to
*
* Unmap a bio previously mapped by bio_map_user(). The @write_to_vm
* must be the same as passed into bio_map_user(). Must be called with
* Unmap a bio previously mapped by bio_map_user(). Must be called with
* a process context.
*
* bio_unmap_user() may sleep.
*/
void bio_unmap_user(struct bio *bio, int write_to_vm)
void bio_unmap_user(struct bio *bio)
{
__bio_unmap_user(bio, write_to_vm);
__bio_unmap_user(bio);
bio_put(bio);
}
......@@ -863,3 +975,5 @@ EXPORT_SYMBOL(bio_unmap_user);
EXPORT_SYMBOL(bio_pair_release);
EXPORT_SYMBOL(bio_split);
EXPORT_SYMBOL(bio_split_pool);
EXPORT_SYMBOL(bio_copy_user);
EXPORT_SYMBOL(bio_uncopy_user);
......@@ -23,14 +23,6 @@
#include <linux/parser.h>
#include <asm/unaligned.h>
#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
/* if user don't select VFAT, this is undefined. */
#define CONFIG_FAT_DEFAULT_IOCHARSET ""
#endif
static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
/*
* New FAT inode stuff. We do the following:
* a) i_ino is constant and has nothing with on-disk location.
......@@ -174,15 +166,15 @@ void fat_put_super(struct super_block *sb)
if (sbi->nls_disk) {
unload_nls(sbi->nls_disk);
sbi->nls_disk = NULL;
sbi->options.codepage = fat_default_codepage;
sbi->options.codepage = 0;
}
if (sbi->nls_io) {
unload_nls(sbi->nls_io);
sbi->nls_io = NULL;
}
if (sbi->options.iocharset != fat_default_iocharset) {
if (sbi->options.iocharset) {
kfree(sbi->options.iocharset);
sbi->options.iocharset = fat_default_iocharset;
sbi->options.iocharset = NULL;
}
sb->s_fs_info = NULL;
......@@ -201,11 +193,10 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
seq_printf(m, ",gid=%u", opts->fs_gid);
seq_printf(m, ",fmask=%04o", opts->fs_fmask);
seq_printf(m, ",dmask=%04o", opts->fs_dmask);
if (sbi->nls_disk && opts->codepage != fat_default_codepage)
if (sbi->nls_disk && opts->codepage)
seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
if (isvfat) {
if (sbi->nls_io &&
strcmp(opts->iocharset, fat_default_iocharset))
if (sbi->nls_io && opts->iocharset)
seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
switch (opts->shortname) {
......@@ -336,15 +327,14 @@ static int parse_options(char *options, int is_vfat, int *debug,
char *p;
substring_t args[MAX_OPT_ARGS];
int option;
char *iocharset;
opts->isvfat = is_vfat;
opts->fs_uid = current->uid;
opts->fs_gid = current->gid;
opts->fs_fmask = opts->fs_dmask = current->fs->umask;
opts->codepage = fat_default_codepage;
opts->iocharset = fat_default_iocharset;
opts->codepage = 0;
opts->iocharset = NULL;
if (is_vfat)
opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95;
else
......@@ -443,12 +433,11 @@ static int parse_options(char *options, int is_vfat, int *debug,
/* vfat specific */
case Opt_charset:
if (opts->iocharset != fat_default_iocharset)
if (opts->iocharset)
kfree(opts->iocharset);
iocharset = match_strdup(&args[0]);
if (!iocharset)
opts->iocharset = match_strdup(&args[0]);
if (opts->iocharset == NULL)
return -ENOMEM;
opts->iocharset = iocharset;
break;
case Opt_shortname_lower:
opts->shortname = VFAT_SFN_DISPLAY_LOWER
......@@ -497,12 +486,6 @@ static int parse_options(char *options, int is_vfat, int *debug,
return -EINVAL;
}
}
/* UTF8 doesn't provide FAT semantics */
if (!strcmp(opts->iocharset, "utf8")) {
printk(KERN_ERR "FAT: utf8 is not a recommended IO charset"
" for FAT filesystems, filesystem will be case sensitive!\n");
}
if (opts->unicode_xlate)
opts->utf8 = 0;
......@@ -785,6 +768,66 @@ static struct export_operations fat_export_ops = {
.get_parent = fat_get_parent,
};
static int fat_load_nls(struct super_block *sb)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct fat_mount_options *opts = &sbi->options;
char codepage[50], *iocharset;
int error = 0, not_specified = 0;
if (opts->codepage)
snprintf(codepage, sizeof(codepage), "cp%d", opts->codepage);
else {
not_specified = 1;
strcpy(codepage, "default");
}
sbi->nls_disk = load_nls(codepage);
if (sbi->nls_disk == NULL) {
printk(KERN_ERR "FAT: codepage %s not found\n", codepage);
error = -EINVAL;
goto out;
}
if (opts->isvfat) {
if (opts->iocharset)
iocharset = opts->iocharset;
else {
not_specified = 1;
iocharset = "default";
}
/*
* FIXME: utf8 is using iocharset for upper/lower conversion
* UTF8 doesn't provide FAT semantics
*/
if (!strcmp(iocharset, "utf8")) {
printk(KERN_WARNING
"FAT: utf8 is not a recommended IO charset"
" for FAT filesystem,"
" filesystem will be case sensitive!\n");
}
sbi->nls_io = load_nls(iocharset);
if (sbi->nls_io == NULL) {
printk(KERN_ERR "FAT: IO charset %s not found\n",
iocharset);
error = -EINVAL;
goto out;
}
}
if (not_specified) {
unsigned long not_ro = !(sb->s_flags & MS_RDONLY);
if (not_ro)
sb->s_flags |= MS_RDONLY;
printk(KERN_INFO "FAT: %s option didn't specified\n"
" File name can not access proper%s\n",
opts->isvfat ? "codepage or iocharset" : "codepage",
not_ro ? " (mounted as read-only)" : "");
}
out:
return error;
}
/*
* Read the super block of an MS-DOS FS.
*/
......@@ -800,7 +843,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
int debug, first;
unsigned int media;
long error;
char buf[50];
sbi = kmalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
if (!sbi)
......@@ -1015,23 +1057,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
goto out_invalid;
}
error = -EINVAL;
sprintf(buf, "cp%d", sbi->options.codepage);
sbi->nls_disk = load_nls(buf);
if (!sbi->nls_disk) {
printk(KERN_ERR "FAT: codepage %s not found\n", buf);
goto out_fail;
}
/* FIXME: utf8 is using iocharset for upper/lower conversion */
if (sbi->options.isvfat) {
sbi->nls_io = load_nls(sbi->options.iocharset);
if (!sbi->nls_io) {
printk(KERN_ERR "FAT: IO charset %s not found\n",
sbi->options.iocharset);
error = fat_load_nls(sb);
if (error)
goto out_fail;
}
}
error = -ENOMEM;
root_inode = new_inode(sb);
......@@ -1065,7 +1093,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
unload_nls(sbi->nls_io);
if (sbi->nls_disk)
unload_nls(sbi->nls_disk);
if (sbi->options.iocharset != fat_default_iocharset)
if (sbi->options.iocharset)
kfree(sbi->options.iocharset);
sb->s_fs_info = NULL;
kfree(sbi);
......
......@@ -120,6 +120,7 @@ struct bio {
#define BIO_SEG_VALID 3 /* nr_hw_seg valid */
#define BIO_CLONED 4 /* doesn't own data */
#define BIO_BOUNCED 5 /* bio is a bounce bio */
#define BIO_USER_MAPPED 6 /* contains user pages */
#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
/*
......@@ -264,9 +265,11 @@ extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int);
extern int bio_get_nr_vecs(struct block_device *);
extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
unsigned long, unsigned int, int);
extern void bio_unmap_user(struct bio *, int);
extern void bio_unmap_user(struct bio *);
extern void bio_set_pages_dirty(struct bio *bio);
extern void bio_check_pages_dirty(struct bio *bio);
extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
extern int bio_uncopy_user(struct bio *);
#ifdef CONFIG_HIGHMEM
/*
......
......@@ -524,7 +524,7 @@ extern void __blk_stop_queue(request_queue_t *q);
extern void blk_run_queue(request_queue_t *);
extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int);
extern int blk_rq_unmap_user(struct request *, void __user *, struct bio *, unsigned int);
extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int);
extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
......
......@@ -420,6 +420,7 @@ struct tcp_opt {
__u32 cnt; /* increase cwnd by 1 after this number of ACKs */
__u32 last_max_cwnd; /* last maximium snd_cwnd */
__u32 last_cwnd; /* the last snd_cwnd */
__u32 last_stamp; /* time when updated last_cwnd */
} bictcp;
};
......
......@@ -178,8 +178,8 @@ static __inline__ u8 ipv6_addr_hash(const struct in6_addr *addr)
* This will include the IEEE address token on links that support it.
*/
word = addr->s6_addr[2] ^ addr->s6_addr32[3];
word ^= (word>>16);
word = addr->s6_addr32[2] ^ addr->s6_addr32[3];
word ^= (word >> 16);
word ^= (word >> 8);
return ((word ^ (word >> 4)) & 0x0f);
......
......@@ -821,11 +821,9 @@ extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_output(struct sk_buff **pskb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_check_size(struct sk_buff *skb);
extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
extern int xfrm6_tunnel_check_size(struct sk_buff *skb);
extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
......
......@@ -75,7 +75,7 @@ static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f)
{
hlist_del_rcu(&f->hlist);
if (!f->is_static)
list_del(&f->age_list);
list_del(&f->u.age_list);
br_fdb_put(f);
}
......@@ -130,9 +130,11 @@ void br_fdb_cleanup(unsigned long _data)
delay = hold_time(br);
list_for_each_safe(l, n, &br->age_list) {
struct net_bridge_fdb_entry *f
= list_entry(l, struct net_bridge_fdb_entry, age_list);
unsigned long expires = f->ageing_timer + delay;
struct net_bridge_fdb_entry *f;
unsigned long expires;
f = list_entry(l, struct net_bridge_fdb_entry, u.age_list);
expires = f->ageing_timer + delay;
if (time_before_eq(expires, jiffies)) {
WARN_ON(f->is_static);
......@@ -220,7 +222,7 @@ struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
static void fdb_rcu_free(struct rcu_head *head)
{
struct net_bridge_fdb_entry *ent
= container_of(head, struct net_bridge_fdb_entry, rcu);
= container_of(head, struct net_bridge_fdb_entry, u.rcu);
kmem_cache_free(br_fdb_cache, ent);
}
......@@ -228,7 +230,7 @@ static void fdb_rcu_free(struct rcu_head *head)
void br_fdb_put(struct net_bridge_fdb_entry *ent)
{
if (atomic_dec_and_test(&ent->use_count))
call_rcu(&ent->rcu, fdb_rcu_free);
call_rcu(&ent->u.rcu, fdb_rcu_free);
}
/*
......@@ -314,7 +316,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
return 0;
/* move to end of age list */
list_del(&fdb->age_list);
list_del(&fdb->u.age_list);
goto update;
}
}
......@@ -338,7 +340,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
fdb->is_static = is_local;
fdb->ageing_timer = jiffies;
if (!is_local)
list_add_tail(&fdb->age_list, &br->age_list);
list_add_tail(&fdb->u.age_list, &br->age_list);
return 0;
}
......
......@@ -49,7 +49,7 @@ struct net_bridge_fdb_entry
union {
struct list_head age_list;
struct rcu_head rcu;
};
} u;
atomic_t use_count;
unsigned long ageing_timer;
mac_addr addr;
......
#include <linux/config.h>
#include <linux/module.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ah.h>
......
#include <linux/config.h>
#include <linux/module.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/esp.h>
......
......@@ -18,7 +18,6 @@
#include <asm/scatterlist.h>
#include <linux/crypto.h>
#include <linux/pfkeyv2.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
......
......@@ -862,6 +862,77 @@ static unsigned char snmp_request_decode(struct asn1_ctx *ctx,
return 1;
}
/*
* Fast checksum update for possibly oddly-aligned UDP byte, from the
* code example in the draft.
*/
static void fast_csum(unsigned char *csum,
const unsigned char *optr,
const unsigned char *nptr,
int odd)
{
long x, old, new;
x = csum[0] * 256 + csum[1];
x =~ x & 0xFFFF;
if (odd) old = optr[0] * 256;
else old = optr[0];
x -= old & 0xFFFF;
if (x <= 0) {
x--;
x &= 0xFFFF;
}
if (odd) new = nptr[0] * 256;
else new = nptr[0];
x += new & 0xFFFF;
if (x & 0x10000) {
x++;
x &= 0xFFFF;
}
x =~ x & 0xFFFF;
csum[0] = x / 256;
csum[1] = x & 0xFF;
}
/*
* Mangle IP address.
* - begin points to the start of the snmp messgae
* - addr points to the start of the address
*/
static inline void mangle_address(unsigned char *begin,
unsigned char *addr,
const struct oct1_map *map,
u_int16_t *check)
{
if (map->from == NOCT1(*addr)) {
u_int32_t old;
if (debug)
memcpy(&old, (unsigned char *)addr, sizeof(old));
*addr = map->to;
/* Update UDP checksum if being used */
if (*check) {
unsigned char odd = !((addr - begin) % 2);
fast_csum((unsigned char *)check,
&map->from, &map->to, odd);
}
if (debug)
printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to "
"%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr));
}
}
static unsigned char snmp_trap_decode(struct asn1_ctx *ctx,
struct snmp_v1_trap *trap,
const struct oct1_map *map,
......@@ -952,77 +1023,6 @@ static void hex_dump(unsigned char *buf, size_t len)
printk("\n");
}
/*
* Fast checksum update for possibly oddly-aligned UDP byte, from the
* code example in the draft.
*/
static void fast_csum(unsigned char *csum,
const unsigned char *optr,
const unsigned char *nptr,
int odd)
{
long x, old, new;
x = csum[0] * 256 + csum[1];
x =~ x & 0xFFFF;
if (odd) old = optr[0] * 256;
else old = optr[0];
x -= old & 0xFFFF;
if (x <= 0) {
x--;
x &= 0xFFFF;
}
if (odd) new = nptr[0] * 256;
else new = nptr[0];
x += new & 0xFFFF;
if (x & 0x10000) {
x++;
x &= 0xFFFF;
}
x =~ x & 0xFFFF;
csum[0] = x / 256;
csum[1] = x & 0xFF;
}
/*
* Mangle IP address.
* - begin points to the start of the snmp messgae
* - addr points to the start of the address
*/
static inline void mangle_address(unsigned char *begin,
unsigned char *addr,
const struct oct1_map *map,
u_int16_t *check)
{
if (map->from == NOCT1(*addr)) {
u_int32_t old;
if (debug)
memcpy(&old, (unsigned char *)addr, sizeof(old));
*addr = map->to;
/* Update UDP checksum if being used */
if (*check) {
unsigned char odd = !((addr - begin) % 2);
fast_csum((unsigned char *)check,
&map->from, &map->to, odd);
}
if (debug)
printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to "
"%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr));
}
}
/*
* Parse and mangle SNMP message according to mapping.
* (And this is the fucking 'basic' method).
......
......@@ -330,6 +330,15 @@ static void tcp_init_buffer_space(struct sock *sk)
tp->snd_cwnd_stamp = tcp_time_stamp;
}
static void init_bictcp(struct tcp_opt *tp)
{
tp->bictcp.cnt = 0;
tp->bictcp.last_max_cwnd = 0;
tp->bictcp.last_cwnd = 0;
tp->bictcp.last_stamp = 0;
}
/* 5. Recalculate window clamp after socket hit its memory bounds. */
static void tcp_clamp_window(struct sock *sk, struct tcp_opt *tp)
{
......@@ -1233,6 +1242,8 @@ static void tcp_enter_frto_loss(struct sock *sk)
tcp_set_ca_state(tp, TCP_CA_Loss);
tp->high_seq = tp->frto_highmark;
TCP_ECN_queue_cwr(tp);
init_bictcp(tp);
}
void tcp_clear_retrans(struct tcp_opt *tp)
......@@ -2011,10 +2022,12 @@ static inline __u32 bictcp_cwnd(struct tcp_opt *tp)
if (!sysctl_tcp_bic)
return tp->snd_cwnd;
if (tp->bictcp.last_cwnd == tp->snd_cwnd)
return tp->bictcp.cnt; /* same cwnd, no update */
if (tp->bictcp.last_cwnd == tp->snd_cwnd &&
(s32)(tcp_time_stamp - tp->bictcp.last_stamp) <= (HZ>>5))
return tp->bictcp.cnt;
tp->bictcp.last_cwnd = tp->snd_cwnd;
tp->bictcp.last_stamp = tcp_time_stamp;
/* start off normal */
if (tp->snd_cwnd <= sysctl_tcp_bic_low_window)
......@@ -4612,6 +4625,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
return 1;
init_westwood(sk);
init_bictcp(tp);
/* Now we have several options: In theory there is
* nothing else in the frame. KA9Q has an option to
......@@ -4635,6 +4649,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
case TCP_SYN_SENT:
init_westwood(sk);
init_bictcp(tp);
queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
if (queued >= 0)
......
......@@ -767,9 +767,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
newtp->snd_cwnd = 2;
newtp->snd_cwnd_cnt = 0;
newtp->bictcp.cnt = 0;
newtp->bictcp.last_max_cwnd = newtp->bictcp.last_cwnd = 0;
newtp->frto_counter = 0;
newtp->frto_highmark = 0;
......
......@@ -13,6 +13,7 @@
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
/* Add encapsulation header.
*
......@@ -67,6 +68,30 @@ static void xfrm4_encap(struct sk_buff *skb)
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
}
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
struct dst_entry *dst;
struct iphdr *iph = skb->nh.iph;
if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
goto out;
IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
if (!(iph->frag_off & htons(IP_DF)))
goto out;
dst = skb->dst;
mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
if (skb->len > mtu) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
ret = -EMSGSIZE;
}
out:
return ret;
}
int xfrm4_output(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
......
......@@ -6,32 +6,7 @@
#include <linux/skbuff.h>
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/inet_ecn.h>
int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
struct dst_entry *dst;
struct iphdr *iph = skb->nh.iph;
if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
goto out;
IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
if (!(iph->frag_off & htons(IP_DF)))
goto out;
dst = skb->dst;
mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
if (skb->len > mtu) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
ret = -EMSGSIZE;
}
out:
return ret;
}
#include <net/protocol.h>
static int ipip_output(struct sk_buff **pskb)
{
......
......@@ -26,7 +26,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/ah.h>
#include <linux/crypto.h>
......
......@@ -26,7 +26,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/esp.h>
......
......@@ -32,7 +32,6 @@
*/
#include <linux/config.h>
#include <linux/module.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ipcomp.h>
......
......@@ -11,6 +11,7 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/icmpv6.h>
#include <net/inet_ecn.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
......@@ -68,6 +69,23 @@ static void xfrm6_encap(struct sk_buff *skb)
ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
}
static int xfrm6_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
struct dst_entry *dst = skb->dst;
mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr);
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
if (skb->len > mtu) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
ret = -EMSGSIZE;
}
return ret;
}
int xfrm6_output(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
......
......@@ -27,8 +27,8 @@
#include <linux/list.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
......@@ -343,25 +343,6 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
int xfrm6_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
struct dst_entry *dst = skb->dst;
mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr);
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
if (skb->len > mtu) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
ret = -EMSGSIZE;
}
return ret;
}
EXPORT_SYMBOL(xfrm6_tunnel_check_size);
static int xfrm6_tunnel_output(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
......
......@@ -213,7 +213,9 @@ config NET_SCH_NETEM
testing applications or protocols.
To compile this driver as a module, choose M here: the module
will be called sch_delay.
will be called sch_netem.
If unsure, say N.
config NET_SCH_INGRESS
tristate "Ingress Qdisc"
......
......@@ -35,7 +35,6 @@ EXPORT_SYMBOL(xfrm_parse_spi);
EXPORT_SYMBOL(xfrm4_rcv);
EXPORT_SYMBOL(xfrm4_tunnel_register);
EXPORT_SYMBOL(xfrm4_tunnel_deregister);
EXPORT_SYMBOL(xfrm4_tunnel_check_size);
EXPORT_SYMBOL(xfrm_register_type);
EXPORT_SYMBOL(xfrm_unregister_type);
EXPORT_SYMBOL(xfrm_get_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment