From e4077388023e5695cb236e0acb5ddaf26e8d9907 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:29:09 -0500 Subject: [PATCH] Import 2.3.32pre2 --- CREDITS | 2 +- Documentation/Configure.help | 16 +- Documentation/ide.txt | 2 + drivers/block/ide-probe.c | 3 +- drivers/block/ide.c | 14 + drivers/char/msp3400.c | 260 +++++++++----- drivers/i2o/i2o_core.c | 3 +- drivers/net/rclanmtl.c | 8 +- drivers/net/sb1000.c | 252 ++++++------- drivers/net/tlan.c | 70 ++-- drivers/net/tlan.h | 1 + drivers/scsi/53c8xx_d.h | 1 + drivers/scsi/g_NCR5380.c | 13 +- drivers/scsi/g_NCR5380.h | 2 +- drivers/scsi/ide-scsi.c | 5 +- drivers/scsi/sim710_d.h | 1 + drivers/sound/mad16.c | 87 ++++- drivers/sound/sb_ess.c | 46 +-- fs/Config.in | 4 + fs/nfsd/Makefile | 3 + fs/nfsd/nfs3proc.c | 622 ++++++++++++++++++++------------- fs/nfsd/nfs3xdr.c | 324 ++++++++++------- fs/nfsd/nfsproc.c | 9 +- fs/nfsd/nfssvc.c | 21 +- fs/nfsd/vfs.c | 297 +++++++++++++++- include/linux/ide.h | 2 + include/linux/nfsd/nfsd.h | 22 +- include/linux/nfsd/nfsfh.h | 81 +++++ include/linux/nfsd/xdr3.h | 116 ++++-- mm/swapfile.c | 4 +- net/decnet/Makefile | 2 - net/decnet/dn_dev.c | 10 +- net/decnet/sysctl_net_decnet.c | 11 + net/netsyms.c | 5 + 34 files changed, 1587 insertions(+), 732 deletions(-) diff --git a/CREDITS b/CREDITS index 70f296ef7dbc..aa16a443ce00 100644 --- a/CREDITS +++ b/CREDITS @@ -1605,7 +1605,7 @@ S: Perth, Western Australia S: Australia N: Greg Page -E: greg@caldera.com +E: gpage@sovereign.org D: IPX development and support N: David Parsons diff --git a/Documentation/Configure.help b/Documentation/Configure.help index fad694c0c80c..30c8f3901568 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1477,10 +1477,6 @@ CONFIG_NETFILTER Chances are that you should say Y here if you compile a kernel which will run as a router and N for regular hosts. If unsure, say N. -Network packet filtering debugging -CONFIG_NETFILTER_DEBUG - Say Y to make sure packets aren't leaking. - SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN @@ -1496,7 +1492,7 @@ CONFIG_SYN_COOKIES is no need for the legitimate users to change their TCP/IP software; SYN cookies work transparently to them. For technical information about SYN cookies, check out - ftp://koobera.math.uic.edu/pub/docs/syncookies-archive . + ftp://koobera.math.uic.edu/syncookies.html . If you are SYN flooded, the source address reported by the kernel is likely to have been forged by the attacker; it is only reported as @@ -8415,7 +8411,15 @@ Emulate SUN NFS server CONFIG_NFSD_SUN If you would like for the server to allow clients to access directories that are mount points on the local filesystem (this is - how nfsd behaves on Sun systems), say Y here. If unsure, say N. + how nfsd behaves on Sun systems), say Y here. + If you use Tru64 clients, say Y. + If unsure, say N. + +Provide NFSv3 server support (EXPERIMENTAL) +CONFIG_NFSD_V3 + If you would like to include the NFSv3 server was well as the NFSv2 + server, say Y here. File locking, via the NLMv4 protocol, is not + supported yet. If unsure, say N. OS/2 HPFS filesystem support CONFIG_HPFS_FS diff --git a/Documentation/ide.txt b/Documentation/ide.txt index df417541d924..4f10e114e1b6 100644 --- a/Documentation/ide.txt +++ b/Documentation/ide.txt @@ -276,6 +276,8 @@ Summary of ide driver parameters for kernel "command line": port. Should be used only as a last resort. "hdx=swapdata" : when the drive is a disk, byte swap all data + "hdxlun=xx" : set the drive last logical unit + "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, where "xx" is between 20 and 66 inclusive, used when tuning chipset PIO modes. diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index d254385ccb57..34ab3eb7b56f 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -56,7 +56,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); - + if (!drive->forced_lun) + drive->last_lun = id->word126 & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 52c90bcaa73a..cfd9f36f9d1c 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -2684,6 +2684,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m * * "hdx=swapdata" : when the drive is a disk, byte swap all data * "hdx=bswap" : same as above.......... + * "hdxlun=xx" : set the drive last logical unit. * "hdx=flash" : allows for more than one ata_flash disk to be * registered. In most cases, only one device * will be present. @@ -2789,6 +2790,19 @@ void __init ide_setup (char *s) strncpy(drive->driver_req, s + 4, 9); goto done; } + /* + * Look for last lun option: "hdxlun=" + */ + if (s[3] == 'l' && s[4] == 'u' && s[5] == 'n') { + if (match_parm(&s[6], NULL, vals, 1) != 1) + goto bad_option; + if (vals[0] >= 0 && vals[0] <= 7) { + drive->last_lun = vals[0]; + drive->forced_lun = 1; + } else + printk(" -- BAD LAST LUN! Expected value from 0 to 7"); + goto done; + } switch (match_parm(&s[3], hd_words, vals, 3)) { case -1: /* "none" */ drive->nobios = 1; /* drop into "noprobe" */ diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 2990efbb6638..73fd1654155c 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -76,6 +76,7 @@ struct msp3400c { int mode; int norm; int stereo; + int nicam_on; int main, second; /* sound carrier */ int left, right; /* volume */ @@ -151,27 +152,39 @@ static int msp3400c_reset(struct i2c_bus *bus) static int msp3400c_read(struct i2c_bus *bus, int dev, int addr) { - int ret=0; - short val = 0; - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, dev+1, 0) || - 0 != i2c_sendbyte(bus, addr >> 8, 0) || - 0 != i2c_sendbyte(bus, addr & 0xff, 0)) { - ret = -1; - } else { + int err,ret; + short val=0; + + for (err = 0; err < 3;) { + ret = 0; i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) { + if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || + 0 != i2c_sendbyte(bus, dev+1, 0) || + 0 != i2c_sendbyte(bus, addr >> 8, 0) || + 0 != i2c_sendbyte(bus, addr & 0xff, 0)) { ret = -1; } else { - val |= (int)i2c_readbyte(bus,0) << 8; - val |= (int)i2c_readbyte(bus,1); + i2c_start(bus); + if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) { + ret = -1; + } else { + val |= (int)i2c_readbyte(bus,0) << 8; + val |= (int)i2c_readbyte(bus,1); + } } + i2c_stop(bus); + if (0 == ret) + break; + + /* some I/O error */ + err++; + printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", + err, dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); } - i2c_stop(bus); if (-1 == ret) { - printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n", - (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr); + printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); msp3400c_reset(bus); } return val; @@ -180,20 +193,31 @@ msp3400c_read(struct i2c_bus *bus, int dev, int addr) static int msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val) { - int ret = 0; + int ret,err; - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, dev, 0) || - 0 != i2c_sendbyte(bus, addr >> 8, 0) || - 0 != i2c_sendbyte(bus, addr & 0xff, 0) || - 0 != i2c_sendbyte(bus, val >> 8, 0) || - 0 != i2c_sendbyte(bus, val & 0xff, 0)) - ret = -1; - i2c_stop(bus); + for (err = 0; err < 3;) { + ret = 0; + i2c_start(bus); + if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || + 0 != i2c_sendbyte(bus, dev, 0) || + 0 != i2c_sendbyte(bus, addr >> 8, 0) || + 0 != i2c_sendbyte(bus, addr & 0xff, 0) || + 0 != i2c_sendbyte(bus, val >> 8, 0) || + 0 != i2c_sendbyte(bus, val & 0xff, 0)) + ret = -1; + i2c_stop(bus); + if (0 == ret) + break; + + /* some I/O error */ + err++; + printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", + err, dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } if (-1 == ret) { - printk(KERN_WARNING "msp3400: I/O error, trying reset (write %s 0x%x)\n", - (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr); + printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); msp3400c_reset(bus); } return ret; @@ -383,12 +407,12 @@ static void msp3400c_setmode(struct msp3400c *msp, int type) static void msp3400c_setstereo(struct msp3400c *msp, int mode) { int nicam=0; /* channel source: FM/AM or nicam */ - + int src=0; + /* switch demodulator */ switch (msp->mode) { case MSP_MODE_FM_TERRA: dprintk("msp3400: FM setstereo: %d\n",mode); - msp->stereo = mode; msp3400c_setcarrier(msp->bus,msp->second,msp->main); switch (mode) { case VIDEO_SOUND_STEREO: @@ -403,7 +427,6 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) break; case MSP_MODE_FM_SAT: dprintk("msp3400: SAT setstereo: %d\n",mode); - msp->stereo = mode; switch (mode) { case VIDEO_SOUND_MONO: msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); @@ -424,7 +447,8 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) dprintk("msp3400: NICAM setstereo: %d\n",mode); msp->stereo = mode; msp3400c_setcarrier(msp->bus,msp->second,msp->main); - nicam=0x0100; + if (msp->nicam_on) + nicam=0x0100; break; default: /* can't do stereo - abort here */ @@ -434,25 +458,22 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) /* switch audio */ switch (mode) { case VIDEO_SOUND_STEREO: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0020|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0020|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0020|nicam); + src = 0x0020 | nicam; #if 0 msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005,0x4000); #endif break; case VIDEO_SOUND_MONO: case VIDEO_SOUND_LANG1: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0000|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0000|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0000|nicam); + src = 0x0000 | nicam; break; case VIDEO_SOUND_LANG2: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0010|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0010|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0010|nicam); + src = 0x0010 | nicam; break; } + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,src); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,src); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,src); } static void @@ -491,6 +512,77 @@ struct REGISTER_DUMP d1[] = { { 0x0057, "ERROR_RATE" }, }; +static int +autodetect_stereo(struct msp3400c *msp) +{ + int val; + int newstereo = msp->stereo; + int newnicam = msp->nicam_on; + int update = 0; + + switch (msp->mode) { + case MSP_MODE_FM_TERRA: + val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18); + dprintk("msp3400: stereo detect register: %d\n",val); + + if (val > 4096) { + newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO; + } else if (val < -4096) { + newstereo = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } else { + newstereo = VIDEO_SOUND_MONO; + } + newnicam = 0; + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23); + dprintk("msp3400: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1); + + if (val & 1) { + /* nicam synced */ + switch ((val & 0x1e) >> 1) { + case 0: + case 8: + newstereo = VIDEO_SOUND_STEREO; + break; + case 1: + case 9: + newstereo = VIDEO_SOUND_MONO + | VIDEO_SOUND_LANG1; + break; + case 2: + case 10: + newstereo = VIDEO_SOUND_MONO + | VIDEO_SOUND_LANG1 + | VIDEO_SOUND_LANG2; + break; + default: + newstereo = VIDEO_SOUND_MONO; + break; + } + newnicam=1; + } else { + newnicam=0; + newstereo = VIDEO_SOUND_MONO; + } + break; + } + if (newstereo != msp->stereo) { + update = 1; + dprintk("msp3400: watch: stereo %d => %d\n", + msp->stereo,newstereo); + msp->stereo = newstereo; + } + if (newnicam != msp->nicam_on) { + update = 1; + dprintk("msp3400: watch: nicam %d => %d\n", + msp->nicam_on,newnicam); + msp->nicam_on = newnicam; + } + return update; +} + /* * A kernel thread for msp3400 control -- we don't want to block the * in the ioctl while doing the sound carrier & stereo detect @@ -503,13 +595,34 @@ static void msp3400c_stereo_wake(unsigned long data) wake_up_interruptible(&msp->wq); } +/* stereo/multilang monitoring */ +static void watch_stereo(struct msp3400c *msp) +{ + LOCK_FLAGS; + + LOCK_I2C_BUS(msp->bus); + if (autodetect_stereo(msp)) { + if (msp->stereo & VIDEO_SOUND_STEREO) + msp3400c_setstereo(msp,VIDEO_SOUND_STEREO); + else if (msp->stereo & VIDEO_SOUND_LANG1) + msp3400c_setstereo(msp,VIDEO_SOUND_LANG1); + else + msp3400c_setstereo(msp,VIDEO_SOUND_MONO); + } + UNLOCK_I2C_BUS(msp->bus); + if (msp->watch_stereo) { + del_timer(&msp->wake_stereo); + msp->wake_stereo.expires = jiffies + 5*HZ; + add_timer(&msp->wake_stereo); + } +} + static int msp3400c_thread(void *data) { struct msp3400c *msp = data; struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; - int newstereo; LOCK_FLAGS; #ifdef __SMP__ @@ -529,7 +642,7 @@ static int msp3400c_thread(void *data) unlock_kernel(); #endif - dprintk("msp3400: thread: start\n"); + printk("msp3400: daemon started\n"); if(msp->notify != NULL) up(msp->notify); @@ -550,48 +663,7 @@ static int msp3400c_thread(void *data) msp->active = 1; if (msp->watch_stereo) { - /* do that stereo/multilang handling */ - LOCK_I2C_BUS(msp->bus); - newstereo = msp->stereo; - switch (msp->mode) { - case MSP_MODE_FM_TERRA: - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18); - dprintk("msp3400: stereo detect register: %d\n",val); - - if (val > 4096) { - newstereo = VIDEO_SOUND_STEREO; - } else if (val < -4096) { - newstereo = VIDEO_SOUND_LANG1; - } else { - newstereo = VIDEO_SOUND_MONO; - } - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23); - switch ((val & 0x1e) >> 1) { - case 0: - case 8: - newstereo = VIDEO_SOUND_STEREO; - break; - default: - newstereo = VIDEO_SOUND_MONO; - break; - } - break; - } - if (msp->stereo != newstereo) { - dprintk("msp3400: watch: stereo %d ==> %d\n", - msp->stereo,newstereo); - msp3400c_setstereo(msp,newstereo); - } - UNLOCK_I2C_BUS(msp->bus); - if (msp->watch_stereo) { - del_timer(&msp->wake_stereo); - msp->wake_stereo.expires = jiffies + 5*HZ; - add_timer(&msp->wake_stereo); - } - + watch_stereo(msp); msp->active = 0; continue; } @@ -599,7 +671,7 @@ static int msp3400c_thread(void *data) restart: LOCK_I2C_BUS(msp->bus); msp3400c_setvolume(msp->bus, 0, 0); - msp3400c_setmode(msp, MSP_MODE_AM_DETECT); + msp3400c_setmode(msp, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; del_timer(&msp->wake_stereo); @@ -626,7 +698,7 @@ static int msp3400c_thread(void *data) val1 = val, max1 = this; dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); } - + /* carrier detect pass #2 -- second (stereo) carrier */ switch (max1) { case 1: /* 5.5 */ @@ -669,12 +741,14 @@ static int msp3400c_thread(void *data) /* B/G FM-stereo */ msp->second = carrier_detect_55[max2].cdo; msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; msp3400c_setstereo(msp, VIDEO_SOUND_MONO); msp->watch_stereo = 1; } else if (max2 == 1 && msp->nicam) { /* B/G NICAM */ msp->second = carrier_detect_55[max2].cdo; msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + msp->nicam_on = 1; msp3400c_setcarrier(msp->bus, msp->second, msp->main); msp->watch_stereo = 1; } else { @@ -685,6 +759,7 @@ static int msp3400c_thread(void *data) /* PAL I NICAM */ msp->second = MSP_CARRIER(6.552); msp3400c_setmode(msp, MSP_MODE_FM_NICAM2); + msp->nicam_on = 1; msp3400c_setcarrier(msp->bus, msp->second, msp->main); msp->watch_stereo = 1; break; @@ -693,12 +768,14 @@ static int msp3400c_thread(void *data) /* D/K FM-stereo */ msp->second = carrier_detect_65[max2].cdo; msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; msp3400c_setstereo(msp, VIDEO_SOUND_MONO); msp->watch_stereo = 1; } else if (max2 == 0 && msp->nicam) { /* D/K NICAM */ msp->second = carrier_detect_65[max2].cdo; msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + msp->nicam_on = 1; msp3400c_setcarrier(msp->bus, msp->second, msp->main); msp->watch_stereo = 1; } else { @@ -710,7 +787,10 @@ static int msp3400c_thread(void *data) no_second: msp->second = carrier_detect_main[max1].cdo; msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp->stereo = VIDEO_SOUND_MONO; + msp3400c_setstereo(msp, VIDEO_SOUND_MONO); break; } @@ -720,7 +800,7 @@ static int msp3400c_thread(void *data) if (msp->watch_stereo) { del_timer(&msp->wake_stereo); - msp->wake_stereo.expires = jiffies + 2*HZ; + msp->wake_stereo.expires = jiffies + 5*HZ; add_timer(&msp->wake_stereo); } @@ -740,7 +820,6 @@ done: return 0; } - #if 0 /* not finished yet */ static int msp3410d_thread(void *data) @@ -1047,11 +1126,6 @@ static int msp3400c_attach(struct i2c_device *device) return -1; } - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setvolume(msp->bus, msp->left, msp->right); - msp3400c_setbass(msp->bus, msp->bass); - msp3400c_settreble(msp->bus, msp->treble); - #if 0 /* this will turn on a 1kHz beep - might be useful for debugging... */ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040); diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index eb7b29aa9ed6..8bd701ad7987 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -1515,7 +1515,7 @@ static void __init i2o_sys_init() { niop = iop->next; #ifdef DRIVERDEBUG - printk(KERN_INFO "Enableing iop%d\n", iop->unit); + printk(KERN_INFO "Enabling iop%d\n", iop->unit); #endif if(i2o_enable_controller(iop)) { @@ -2680,6 +2680,7 @@ EXPORT_SYMBOL(i2o_report_controller_unit); EXPORT_SYMBOL(i2o_activate_controller); EXPORT_SYMBOL(i2o_online_controller); EXPORT_SYMBOL(i2o_get_class_name); +EXPORT_SYMBOL(i2o_status_get); EXPORT_SYMBOL(i2o_query_scalar); EXPORT_SYMBOL(i2o_set_scalar); diff --git a/drivers/net/rclanmtl.c b/drivers/net/rclanmtl.c index 504cd865e006..c1c79247e532 100644 --- a/drivers/net/rclanmtl.c +++ b/drivers/net/rclanmtl.c @@ -741,7 +741,7 @@ RCProcI2OMsgQ(U16 AdapterID) } break; default: - printk("Unknown private I2O msg received: 0x%x\n", + printk("Unknown private I2O msg received: 0x%lx\n", p32[5]); break; } @@ -1216,7 +1216,7 @@ RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) if (!timeout--) { kprintf("Timeout waiting for promiscuous mode from adapter\n"); - kprintf("0x%08.8ulx\n", p32[0]); + kprintf("0x%8.8lx\n", p32[0]); return RC_RTN_NO_LINK_SPEED; } } @@ -1337,7 +1337,7 @@ RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) if (!timeout--) { kprintf("Timeout waiting for promiscuous mode from adapter\n"); - kprintf("0x%08.8ulx\n", p32[0]); + kprintf("0x%8.8lx\n", p32[0]); return RC_RTN_NO_LINK_SPEED; } } @@ -1421,7 +1421,7 @@ RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) if (!timeout--) { kprintf("Timeout waiting for link speed from IOP\n"); - kprintf("0x%08.8ulx\n", p32[0]); + kprintf("0x%8.8lx\n", p32[0]); return RC_RTN_NO_LINK_SPEED; } } diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index b0d8a9ad4d77..ad425f91b56f 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -56,8 +56,10 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; #include #include #include +#include /* for SIOGCM/SIOSCM stuff */ + #include #ifdef SB1000_DEBUG @@ -93,8 +95,6 @@ static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct enet_statistics *sb1000_stats(struct net_device *dev); static int sb1000_close(struct net_device *dev); -/* Plug-n-Play routine */ -static inline unsigned char read_resource_data(void); /* SB1000 hardware routines to be used during open/configuration phases */ static inline void nicedelay(unsigned long usecs); @@ -138,160 +138,132 @@ static inline int sb1000_set_PIDs(const int ioaddr[], const char* name, static inline int sb1000_rx(struct net_device *dev); static inline void sb1000_error_dpc(struct net_device *dev); - -/* Plug-n-Play constants */ -static const int READ_DATA_PORT = 0x203; /* This port number may change!!! */ -static const int ADDRESS_PORT = 0x279; -static const int WRITE_DATA_PORT = 0xa79; - -/* Plug-n-Play read resource mechanism */ -static inline unsigned char -read_resource_data(void) { - /* poll */ - outb(0x05, ADDRESS_PORT); /* Select PnP status register. */ - while (!(inb(READ_DATA_PORT) & 0x1)) ; - /* read resource data */ - outb(0x04, ADDRESS_PORT); /* Select PnP resource data register. */ - return inb(READ_DATA_PORT); -} - /* probe for SB1000 using Plug-n-Play mechanism */ int sb1000_probe(struct net_device *dev) { unsigned short ioaddr[2], irq; - short i, csn; + struct pci_dev *idev=NULL; unsigned int serial_number; + + while(1) + { + /* + * Find the card + */ + + idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('G','I','C'), + ISAPNP_FUNCTION(0x1000), idev); + + /* + * No card + */ + + if(idev==NULL) + return -ENODEV; + + /* + * Bring it online + */ + + idev->prepare(idev); + idev->activate(idev); + + /* + * Ports free ? + */ + + if(!idev->resource[0].start || check_region(idev->resource[0].start, 16)) + continue; + if(!idev->resource[1].start || check_region(idev->resource[1].start, 16)) + continue; + + serial_number = idev->bus->serial; + + ioaddr[0]=idev->resource[0].start; + ioaddr[1]=idev->resource[1].start; + + irq = idev->irq; + + /* check I/O base and IRQ */ + if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) + continue; + if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) + continue; + if (dev->irq != 0 && dev->irq != irq) + continue; + + /* + * Ok set it up. + */ + + + dev->base_addr = ioaddr[0]; + /* rmem_end holds the second I/O address - fv */ + dev->rmem_end = ioaddr[1]; + dev->irq = irq; + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), " + "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, + dev->rmem_end, serial_number, dev->irq); + + dev = init_etherdev(dev, 0); + + /* Make up a SB1000-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct sb1000_private)); + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s", version); + + /* The SB1000-specific entries in the device structure. */ + dev->open = sb1000_open; + dev->do_ioctl = sb1000_dev_ioctl; + dev->hard_start_xmit = sb1000_start_xmit; + dev->stop = sb1000_close; + dev->get_stats = sb1000_stats; + + /* Fill in the generic fields of the device structure. */ + dev->change_mtu = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->header_cache_update= NULL; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = 0; + dev->mtu = 1500; + dev->addr_len = ETH_ALEN; + /* hardware address is 0:0:serial_number */ + dev->dev_addr[0] = 0; + dev->dev_addr[1] = 0; + dev->dev_addr[2] = serial_number >> 24 & 0xff; + dev->dev_addr[3] = serial_number >> 16 & 0xff; + dev->dev_addr[4] = serial_number >> 8 & 0xff; + dev->dev_addr[5] = serial_number >> 0 & 0xff; + dev->tx_queue_len = 0; + + /* New-style flags. */ + dev->flags = IFF_POINTOPOINT|IFF_NOARP; - const unsigned char initiation_key[] = { 0x00, 0x00, 0x6a, 0xb5, 0xda, - 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, - 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, - 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; - const unsigned char sb1000_vendor_ID[] = { - 0x1d, 0x23, 0x10, 0x00 }; /* "GIC1000" */ - - /* Reset the ISA PnP mechanism */ - outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ - outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ - - /* send initiation key */ - for (i = 0; i < sizeof(initiation_key) / sizeof(initiation_key[0]); i++) { - outb(initiation_key[i], ADDRESS_PORT); - } - - /* set card CSN into configuration mode */ - for (csn = 1; csn <= 255; csn++) { - outb(0x03, ADDRESS_PORT); /* Select PnP wake[CSN] register. */ - outb(csn, WRITE_DATA_PORT); /* Wake[CSN] */ - /* check card ID */ - for (i = 0; i < 4; i++) { - if (read_resource_data() != sb1000_vendor_ID[i]) break; - } - if (i == 4) break; - } + /* Lock resources */ - /* SB1000 not found */ - if (csn > 255) { - /* return to WaitForKey state */ - outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ - outb(0x02, WRITE_DATA_PORT);/* Return to WaitForKey state. */ - return -ENODEV; - } + request_region(ioaddr[0], 16, dev->name); + request_region(ioaddr[1], 16, dev->name); - /* found: get serial number and skip checksum */ - serial_number = 0; - for (i = 0; i < 4; i++) { - serial_number |= read_resource_data() << (8 * i); - } - read_resource_data(); - - /* get I/O port base address */ - outb(0x60, ADDRESS_PORT); /* Select PnP I/O port base address 0. */ - ioaddr[0] = inb(READ_DATA_PORT) << 8; - outb(0x61, ADDRESS_PORT); - ioaddr[0] |= inb(READ_DATA_PORT); - outb(0x62, ADDRESS_PORT); /* Select PnP I/O port base address 1. */ - ioaddr[1] = inb(READ_DATA_PORT) << 8; - outb(0x63, ADDRESS_PORT); - ioaddr[1] |= inb(READ_DATA_PORT); - - /* get IRQ */ - outb(0x70, ADDRESS_PORT); /* Select PnP IRQ level select 0. */ - irq = inb(READ_DATA_PORT); - - /* return to WaitForKey state */ - outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ - outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ - - /* check I/O base and IRQ */ - if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) { - return -ENODEV; - } - if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) { - return -ENODEV; - } - if (dev->irq != 0 && dev->irq != irq) { - return -ENODEV; + return 0; } - - dev->base_addr = ioaddr[0]; - /* rmem_end holds the second I/O address - fv */ - dev->rmem_end = ioaddr[1]; - dev->irq = irq; - - if (sb1000_debug > 0) - printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), csn %d, " - "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, - dev->rmem_end, csn, serial_number, dev->irq); - - dev = init_etherdev(dev, 0); - - /* Make up a SB1000-specific-data structure. */ - dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct sb1000_private)); - - if (sb1000_debug > 0) - printk(KERN_NOTICE "%s", version); - - /* The SB1000-specific entries in the device structure. */ - dev->open = sb1000_open; - dev->do_ioctl = sb1000_dev_ioctl; - dev->hard_start_xmit = sb1000_start_xmit; - dev->stop = sb1000_close; - dev->get_stats = sb1000_stats; - - /* Fill in the generic fields of the device structure. */ - dev->change_mtu = NULL; - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->header_cache_update= NULL; - - dev->type = ARPHRD_ETHER; - dev->hard_header_len = 0; - dev->mtu = 1500; - dev->addr_len = ETH_ALEN; - /* hardware address is 0:0:serial_number */ - dev->dev_addr[0] = 0; - dev->dev_addr[1] = 0; - dev->dev_addr[2] = serial_number >> 24 & 0xff; - dev->dev_addr[3] = serial_number >> 16 & 0xff; - dev->dev_addr[4] = serial_number >> 8 & 0xff; - dev->dev_addr[5] = serial_number >> 0 & 0xff; - dev->tx_queue_len = 0; - - /* New-style flags. */ - dev->flags = IFF_POINTOPOINT|IFF_NOARP; - return 0; } /* * SB1000 hardware routines to be used during open/configuration phases */ + const int TimeOutJiffies = (int)(8.75 * HZ); static inline void nicedelay(unsigned long usecs) @@ -1279,6 +1251,8 @@ init_module(void) void cleanup_module(void) { unregister_netdev(&dev_sb1000); + release_region(&dev_sb1000.base_addr, 16); + release_region(&dev_sb1000.rmem_end, 16); kfree_s(dev_sb1000.priv, sizeof(struct sb1000_private)); dev_sb1000.priv = NULL; } diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 13751db71031..53da1d861c65 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -43,7 +43,7 @@ #include #include #include - +#include typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); @@ -234,13 +234,15 @@ static inline void TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) { TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + unsigned long flags; - cli(); + spin_lock_irqsave(&priv->lock, flags); if ( priv->timer.function != NULL ) { + spin_unlock_irqrestore(&priv->lock, flags); return; } priv->timer.function = &TLan_Timer; - sti(); + spin_unlock_irqrestore(&priv->lock, flags); priv->timer.data = (unsigned long) dev; priv->timer.expires = jiffies + ticks; @@ -336,6 +338,8 @@ extern int init_module(void) priv->speed = speed; priv->sa_int = sa_int; priv->debug = debug; + + spin_lock_init(&priv->lock); ether_setup( dev ); @@ -770,6 +774,7 @@ int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLanList *tail_list; u8 *tail_buffer; int pad; + unsigned long flags; if ( ! priv->phyOnline ) { TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name ); @@ -810,7 +815,7 @@ int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_list->buffer[1].address = 0; } - cli(); + spin_lock_irqsave(&priv->lock, flags); tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; @@ -826,7 +831,7 @@ int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); } } - sti(); + spin_unlock_irqrestore(&priv->lock, flags); CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); @@ -870,10 +875,12 @@ void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) u32 host_cmd; u16 host_int; int type; + TLanPrivateInfo *priv; dev = (struct net_device *) dev_id; + priv = (TLanPrivateInfo *) dev->priv; - cli(); + spin_lock(&priv->lock); if ( dev->interrupt ) { printk( "TLAN: Re-entering interrupt handler for %s: %ld.\n" , dev->name, dev->interrupt ); } @@ -892,7 +899,7 @@ void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) } dev->interrupt--; - sti(); + spin_unlock(&priv->lock); } /* TLan_HandleInterrupts */ @@ -1558,6 +1565,7 @@ void TLan_Timer( unsigned long data ) struct net_device *dev = (struct net_device *) data; TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; u32 elapsed; + unsigned long flags; priv->timer.function = NULL; @@ -1581,7 +1589,7 @@ void TLan_Timer( unsigned long data ) TLan_FinishReset( dev ); break; case TLAN_TIMER_ACTIVITY: - cli(); + spin_lock_irqsave(&priv->lock, flags); if ( priv->timer.function == NULL ) { elapsed = jiffies - priv->timerSetAt; if ( elapsed >= TLAN_TIMER_ACT_DELAY ) { @@ -1589,11 +1597,12 @@ void TLan_Timer( unsigned long data ) } else { priv->timer.function = &TLan_Timer; priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; - sti(); + spin_unlock_irqrestore(&priv->lock, flags); add_timer( &priv->timer ); + break; } } - sti(); + spin_unlock_irqrestore(&priv->lock, flags); break; default: break; @@ -2435,16 +2444,19 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) { u8 nack; u16 sio, tmp; - u32 i; + u32 i; int err; int minten; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int irq; + unsigned long flags; err = FALSE; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; if ( dev->interrupt == 0 ) - cli(); + spin_lock_irqsave(&priv->lock, flags); dev->interrupt++; TLan_MiiSync(dev->base_addr); @@ -2494,7 +2506,7 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) dev->interrupt--; if ( dev->interrupt == 0 ) - sti(); + spin_unlock_irqrestore(&priv->lock, flags); return err; @@ -2606,12 +2618,14 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ) { u16 sio; int minten; + unsigned long flags; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; if ( dev->interrupt == 0 ) - cli(); + spin_lock_irqsave(&priv->lock, flags); dev->interrupt++; TLan_MiiSync( dev->base_addr ); @@ -2636,7 +2650,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ) dev->interrupt--; if ( dev->interrupt == 0 ) - sti(); + spin_unlock_irqrestore(&priv->lock, flags); } /* TLan_MiiWriteReg */ @@ -2834,29 +2848,41 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data ) { int err; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + unsigned long flags; + int ret=0; if ( dev->interrupt == 0 ) - cli(); + spin_lock_irqsave(&priv->lock, flags); dev->interrupt++; TLan_EeSendStart( dev->base_addr ); err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK ); if (err) - return 1; + { + ret=1; + goto fail; + } err = TLan_EeSendByte( dev->base_addr, ee_addr, TLAN_EEPROM_ACK ); if (err) - return 2; + { + ret=2; + goto fail; + } TLan_EeSendStart( dev->base_addr ); err = TLan_EeSendByte( dev->base_addr, 0xA1, TLAN_EEPROM_ACK ); if (err) - return 3; + { + ret=3; + goto fail; + } TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP ); - +fail: dev->interrupt--; if ( dev->interrupt == 0 ) - sti(); + spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return ret; } /* TLan_EeReadByte */ diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 8c18dee60c42..7a49663d6351 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -187,6 +187,7 @@ typedef struct tlan_private_tag { u8 tlanRev; u8 tlanFullDuplex; char devName[8]; + spinlock_t lock; } TLanPrivateInfo; diff --git a/drivers/scsi/53c8xx_d.h b/drivers/scsi/53c8xx_d.h index a3c81ffc2255..c90dc2f7800d 100644 --- a/drivers/scsi/53c8xx_d.h +++ b/drivers/scsi/53c8xx_d.h @@ -1,3 +1,4 @@ +/* DO NOT EDIT - Generated automatically by script_asm.pl */ static u32 SCRIPT[] = { /* diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 37e955b2a8b0..6b427ddbc14c 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -304,6 +304,7 @@ int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){ break; } +#ifdef CONFIG_SCSI_G_NCR5380_PORT if (ports) { /* wakeup sequence for the NCR53C400A and DTC3181E*/ @@ -343,7 +344,13 @@ int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){ request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); - +#else + if(check_mem_region(overrides[current_override].NCR5380_map_name, + NCR5380_region_size)) + continue; + request_mem_region(overrides[current_override].NCR5380_map_name, + NCR5380_region_size, "ncr5380"); +#endif instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; @@ -393,7 +400,11 @@ int generic_NCR5380_release_resources(struct Scsi_Host * instance) NCR5380_setup(instance); +#ifdef CONFIG_SCSI_G_NCR5380_PORT release_region(instance->NCR5380_instance_name, NCR5380_region_size); +#else + release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); +#endif if (instance->irq != IRQ_NONE) free_irq(instance->irq, NULL); diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h index 32894de45bcb..6897c91c19a7 100644 --- a/drivers/scsi/g_NCR5380.h +++ b/drivers/scsi/g_NCR5380.h @@ -123,7 +123,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng #define NCR5380_map_config memory -#define NCR5380_map_type volatile unsigned char* +#define NCR5380_map_type unsigned long #define NCR5380_map_name base diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 28102c0b1e51..006a2aff96be 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -602,11 +602,14 @@ int idescsi_detect (Scsi_Host_Template *host_template) { struct Scsi_Host *host; int id; + int last_lun = 0; host_template->proc_name = "ide-scsi"; host = scsi_register(host_template, 0); - for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); + for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++) + last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun); host->max_id = id; + host->max_lun = last_lun + 1; host->can_queue = host->cmd_per_lun * id; return 1; } diff --git a/drivers/scsi/sim710_d.h b/drivers/scsi/sim710_d.h index b6305f806d92..2a2a0d91bfe3 100644 --- a/drivers/scsi/sim710_d.h +++ b/drivers/scsi/sim710_d.h @@ -1,3 +1,4 @@ +/* DO NOT EDIT - Generated automatically by script_asm.pl */ static u32 SCRIPT[] = { /* diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 6b1b2d13fcb8..8dc338aec28d 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -14,6 +14,7 @@ * * OPTi 82C928 MAD16 (replaced by C929) * OAK OTI-601D Mozart + * OAK OTI-605 Mozart (later version with MPU401 Midi) * OPTi 82C929 MAD16 Pro * OPTi 82C930 * OPTi 82C924 @@ -22,8 +23,9 @@ * connect some other components (OPL-[234] and a WSS compatible codec) * to the PC bus and perform I/O, DMA and IRQ address decoding. There is * also a UART for the MPU-401 mode (not 82C928/Mozart). - * The Mozart chip appears to be compatible with the 82C928 (can anybody - * confirm this?). + * The Mozart chip appears to be compatible with the 82C928, although later + * issues of the card, using the OTI-605 chip, have an MPU-401 compatable Midi + * port. This port is configured differently to that of the OPTi audio chips. * * NOTE! If you want to set CD-ROM address and/or joystick enable, define * MAD16_CONF in local.h as combination of the following bits: @@ -65,8 +67,11 @@ * Improved debugging support. 16-May-1998 * Fixed bug. 16-Jun-1998 * - * Torsten Duwe Made Opti924 PnP support non-destructive - * 1998-12-23 + * Torsten Duwe Made Opti924 PnP support non-destructive + * 23-Dec-1998 + * + * Paul Grayson Added support for Midi on later Mozart cards. + * 25-Nov-1999 */ #include "sound_config.h" @@ -719,29 +724,24 @@ void attach_mad16(struct address_info *hw_config) void attach_mad16_mpu(struct address_info *hw_config) { - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { #if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) - if (mad_read(MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; - hw_config->name = "Mad16/Mozart"; - sb_dsp_init(hw_config); + hw_config->name = "Mad16/Mozart"; + sb_dsp_init(hw_config); + return; #endif - return; - } -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (!already_initialized) return; hw_config->driver_use_1 = SB_MIDI_ONLY; hw_config->name = "Mad16/Mozart"; attach_uart401(hw_config); -#endif } int probe_mad16_mpu(struct address_info *hw_config) @@ -802,7 +802,60 @@ int probe_mad16_mpu(struct address_info *hw_config) hw_config->driver_use_1 = SB_MIDI_ONLY; return sb_dsp_detect(hw_config, 0, 0); #else - return 0; + /* assuming all later Mozart cards are identified as + * either 82C928 or Mozart. If so, following code attempts + * to set MPU register. TODO - add probing + */ + + + unsigned char tmp; + + tmp = mad_read(MC8_PORT); + + switch (hw_config->irq) + { + case 5: + tmp |= 0x08; + break; + case 7: + tmp |= 0x10; + break; + case 9: + tmp |= 0x18; + break; + case 10: + tmp |= 0x20; + break; + case 11: + tmp |= 0x28; + break; + default: + printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n"); + return 0; + } + + switch (hw_config->io_base) + { + case 0x300: + tmp |= 0x01; + break; + case 0x310: + tmp |= 0x03; + break; + case 0x320: + tmp |= 0x05; + break; + case 0x330: + tmp |= 0x07; + break; + default: + printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n"); + return 0; + } + + mad_write(MC8_PORT, tmp); /* write MPU port parameters */ + + return probe_uart401(hw_config); #endif } tmp = mad_read(MC6_PORT) & 0x83; diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c index e4664b06abda..b6c9f0aeeb5d 100644 --- a/drivers/sound/sb_ess.c +++ b/drivers/sound/sb_ess.c @@ -10,29 +10,29 @@ * * History: * - * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per + * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per * fokkensr@vertis.nl input basis. - * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, + * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, * ES1868, ES1869 and ES1878. Could be used for * specific handling in the future. All except * ES1887 and ES1888 and ES688 are handled like * ES1688. - * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now + * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now * have the "Dec 20" support + RECLEV - * (Jan 2 1999): Preparation for Full Duplex. This means + * (Jan 2 1999): Preparation for Full Duplex. This means * Audio 2 is now used for playback when dma16 * is specified. The next step would be to use * Audio 1 and Audio 2 at the same time. - * (Jan 9 1999): Put all ESS stuff into sb_ess.[ch], this + * (Jan 9 1999): Put all ESS stuff into sb_ess.[ch], this * includes both the ESS stuff that has been in * sb_*[ch] before I touched it and the ESS support * I added later - * (Jan 23 1999): Full Duplex seems to work. I wrote a small + * (Jan 23 1999): Full Duplex seems to work. I wrote a small * test proggy which works OK. Haven't found * any applications to test it though. So why did * I bother to create it anyway?? :) Just for * fun. - * (May 2 1999): I tried to be too smart by "introducing" + * (May 2 1999): I tried to be too smart by "introducing" * ess_calc_best_speed (). The idea was that two * dividers could be used to setup a samplerate, * ess_calc_best_speed () would choose the best. @@ -40,10 +40,12 @@ * recording problems for high samplerates. I * fixed this by removing ess_calc_best_speed () * and just doing what the documentation says. - * Andy Sloane (June 4 1999): Stole some code from ALSA to fix the playback + * Andy Sloane (Jun 4 1999): Stole some code from ALSA to fix the playback * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. * 1879's were previously ignored by this driver; * added (untested) support for those. + * Cvetan Ivanov (Oct 27 1999): Fixed ess_dsp_init to call ess_set_dma_hw for + * zezo@inet.bg _ALL_ ESS models, not only ES1887 * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This @@ -52,7 +54,7 @@ * - RECLEV support for ES1688 and later * - 6 bits playback level support chips later than ES1688 * - Recording level support on a per-device basis for ES1887 - * - Full-Duplex for ES1887 (under development) + * - Full-Duplex for ES1887 * * Full duplex is enabled by specifying dma16. While the normal dma must * be one of 0, 1 or 3, dma16 can be one of 0, 1, 3 or 5. DMA 5 is a 16 bit @@ -100,7 +102,7 @@ * of writing 0x00 to 0x7f (which should be done by reset): The ES1887 moves * into ES1888 mode. This means that it claims IRQ 11, which happens to be my * ISDN adapter. Needless to say it no longer worked. I now understand why - * after rebooting 0x7f already was 0x05, the value of my choise: the BIOS + * after rebooting 0x7f already was 0x05, the value of my choice: the BIOS * did it. * * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is decribed @@ -1200,10 +1202,10 @@ FKS_test (devc); /* AAS: info stolen from ALSA: these boards have different clocks */ switch(devc->submodel) { -/* APPARENTLY NOT 1869 +/* APPARENTLY NOT 1869 AND 1887 case SUBMDL_ES1869: -*/ case SUBMDL_ES1887: +*/ case SUBMDL_ES1888: devc->caps |= SB_CAP_ES18XX_RATE; break; @@ -1304,6 +1306,13 @@ printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n" */ int ess_dsp_init (sb_devc *devc, struct address_info *hw_config) { + /* + * Caller also checks this, but anyway + */ + if (devc->model != MDL_ESS) { + printk (KERN_INFO "ess_dsp_init for non ESS chip\n"); + return 1; + } /* * This for ES1887 to run Full Duplex. Actually ES1888 * is allowed to do so too. I have no idea yet if this @@ -1324,15 +1333,12 @@ int ess_dsp_init (sb_devc *devc, struct address_info *hw_config) if (devc->dma8 != devc->dma16 && devc->dma16 != -1) { devc->duplex = 1; } - - if (!ess_set_dma_hw (devc)) { - free_irq(devc->irq, devc); - return 0; - } - return 1; - } else { - return -1; } + if (!ess_set_dma_hw (devc)) { + free_irq(devc->irq, devc); + return 0; + } + return 1; } /**************************************************************************** diff --git a/fs/Config.in b/fs/Config.in index 3bfc3172d4e8..b8b7784f03da 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -88,6 +88,10 @@ if [ "$CONFIG_INET" = "y" ]; then if [ "$CONFIG_NFSD" != "n" ]; then bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3 + fi + if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_tristate CONFIG_SUNRPC y define_tristate CONFIG_LOCKD y diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 4d8025650cc1..152a8b0b218f 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile @@ -11,6 +11,9 @@ O_TARGET := nfsd.o O_OBJS := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o \ stats.o +ifdef CONFIG_NFSD_V3 + O_OBJS += nfs3proc.o nfs3xdr.o +endif M_OBJS := $(O_TARGET) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 5396a784fb71..9daf3a8a09dd 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -3,7 +3,7 @@ * * Process version 3 NFS requests. * - * Copyright (C) 1996 Olaf Kirch + * Copyright (C) 1996, 1997, 1998 Olaf Kirch */ #include @@ -18,19 +18,32 @@ #include #include #include +#include #include #include #include #include - -typedef struct svc_rqst svc_rqst; -typedef struct svc_buf svc_buf; +#include #define NFSDDBG_FACILITY NFSDDBG_PROC #define RETURN(st) { resp->status = (st); return (st); } +static int nfs3_ftypes[] = { + 0, /* NF3NON */ + S_IFREG, /* NF3REG */ + S_IFDIR, /* NF3DIR */ + S_IFBLK, /* NF3BLK */ + S_IFCHR, /* NF3CHR */ + S_IFLNK, /* NF3LNK */ + S_IFIFO, /* NF3FIFO */ + S_IFSOCK, /* NF3SOCK */ +}; + +/* + * Reserve room in the send buffer + */ static void svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr) { @@ -38,6 +51,9 @@ svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr) *len = buf->buflen - buf->len - nr; } +/* + * NULL call. + */ static int nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { @@ -46,7 +62,6 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get a file's attributes - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, @@ -54,18 +69,17 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, { int nfserr; - dprintk("nfsd: GETATTR %x/%ld\n", + dprintk("nfsd: GETATTR(3) %x/%ld\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh)); + (long)SVCFH_INO(&argp->fh)); - resp->fh = argp->fh; + fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); RETURN(nfserr); } /* * Set a file's attributes - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, @@ -73,31 +87,30 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, { int nfserr; - dprintk("nfsd: SETATTR %x/%ld\n", + dprintk("nfsd: SETATTR(3) %x/%ld\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh)); + (long)SVCFH_INO(&argp->fh)); - resp->fh = argp->fh; + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs); RETURN(nfserr); } /* * Look up a path name component - * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put */ static int nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, - struct nfsd3_lookupres *resp) + struct nfsd3_diropres *resp) { int nfserr; - dprintk("nfsd: LOOKUP %x/%ld %s\n", + dprintk("nfsd: LOOKUP(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), + (long)SVCFH_INO(&argp->fh), argp->name); - resp->dirfh = argp->fh; + fh_copy(&resp->dirfh, &argp->fh); nfserr = nfsd_lookup(rqstp, &resp->dirfh, argp->name, argp->len, @@ -109,12 +122,20 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, * Check file access */ static int -nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, +nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { - /* to be done */ - resp->fh = argp->fh; - return nfserr_notsupp; + int nfserr; + + dprintk("nfsd: ACCESS(3) %x/%ld 0x%x\n", + SVCFH_DEV(&argp->fh), + (long)SVCFH_INO(&argp->fh), + argp->access); + + fh_copy(&resp->fh, &argp->fh); + resp->access = argp->access; + nfserr = nfsd_access(rqstp, &resp->fh, &resp->access); + RETURN(nfserr); } /* @@ -127,23 +148,23 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, u32 *path; int dummy, nfserr; - dprintk("nfsd: READLINK %x/%ld\n", + dprintk("nfsd: READLINK(3) %x/%ld\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh)); + (long)SVCFH_INO(&argp->fh)); /* Reserve room for status, post_op_attr, and path length */ - svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, 1 + 22 + 1); + svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, + 1 + NFS3_POST_OP_ATTR_WORDS + 1); /* Read the symlink. */ + fh_copy(&resp->fh, &argp->fh); resp->len = NFS3_MAXPATHLEN; - nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len); - fh_put(&argp->fh); + nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len); RETURN(nfserr); } /* * Read a portion of a file. - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, @@ -152,9 +173,9 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, u32 * buffer; int nfserr, avail; - dprintk("nfsd: READ %x/%ld %lu bytes at %lu\n", + dprintk("nfsd: READ(3) %x/%ld %lu bytes at %lu\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), + (long)SVCFH_INO(&argp->fh), (unsigned long) argp->count, (unsigned long) argp->offset); @@ -162,30 +183,29 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) * + 1 (xdr opaque byte count) = 26 */ - svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, 26); - - if ((avail << 2) < argp->count) { - printk(KERN_NOTICE - "oversized read request from %08lx:%d (%d bytes)\n", - ntohl(rqstp->rq_addr.sin_addr.s_addr), - ntohs(rqstp->rq_addr.sin_port), - argp->count); - argp->count = avail; - } + svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, + 1 + NFS3_POST_OP_ATTR_WORDS + 3); resp->count = argp->count; - resp->fh = argp->fh; + if ((avail << 2) < resp->count) + resp->count = avail << 2; + + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_read(rqstp, &resp->fh, argp->offset, (char *) buffer, &resp->count); + if (nfserr == 0) { + struct inode *inode = resp->fh.fh_dentry->d_inode; + + resp->eof = (argp->offset + resp->count) >= inode->i_size; + } RETURN(nfserr); } /* * Write data to a file - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, @@ -193,19 +213,21 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, { int nfserr; - dprintk("nfsd: WRITE %x/%ld %d bytes at %ld\n", + dprintk("nfsd: WRITE(3) %x/%ld %d bytes at %ld%s\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), + (long)SVCFH_INO(&argp->fh), argp->len, - (unsigned long) argp->offset); + (unsigned long) argp->offset, + argp->stable? " stable" : ""); - resp->fh = argp->fh; + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, argp->data, argp->len, argp->stable); resp->committed = argp->stable; + resp->count = argp->count; RETURN(nfserr); } @@ -213,20 +235,18 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, * With NFSv3, CREATE processing is a lot easier than with NFSv2. * At least in theory; we'll see how it fares in practice when the * first reports about SunOS compatibility problems start to pour in... - * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put */ static int nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, - struct nfsd3_createres *resp) + struct nfsd3_diropres *resp) { svc_fh *dirfhp, *newfhp = NULL; struct iattr *attr; - int mode; u32 nfserr; - dprintk("nfsd: CREATE %x/%ld %s\n", + dprintk("nfsd: CREATE(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), + (long)SVCFH_INO(&argp->fh), argp->name); dirfhp = fh_copy(&resp->dirfh, &argp->fh); @@ -243,303 +263,427 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, if (!(attr->ia_valid & ATTR_MODE)) { attr->ia_valid |= ATTR_MODE; attr->ia_mode = S_IFREG; + } else { + attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG; } - mode = attr->ia_mode & ~S_IFMT; /* Now create the file and set attributes */ - nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len, - attr, S_IFREG, 0, newfhp); + nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, + attr, newfhp, + argp->createmode, argp->verf); + + RETURN(nfserr); +} + +/* + * Make directory. This operation is not idempotent. + */ +static int +nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, + struct nfsd3_diropres *resp) +{ + int nfserr; + + dprintk("nfsd: MKDIR(3) %x/%ld %s\n", + SVCFH_DEV(&argp->fh), + (long)SVCFH_INO(&argp->fh), + argp->name); + + argp->attrs.ia_valid &= ~ATTR_SIZE; + fh_copy(&resp->dirfh, &argp->fh); + fh_init(&resp->fh); + nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &argp->attrs, S_IFDIR, 0, &resp->fh); RETURN(nfserr); } -/* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */ +static int +nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, + struct nfsd3_diropres *resp) +{ + int nfserr; + + dprintk("nfsd: SYMLINK(3) %x/%ld %s -> %s\n", + SVCFH_DEV(&argp->ffh), + (long)SVCFH_INO(&argp->ffh), + argp->fname, argp->tname); + + fh_copy(&resp->dirfh, &argp->ffh); + fh_init(&resp->fh); + nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, + argp->tname, argp->tlen, + &resp->fh, &argp->attrs); + RETURN(nfserr); +} + +/* + * Make socket/fifo/device. + */ +static int +nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, + struct nfsd3_diropres *resp) +{ + int nfserr, type; + dev_t rdev = 0; + + dprintk("nfsd: MKNOD(3) %x/%ld %s\n", + SVCFH_DEV(&argp->fh), + (long)SVCFH_INO(&argp->fh), + argp->name); + + fh_copy(&resp->dirfh, &argp->fh); + fh_init(&resp->fh); + + if (argp->ftype == 0 || argp->ftype >= NF3BAD) + return nfserr_inval; + if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) { + if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV) + || (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV) + || argp->minor > 0xFF) + return nfserr_inval; + rdev = ((argp->major) << 8) | (argp->minor); + } else + if (argp->ftype != NF3SOCK || argp->ftype != NF3FIFO) + return nfserr_inval; + + type = nfs3_ftypes[argp->ftype]; + nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &argp->attrs, type, rdev, &resp->fh); + + RETURN(nfserr); +} + +/* + * Remove file/fifo/socket etc. + */ static int nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { int nfserr; - dprintk("nfsd: REMOVE %x/%ld %s\n", + dprintk("nfsd: REMOVE(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), + (long)SVCFH_INO(&argp->fh), argp->name); - /* Is this correct?? */ - fh_copy(&resp->fh, &argp->fh); - /* Unlink. -S_IFDIR means file must not be a directory */ + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); - /* - * N.B. Should be an fh_put here ... nfsd3_proc_rmdir has one, - * or else as an xdr release function - */ - fh_put(&resp->fh); + RETURN(nfserr); +} + +/* + * Remove a directory + */ +static int +nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, + struct nfsd3_attrstat *resp) +{ + int nfserr; + + dprintk("nfsd: RMDIR(3) %x/%ld %s\n", + SVCFH_DEV(&argp->fh), + (long)SVCFH_INO(&argp->fh), + argp->name); + + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); RETURN(nfserr); } static int nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, - void *resp) + struct nfsd3_renameres *resp) { int nfserr; - dprintk("nfsd: RENAME %x/%ld %s -> %x/%ld %s\n", + dprintk("nfsd: RENAME(3) %x/%ld %s -> %x/%ld %s\n", SVCFH_DEV(&argp->ffh), - SVCFH_INO(&argp->ffh), + (long)SVCFH_INO(&argp->ffh), argp->fname, SVCFH_DEV(&argp->tfh), - SVCFH_INO(&argp->tfh), + (long)SVCFH_INO(&argp->tfh), argp->tname); - nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, - &argp->tfh, argp->tname, argp->tlen); - fh_put(&argp->ffh); - fh_put(&argp->tfh); + fh_copy(&resp->ffh, &argp->ffh); + fh_copy(&resp->tfh, &argp->tfh); + nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, + &resp->tfh, argp->tname, argp->tlen); RETURN(nfserr); } static int nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, - void *resp) + struct nfsd3_linkres *resp) { int nfserr; - dprintk("nfsd: LINK %x/%ld -> %x/%ld %s\n", + dprintk("nfsd: LINK(3) %x/%ld -> %x/%ld %s\n", SVCFH_DEV(&argp->ffh), - SVCFH_INO(&argp->ffh), + (long)SVCFH_INO(&argp->ffh), SVCFH_DEV(&argp->tfh), - SVCFH_INO(&argp->tfh), + (long)SVCFH_INO(&argp->tfh), argp->tname); - nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, - &argp->ffh); - fh_put(&argp->ffh); - fh_put(&argp->tfh); + fh_copy(&resp->fh, &argp->ffh); + fh_copy(&resp->tfh, &argp->tfh); + nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, + &resp->fh); RETURN(nfserr); } +/* + * Read a portion of a directory. + */ static int -nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, - void *resp) +nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, + struct nfsd3_readdirres *resp) { - struct svc_fh newfh; - int nfserr; + u32 * buffer; + int nfserr, count; + unsigned int want; - dprintk("nfsd: SYMLINK %x/%ld %s -> %s\n", - SVCFH_DEV(&argp->ffh), - SVCFH_INO(&argp->ffh), - argp->fname, argp->tname); + dprintk("nfsd: READDIR(3) %x/%ld %d bytes at %d\n", + SVCFH_DEV(&argp->fh), + (long)SVCFH_INO(&argp->fh), + argp->count, (u32) argp->cookie); - memset(&newfh, 0, sizeof(newfh)); + /* Reserve buffer space for status, attributes and verifier */ + svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, + 1 + NFS3_POST_OP_ATTR_WORDS + 2); - /* - * Create the link, look up new file and set attrs. - */ - nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, - argp->tname, argp->tlen, - &newfh); - if (!nfserr) { - argp->attrs.ia_valid &= ~ATTR_SIZE; - nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs); - } + /* Make sure we've room for the NULL ptr & eof flag, and shrink to + * client read size */ + if ((count -= 2) > (want = (argp->count >> 2) - 2)) + count = want; + + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, + nfs3svc_encode_entry, + buffer, &count, argp->verf); + memcpy(resp->verf, argp->verf, 8); + resp->count = count; - fh_put(&argp->ffh); - fh_put(&newfh); RETURN(nfserr); } /* - * Make directory. This operation is not idempotent. - * N.B. After this call resp->fh needs an fh_put + * Read a portion of a directory, including file handles and attrs. + * For now, we choose to ignore the dircount parameter. */ static int -nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, - struct nfsd3_diropres *resp) +nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, + struct nfsd3_readdirres *resp) { - int nfserr; + u32 * buffer; + int nfserr, count, want; - dprintk("nfsd: MKDIR %x/%ld %s\n", + dprintk("nfsd: READDIR+(3) %x/%ld %d bytes at %d\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), - argp->name); + (long)SVCFH_INO(&argp->fh), + argp->count, (u32) argp->cookie); + + /* Reserve buffer space for status, attributes and verifier */ + svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, + 1 + NFS3_POST_OP_ATTR_WORDS + 2); + + /* Make sure we've room for the NULL ptr & eof flag, and shrink to + * client read size */ + if ((count -= 2) > (want = argp->count >> 2)) + count = want; + + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, + nfs3svc_encode_entry_plus, + buffer, &count, argp->verf); + memcpy(resp->verf, argp->verf, 8); + resp->count = count; - argp->attrs.ia_valid &= ~ATTR_SIZE; - nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, - &argp->attrs, S_IFDIR, 0, &resp->fh); - fh_put(&argp->fh); RETURN(nfserr); } /* - * Remove a directory + * Get file system stats */ static int -nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, - void *resp) +nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, + struct nfsd3_fsstatres *resp) { int nfserr; - dprintk("nfsd: RMDIR %x/%ld %s\n", + dprintk("nfsd: FSSTAT(3) %x/%ld\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), - argp->name); + (long)SVCFH_INO(&argp->fh)); - nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len); + nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); fh_put(&argp->fh); RETURN(nfserr); } /* - * Read a portion of a directory. + * Get file system info */ static int -nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, - struct nfsd3_readdirres *resp) +nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, + struct nfsd3_fsinfores *resp) { - u32 * buffer; - int nfserr, count; + int nfserr; - dprintk("nfsd: READDIR %x/%ld %d bytes at %d\n", + dprintk("nfsd: FSINFO(3) %x/%ld\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh), - argp->count, argp->cookie); + (long)SVCFH_INO(&argp->fh)); + + resp->f_rtmax = NFSSVC_MAXBLKSIZE; + resp->f_rtpref = NFSSVC_MAXBLKSIZE; + resp->f_rtmult = PAGE_SIZE; + resp->f_wtmax = NFSSVC_MAXBLKSIZE; + resp->f_wtpref = NFSSVC_MAXBLKSIZE; + resp->f_wtmult = PAGE_SIZE; + resp->f_dtpref = PAGE_SIZE; + resp->f_maxfilesize = ~(u32) 0; + resp->f_properties = NFS3_FSF_DEFAULT; + + nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); + + /* Check special features of the file system. May request + * different read/write sizes for file systems known to have + * problems with large blocks */ + if (nfserr == 0) { + struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; + + /* Note that we don't care for remote fs's here */ + if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) { + resp->f_properties = NFS3_FSF_BILLYBOY; + } + } - /* Reserve buffer space for status */ - svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, 1); + fh_put(&argp->fh); + RETURN(nfserr); +} - /* Make sure we've room for the NULL ptr & eof flag, and shrink to - * client read size */ - if ((count -= 8) > argp->count) - count = argp->count; +/* + * Get pathconf info for the specified file + */ +static int +nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, + struct nfsd3_pathconfres *resp) +{ + int nfserr; - /* Read directory and encode entries on the fly */ - nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, - nfssvc_encode_entry, - buffer, &count); - resp->count = count; + dprintk("nfsd: PATHCONF(3) %x/%ld\n", + SVCFH_DEV(&argp->fh), + (long)SVCFH_INO(&argp->fh)); + + /* Set default pathconf */ + resp->p_link_max = 255; /* at least */ + resp->p_name_max = 255; /* at least */ + resp->p_no_trunc = 0; + resp->p_chown_restricted = 1; + resp->p_case_insensitive = 0; + resp->p_case_preserving = 1; + + nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); + + if (nfserr == 0) { + struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; + + /* Note that we don't care for remote fs's here */ + switch (sb->s_magic) { + case EXT2_SUPER_MAGIC: + resp->p_link_max = EXT2_LINK_MAX; + resp->p_name_max = EXT2_NAME_LEN; + break; + case 0x4d44: /* MSDOS_SUPER_MAGIC */ + resp->p_case_insensitive = 1; + resp->p_case_preserving = 0; + break; + } + } fh_put(&argp->fh); RETURN(nfserr); } + /* - * Get file system info + * Commit a file (range) to stable storage. */ static int -nfsd3_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, - struct nfsd3_statfsres *resp) +nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, + struct nfsd3_commitres *resp) { int nfserr; - dprintk("nfsd: STATFS %x/%ld\n", + dprintk("nfsd: COMMIT(3) %x/%ld %d@%ld\n", SVCFH_DEV(&argp->fh), - SVCFH_INO(&argp->fh)); + (long)SVCFH_INO(&argp->fh), + argp->count, + (unsigned long) argp->offset); + + if (argp->offset > NFS_OFFSET_MAX) + return nfserr_inval; + + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count); - nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); - fh_put(&argp->fh); RETURN(nfserr); } + /* - * NFSv2 Server procedures. + * NFSv3 Server procedures. * Only the results of non-idempotent operations are cached. */ -#define nfsd3_proc_none NULL -#define nfssvc_encode_void NULL -#define nfssvc_decode_void NULL -#define nfssvc_release_void NULL -struct nfsd3_void { int dummy; }; +#define nfs3svc_decode_voidargs NULL +#define nfs3svc_release_void NULL +#define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle +#define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat +#define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat +#define nfsd3_mkdirargs nfsd3_createargs +#define nfsd3_readdirplusargs nfsd3_readdirargs +#define nfsd3_fhandleargs nfsd_fhandle +#define nfsd3_fhandleres nfsd3_attrstat +#define nfsd3_attrstatres nfsd3_attrstat +#define nfsd3_wccstatres nfsd3_attrstat +#define nfsd3_createres nfsd3_diropres +#define nfsd3_voidres nfsd3_voidargs +struct nfsd3_voidargs { int dummy; }; #define PROC(name, argt, rest, relt, cache) \ - { (svc_procfunc) nfsd3_proc_##name, \ - (kxdrproc_t) nfssvc_decode_##argt, \ - (kxdrproc_t) nfssvc_encode_##rest, \ - (kxdrproc_t) nfssvc_release_##relt, \ - sizeof(struct nfsd3_##argt), \ - sizeof(struct nfsd3_##rest), \ - 0, \ - cache \ + { (svc_procfunc) nfsd3_proc_##name, \ + (kxdrproc_t) nfs3svc_decode_##argt##args, \ + (kxdrproc_t) nfs3svc_encode_##rest##res, \ + (kxdrproc_t) nfs3svc_release_##relt, \ + sizeof(struct nfsd3_##argt##args), \ + sizeof(struct nfsd3_##rest##res), \ + 0, \ + cache \ } -struct svc_procedure nfsd3_procedures2[18] = { +struct svc_procedure nfsd_procedures3[22] = { PROC(null, void, void, void, RC_NOCACHE), PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE), - PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF), - PROC(none, void, void, void, RC_NOCACHE), - PROC(lookup, diropargs, diropres, fhandle2,RC_NOCACHE), - PROC(readlink, fhandle, readlinkres, void, RC_NOCACHE), - PROC(read, readargs, readres, fhandle, RC_NOCACHE), - PROC(none, void, void, void, RC_NOCACHE), - PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF), - PROC(create, createargs, diropres, fhandle2,RC_REPLBUFF), - PROC(remove, diropargs, void,/* ??*/ void, RC_REPLSTAT), - PROC(rename, renameargs, void, void, RC_REPLSTAT), - PROC(link, linkargs, void, void, RC_REPLSTAT), - PROC(symlink, symlinkargs, void, void, RC_REPLSTAT), - PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF), - PROC(rmdir, diropargs, void, void, RC_REPLSTAT), - PROC(readdir, readdirargs, readdirres, void, RC_REPLSTAT), - PROC(statfs, fhandle, statfsres, void, RC_NOCACHE), + PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF), + PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE), + PROC(access, access, access, fhandle, RC_NOCACHE), + PROC(readlink, fhandle, readlink, fhandle, RC_NOCACHE), + PROC(read, read, read, fhandle, RC_NOCACHE), + PROC(write, write, write, fhandle, RC_REPLBUFF), + PROC(create, create, create, fhandle2, RC_REPLBUFF), + PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF), + PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF), + PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF), + PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF), + PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF), + PROC(rename, rename, rename, fhandle, RC_REPLBUFF), + PROC(link, link, link, fhandle2, RC_REPLBUFF), + PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE), + PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE), + PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE), + PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE), + PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE), + PROC(commit, commit, commit, fhandle, RC_NOCACHE) }; - - -/* - * Map errnos to NFS errnos. - */ -int -nfserrno (int errno) -{ - static struct { - int nfserr; - int syserr; - } nfs_errtbl[] = { - { NFS_OK, 0 }, - { NFSERR_PERM, EPERM }, - { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, EIO }, - { NFSERR_NXIO, ENXIO }, - { NFSERR_ACCES, EACCES }, - { NFSERR_EXIST, EEXIST }, - { NFSERR_NODEV, ENODEV }, - { NFSERR_NOTDIR, ENOTDIR }, - { NFSERR_ISDIR, EISDIR }, - { NFSERR_INVAL, EINVAL }, - { NFSERR_FBIG, EFBIG }, - { NFSERR_NOSPC, ENOSPC }, - { NFSERR_ROFS, EROFS }, - { NFSERR_NAMETOOLONG, ENAMETOOLONG }, - { NFSERR_NOTEMPTY, ENOTEMPTY }, -#ifdef EDQUOT - { NFSERR_DQUOT, EDQUOT }, -#endif - { NFSERR_STALE, ESTALE }, - { NFSERR_WFLUSH, EIO }, - { -1, EIO } - }; - int i; - - for (i = 0; nfs_errtbl[i].nfserr != -1; i++) { - if (nfs_errtbl[i].syserr == errno) - return htonl (nfs_errtbl[i].nfserr); - } - printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno); - return nfserr_io; -} - -#if 0 -static void -nfsd3_dump(char *tag, u32 *buf, int len) -{ - int i; - - printk(KERN_NOTICE - "nfsd: %s (%d words)\n", tag, len); - - for (i = 0; i < len && i < 32; i += 8) - printk(KERN_NOTICE - " %08lx %08lx %08lx %08lx" - " %08lx %08lx %08lx %08lx\n", - buf[i], buf[i+1], buf[i+2], buf[i+3], - buf[i+4], buf[i+5], buf[i+6], buf[i+7]); -} -#endif diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 31a5ef88795d..95e8e84243e7 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -3,7 +3,7 @@ * * XDR support for nfsd/protocol version 3. * - * Copyright (C) 1995, 1996 Olaf Kirch + * Copyright (C) 1995, 1996, 1997 Olaf Kirch */ #include @@ -17,15 +17,15 @@ #define NFSDDBG_FACILITY NFSDDBG_XDR -u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio, - nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir, - nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs, - nfserr_nametoolong, nfserr_dquot, nfserr_stale; - #ifdef NFSD_OPTIMIZE_SPACE # define inline #endif +/* + * Size of encoded NFS3 file handle, in words + */ +#define NFS3_FHANDLE_WORDS (1 + XDR_QUADLEN(sizeof(struct knfs_fh))) + /* * Mapping of S_IF* types to NFS file types */ @@ -36,48 +36,9 @@ static u32 nfs3_ftypes[] = { NF3SOCK, NF3BAD, NF3LNK, NF3BAD, }; -/* - * Initialization of NFS status variables - */ -void -nfs3xdr_init(void) -{ - static int inited = 0; - - if (inited) - return; - - nfs_ok = htonl(NFS_OK); - nfserr_perm = htonl(NFSERR_PERM); - nfserr_noent = htonl(NFSERR_NOENT); - nfserr_io = htonl(NFSERR_IO); - nfserr_nxio = htonl(NFSERR_NXIO); - nfserr_acces = htonl(NFSERR_ACCES); - nfserr_exist = htonl(NFSERR_EXIST); - nfserr_nodev = htonl(NFSERR_NODEV); - nfserr_notdir = htonl(NFSERR_NOTDIR); - nfserr_isdir = htonl(NFSERR_ISDIR); - nfserr_fbig = htonl(NFSERR_FBIG); - nfserr_nospc = htonl(NFSERR_NOSPC); - nfserr_rofs = htonl(NFSERR_ROFS); - nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG); - nfserr_dquot = htonl(NFSERR_DQUOT); - nfserr_stale = htonl(NFSERR_STALE); - - inited = 1; -} - /* * XDR functions for basic NFS types */ -static inline u32 * -enc64(u32 *p, u64 val) -{ - *p++ = (val >> 32); - *p++ = (val & 0xffffffff); - return p; -} - static inline u32 * dec64(u32 *p, u64 *valp) { @@ -103,13 +64,10 @@ decode_time3(u32 *p, time_t *secp) static inline u32 * decode_fh(u32 *p, struct svc_fh *fhp) { - if (*p++ != sizeof(struct knfs_fh)) + if (ntohl(*p++) != sizeof(struct knfs_fh)) return NULL; memcpy(&fhp->fh_handle, p, sizeof(struct knfs_fh)); - fhp->fh_inode = NULL; - fhp->fh_export = NULL; - return p + (sizeof(struct knfs_fh) >> 2); } @@ -179,27 +137,35 @@ decode_sattr3(u32 *p, struct iattr *iap) iap->ia_gid = ntohl(*p++); } if (*p++) { + u64 newsize; + iap->ia_valid |= ATTR_SIZE; - iap->ia_size = ntohl(*p++); + p = dec64(p, &newsize); + if (newsize <= NFS_OFFSET_MAX) + iap->ia_size = (u32) newsize; + else + iap->ia_size = ~(size_t) 0; } - if ((tmp = *p++) == 1) { + if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_ATIME; - } else if (tmp == 2) { + } else if (tmp == 2) { /* set to client time */ iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; iap->ia_atime = ntohl(*p++), p++; } - if ((tmp = *p++) != 0) { - iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; - } else if (tmp == 2) { + if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_MTIME; + } else if (tmp == 2) { /* set to client time */ + iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; iap->ia_mtime = ntohl(*p++), p++; } return p; } static inline u32 * -encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct inode *inode) +encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; + if (!inode) { printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__); return NULL; @@ -227,19 +193,50 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct inode *inode) return p; } +static inline u32 * +encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +{ + struct inode *inode = fhp->fh_dentry->d_inode; + + /* Attributes to follow */ + *p++ = xdr_one; + + *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); + *p++ = htonl((u32) fhp->fh_post_mode); + *p++ = htonl((u32) fhp->fh_post_nlink); + *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); + *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); + if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { + p = enc64(p, (u64) NFS3_MAXPATHLEN); + } else { + p = enc64(p, (u64) fhp->fh_post_size); + } + p = enc64(p, fhp->fh_post_blksize * fhp->fh_post_blocks); + *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev)); + *p++ = htonl((u32) MINOR(fhp->fh_post_rdev)); + p = enc64(p, (u64) inode->i_dev); + p = enc64(p, (u64) inode->i_ino); + p = encode_time3(p, fhp->fh_post_atime); + p = encode_time3(p, fhp->fh_post_mtime); + p = encode_time3(p, fhp->fh_post_ctime); + + return p; +} + /* * Encode post-operation attributes. * The inode may be NULL if the call failed because of a stale file * handle. In this case, no attributes are returned. */ static u32 * -encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct inode *inode) +encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry) { - if (inode == NULL) { - *p++ = xdr_zero; - return p; + if (dentry && dentry->d_inode != NULL) { + *p++ = xdr_one; /* attributes follow */ + return encode_fattr3(rqstp, p, dentry); } - return encode_fattr3(rqstp, p, inode); + *p++ = xdr_zero; + return p; } /* @@ -248,17 +245,22 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct inode *inode) static u32 * encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) { - struct inode *inode = fhp->fh_inode; + struct dentry *dentry = fhp->fh_dentry; - if (fhp->fh_post_version == inode->i_version) { - *p++ = xdr_one; - p = enc64(p, (u64) fhp->fh_pre_size); - p = encode_time3(p, fhp->fh_pre_mtime); - p = encode_time3(p, fhp->fh_pre_ctime); - } else { - *p++ = xdr_zero; + if (dentry && dentry->d_inode && fhp->fh_post_saved) { + if (fhp->fh_pre_saved) { + *p++ = xdr_one; + p = enc64(p, (u64) fhp->fh_pre_size); + p = encode_time3(p, fhp->fh_pre_mtime); + p = encode_time3(p, fhp->fh_pre_ctime); + } else { + *p++ = xdr_zero; + } + return encode_saved_post_attr(rqstp, p, fhp); } - return encode_post_op_attr(rqstp, p, inode); + /* no pre- or post-attrs */ + *p++ = xdr_zero; + return encode_post_op_attr(rqstp, p, dentry); } /* @@ -299,10 +301,12 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_sattrargs *args) { if (!(p = decode_fh(p, &args->fh)) - || !(p = decode_sattr3(p, &args->attrs)) - || (*p++ && !(p = decode_time3(p, &args->guardtime)))) + || !(p = decode_sattr3(p, &args->attrs))) return 0; + if ((args->check_guard = ntohl(*p++)) != 0) + p = decode_time3(p, &args->guardtime); + return xdr_argsize_check(rqstp, p); } @@ -333,10 +337,10 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readargs *args) { if (!(p = decode_fh(p, &args->fh)) - || !(p = dec64(p, &args->offset)) - || !(p = dec64(p, &args->count))) + || !(p = dec64(p, &args->offset))) return 0; + args->count = ntohl(*p++); return xdr_argsize_check(rqstp, p); } @@ -345,14 +349,14 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_writeargs *args) { if (!(p = decode_fh(p, &args->fh)) - || !(p = dec64(p, &args->offset)) - || !(p = dec64(p, &args->count))) + || !(p = dec64(p, &args->offset))) return 0; + args->count = ntohl(*p++); args->stable = ntohl(*p++); args->len = ntohl(*p++); args->data = (char *) p; - p += (args->len + 3) >> 2; + p += XDR_QUADLEN(args->len); return xdr_argsize_check(rqstp, p); } @@ -366,11 +370,12 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, return 0; switch (args->createmode = ntohl(*p++)) { - case 0: case 1: + case NFS3_CREATE_UNCHECKED: + case NFS3_CREATE_GUARDED: if (!(p = decode_sattr3(p, &args->attrs))) return 0; break; - case 2: + case NFS3_CREATE_EXCLUSIVE: args->verf = p; p += 2; break; @@ -460,8 +465,9 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, { if (!(p = decode_fh(p, &args->fh))) return 0; - args->cookie = ntohl(*p++); + p = dec64(p, &args->cookie); args->verf = p; p += 2; + args->dircount = ~0; args->count = ntohl(*p++); return xdr_argsize_check(rqstp, p); @@ -473,7 +479,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, { if (!(p = decode_fh(p, &args->fh))) return 0; - args->cookie = ntohl(*p++); + p = dec64(p, &args->cookie); args->verf = p; p += 2; args->dircount = ntohl(*p++); args->count = ntohl(*p++); @@ -485,9 +491,9 @@ int nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_commitargs *args) { - if (!(p = decode_fh(p, &args->fh)) - || !(p = dec64(p, &args->offset))) + if (!(p = decode_fh(p, &args->fh))) return 0; + p = dec64(p, &args->offset); args->count = ntohl(*p++); return xdr_argsize_check(rqstp, p); @@ -496,12 +502,23 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, /* * XDR encode functions */ +/* + * There must be an encoding function for void results so svc_process + * will work properly. + */ +int +nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) +{ + return xdr_ressize_check(rqstp, p); +} + /* GETATTR */ int nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, struct nfsd3_attrstat *resp) { - if (!(p = encode_fattr3(rqstp, p, resp->fh.fh_inode))) + if (resp->status == 0 + && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry))) return 0; return xdr_ressize_check(rqstp, p); } @@ -518,15 +535,14 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p, /* LOOKUP */ int -nfs3svc_encode_lookupres(struct svc_rqst *rqstp, u32 *p, - struct nfsd3_lookupres *resp) +nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_diropres *resp) { if (resp->status == 0) { p = encode_fh(p, &resp->fh); - if (!(p = encode_fattr3(rqstp, p, resp->fh.fh_inode))) - return 0; + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); } - p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry); return xdr_ressize_check(rqstp, p); } @@ -535,7 +551,7 @@ int nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_accessres *resp) { - p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); if (resp->status == 0) *p++ = htonl(resp->access); return xdr_ressize_check(rqstp, p); @@ -546,7 +562,7 @@ int nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readlinkres *resp) { - p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); if (resp->status == 0) { *p++ = htonl(resp->len); p += XDR_QUADLEN(resp->len); @@ -559,7 +575,7 @@ int nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readres *resp) { - p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); if (resp->status == 0) { *p++ = htonl(resp->count); *p++ = htonl(resp->eof); @@ -587,11 +603,12 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p, /* CREATE, MKDIR, SYMLINK, MKNOD */ int nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p, - struct nfsd3_createres *resp) + struct nfsd3_diropres *resp) { if (resp->status == 0) { + *p++ = xdr_one; p = encode_fh(p, &resp->fh); - p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); } p = encode_wcc_data(rqstp, p, &resp->dirfh); return xdr_ressize_check(rqstp, p); @@ -612,7 +629,7 @@ int nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_linkres *resp) { - p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); p = encode_wcc_data(rqstp, p, &resp->tfh); return xdr_ressize_check(rqstp, p); } @@ -622,73 +639,116 @@ int nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readdirres *resp) { - p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode); + p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry); if (resp->status == 0) { /* stupid readdir cookie */ - *p++ = ntohl(resp->fh.fh_inode->i_mtime); - *p++ = xdr_zero; - p = resp->list_end; + memcpy(p, resp->verf, 8); p += 2; + p += XDR_QUADLEN(resp->count); } return xdr_ressize_check(rqstp, p); } -#define NFS3_ENTRYPLUS_BAGGAGE ((1 + 20 + 1 + NFS3_FHSIZE) << 2) -int -nfs3svc_encode_entry(struct readdir_cd *cd, const char *name, - int namlen, unsigned long offset, ino_t ino) +/* + * Encode a directory entry. This one works for both normal readdir + * and readdirplus. + * The normal readdir reply requires 2 (fileid) + 1 (stringlen) + * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen. + * + * The readdirplus baggage is 1+21 words for post_op_attr, plus the + * file handle. + */ + +#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1) +#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) +static int +encode_entry(struct readdir_cd *cd, const char *name, + int namlen, off_t offset, ino_t ino, int plus) { u32 *p = cd->buffer; int buflen, slen, elen; - struct svc_fh fh; - if (offset > ~((u64) 0)) - return -EINVAL; if (cd->offset) - *cd->offset = htonl(offset); + enc64(cd->offset, (u64) offset); - /* For readdirplus, look up the inode */ - if (cd->plus && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh)) + /* nfsd_readdir calls us with name == 0 when it wants us to + * set the last offset entry. */ + if (name == 0) return 0; + /* + dprintk("encode_entry(%.*s @%ld%s)\n", + namlen, name, (long) offset, plus? " plus" : ""); + */ + /* truncate filename if too long */ if (namlen > NFS3_MAXNAMLEN) namlen = NFS3_MAXNAMLEN; slen = XDR_QUADLEN(namlen); - elen = slen + (cd->plus? NFS3_ENTRYPLUS_BAGGAGE : 0); - if ((buflen = cd->buflen - elen - 4) < 0) { + elen = slen + NFS3_ENTRY_BAGGAGE + + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0); + if ((buflen = cd->buflen - elen) < 0) { cd->eob = 1; - if (cd->plus) - fh_put(&fh); return -EINVAL; } - *p++ = xdr_one; /* mark entry present */ - *p++ = xdr_zero; /* file id (64 bit) */ - *p++ = htonl((u32) ino); - *p++ = htonl((u32) namlen); /* name length & name */ + *p++ = xdr_one; /* mark entry present */ + p = enc64(p, ino); /* file id */ +#ifdef XDR_ENCODE_STRING_TAKES_LENGTH + p = xdr_encode_string(p, name, namlen); /* name length & name */ +#else + /* just like nfsproc.c */ + *p++ = htonl((u32) namlen); memcpy(p, name, namlen); p += slen; +#endif + p[slen - 1] = 0; /* don't leak kernel data */ + + cd->offset = p; /* remember pointer */ + p = enc64(p, NFS_OFFSET_MAX); /* offset of next entry */ /* throw in readdirplus baggage */ - if (cd->plus) { - p = encode_post_op_attr(cd->rqstp, p, fh.fh_inode); - p = encode_fh(p, &fh); - fh_put(&fh); + if (plus) { + struct svc_fh fh; + + fh_init(&fh); + /* Disabled for now because of lock-up */ + if (0 && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh) == 0) { + p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry); + p = encode_fh(p, &fh); + fh_put(&fh); + } else { + /* Didn't find this entry... weird. + * Proceed without the attrs anf fh anyway. + */ + *p++ = 0; + *p++ = 0; + } } - cd->offset = p; /* remember pointer */ - p = enc64(p, ~(u64) 0); /* offset of next entry */ - cd->buflen = buflen; cd->buffer = p; return 0; } +int +nfs3svc_encode_entry(struct readdir_cd *cd, const char *name, + int namlen, off_t offset, ino_t ino) +{ + return encode_entry(cd, name, namlen, offset, ino, 0); +} + +int +nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name, + int namlen, off_t offset, ino_t ino) +{ + return encode_entry(cd, name, namlen, offset, ino, 1); +} + /* FSSTAT */ int -nfs3svc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, - struct nfsd3_statfsres *resp) +nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_fsstatres *resp) { struct statfs *s = &resp->stats; u64 bs = s->f_bsize; @@ -722,9 +782,9 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p, *p++ = htonl(resp->f_wtpref); *p++ = htonl(resp->f_wtmult); *p++ = htonl(resp->f_dtpref); - *p++ = htonl(resp->f_maxfilesize); + p = enc64(p, resp->f_maxfilesize); + *p++ = xdr_one; *p++ = xdr_zero; - *p++ = htonl(1000000000 / HZ); *p++ = htonl(resp->f_properties); } @@ -741,8 +801,8 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p, if (resp->status == 0) { *p++ = htonl(resp->p_link_max); *p++ = htonl(resp->p_name_max); - *p++ = xdr_one; /* always reject long file names */ - *p++ = xdr_one; /* chown restricted */ + *p++ = htonl(resp->p_no_trunc); + *p++ = htonl(resp->p_chown_restricted); *p++ = htonl(resp->p_case_insensitive); *p++ = htonl(resp->p_case_preserving); } @@ -769,7 +829,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p, */ int nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, - struct nfsd_fhandle *resp) + struct nfsd3_attrstat *resp) { fh_put(&resp->fh); return 1; @@ -777,7 +837,7 @@ nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, int nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p, - struct nfsd3_fhandle2 *resp) + struct nfsd3_fhandle_pair *resp) { fh_put(&resp->fh1); fh_put(&resp->fh2); diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index c05a6304fae5..ee7b22fd48fd 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -390,7 +390,8 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, */ nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, argp->tname, argp->tlen, - &newfh); + &newfh, &argp->attrs); + if (!nfserr) { argp->attrs.ia_valid &= ~ATTR_SIZE; nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs); @@ -469,7 +470,8 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, /* Read directory and encode entries on the fly */ nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, - nfssvc_encode_entry, buffer, &count); + nfssvc_encode_entry, + buffer, &count, NULL); resp->count = count; fh_put(&argp->fh); @@ -549,6 +551,8 @@ nfserrno (int errno) { NFSERR_NXIO, ENXIO }, { NFSERR_ACCES, EACCES }, { NFSERR_EXIST, EEXIST }, + { NFSERR_XDEV, EXDEV }, + { NFSERR_MLINK, EMLINK }, { NFSERR_NODEV, ENODEV }, { NFSERR_NOTDIR, ENOTDIR }, { NFSERR_ISDIR, EISDIR }, @@ -556,6 +560,7 @@ nfserrno (int errno) { NFSERR_FBIG, EFBIG }, { NFSERR_NOSPC, ENOSPC }, { NFSERR_ROFS, EROFS }, + { NFSERR_MLINK, EMLINK }, { NFSERR_NAMETOOLONG, ENAMETOOLONG }, { NFSERR_NOTEMPTY, ENOTEMPTY }, #ifdef EDQUOT diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 7c3a22fd5aa6..940460a1b20d 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -226,8 +226,20 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) svc_putlong(&rqstp->rq_resbuf, nfserr); /* Encode result. - * FIXME: Most NFSv3 calls return wcc data even when the call failed + * For NFSv2, additional info is never returned in case of an error. */ +#ifdef CONFIG_NFSD_V3 + if (!(nfserr && rqstp->rq_vers == 2)) { + xdr = proc->pc_encode; + if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) { + /* Failed to encode result. Release cache entry */ + dprintk("nfsd: failed to encode result!\n"); + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); + *statp = rpc_system_err; + return 1; + } + } +#else xdr = proc->pc_encode; if (!nfserr && xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) { @@ -237,6 +249,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) *statp = rpc_system_err; return 1; } +#endif /* CONFIG_NFSD_V3 */ /* Store reply in cache. */ nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); @@ -246,16 +259,16 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) static struct svc_version nfsd_version2 = { 2, 18, nfsd_procedures2, nfsd_dispatch }; -#ifdef CONFIG_NFSD_NFS3 +#ifdef CONFIG_NFSD_V3 static struct svc_version nfsd_version3 = { - 3, 23, nfsd_procedures3, nfsd_dispatch + 3, 22, nfsd_procedures3, nfsd_dispatch }; #endif static struct svc_version * nfsd_version[] = { NULL, NULL, &nfsd_version2, -#ifdef CONFIG_NFSD_NFS3 +#ifdef CONFIG_NFSD_V3 &nfsd_version3, #endif }; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index f929c4860e20..d952ffac90a2 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -32,6 +32,10 @@ #include #include +#ifdef CONFIG_NFSD_V3 +#include +#include +#endif /* CONFIG_NFSD_V3 */ #include #include @@ -357,6 +361,9 @@ printk("nfsd_setattr: size change??\n"); if (EX_ISSYNC(fhp->fh_export)) write_inode_now(inode); err = 0; + + /* Don't unlock inode; the nfssvc_release functions are supposed + * to do this. */ out: return err; @@ -365,6 +372,84 @@ out_nfserr: goto out; } +#ifdef CONFIG_NFSD_V3 +/* + * Check server access rights to a file system object + */ +struct accessmap { + u32 access; + int how; +}; +static struct accessmap nfs3_regaccess[] = { + { NFS3_ACCESS_READ, MAY_READ }, + { NFS3_ACCESS_EXECUTE, MAY_EXEC }, + { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_TRUNC }, + { NFS3_ACCESS_EXTEND, MAY_WRITE }, + + { 0, 0 } +}; + +static struct accessmap nfs3_diraccess[] = { + { NFS3_ACCESS_READ, MAY_READ }, + { NFS3_ACCESS_LOOKUP, MAY_EXEC }, + { NFS3_ACCESS_MODIFY, MAY_EXEC|MAY_WRITE|MAY_TRUNC }, + { NFS3_ACCESS_EXTEND, MAY_EXEC|MAY_WRITE }, + { NFS3_ACCESS_DELETE, MAY_REMOVE }, + + { 0, 0 } +}; + +static struct accessmap nfs3_anyaccess[] = { + /* XXX: should we try to cover read/write here for clients that + * rely on us to do their access checking for special files? */ + + { 0, 0 } +}; + +int +nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access) +{ + struct accessmap *map; + struct svc_export *export; + struct dentry *dentry; + u32 query, result = 0; + int error; + + error = fh_verify(rqstp, fhp, 0, MAY_NOP); + if (error < 0) + goto out; + + export = fhp->fh_export; + dentry = fhp->fh_dentry; + + if (S_ISREG(dentry->d_inode->i_mode)) { + map = nfs3_regaccess; + } else if (S_ISDIR(dentry->d_inode->i_mode)) { + map = nfs3_diraccess; + } else { + map = nfs3_anyaccess; + } + + query = *access; + while (map->access) { + if (map->access & query) { + error = nfsd_permission(export, dentry, map->how); + if (error == 0) + result |= map->access; + else if (error != -EPERM) + goto out; + } + map++; + } + *access = result; + +out: + return error; +} +#endif + + + /* * Open an existing file or directory. * The wflag argument indicates write access. @@ -603,11 +688,21 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, * Request sync writes if * - the sync export option has been set, or * - the client requested O_SYNC behavior (NFSv3 feature). + * - The file system doesn't support fsync(). * When gathered writes have been configured for this volume, * flushing the data to disk is handled separately below. */ +#ifdef CONFIG_NFSD_V3 + if (rqstp->rq_vers == 2) + stable = EX_ISSYNC(exp); + else if (file.f_op->fsync == 0) + stable = 1; + if (stable && !EX_WGATHER(exp)) + file.f_flags |= O_SYNC; +#else if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp)) file.f_flags |= O_SYNC; +#endif /* CONFIG_NFSD_V3 */ file.f_pos = offset; /* set write offset */ @@ -662,6 +757,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000); #else dprintk("nfsd: write defer %d\n", current->pid); +/* FIXME: Olaf commented this out [gam3] */ schedule_timeout((HZ+99)/100); dprintk("nfsd: write resume %d\n", current->pid); #endif @@ -687,6 +783,36 @@ out: return err; } + +#ifdef CONFIG_NFSD_V3 +/* + * Commit all pendig writes to stable storage. + * Strictly speaking, we could sync just indicated the file region here, + * but there's currently no way we can ask the VFS to do so. + * + * We lock the file to make sure we return full WCC data to the client. + */ +int +nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + off_t offset, unsigned long count) +{ + struct file file; + int err; + + if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file)) != 0) + return err; + + if (file.f_op && file.f_op->fsync) { + nfsd_sync(&file); + } else { + err = nfserr_notsupp; + } + + nfsd_close(&file); + return err; +} +#endif /* CONFIG_NFSD_V3 */ + /* * Create a file (regular, directory, device, fifo); UNIX sockets * not yet implemented. @@ -826,6 +952,126 @@ out_nfserr: goto out; } +#ifdef CONFIG_NFSD_V3 +/* + * NFSv3 version of nfsd_create + */ +int +nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *fname, int flen, struct iattr *iap, + struct svc_fh *resfhp, int createmode, u32 *verifier) +{ + struct dentry *dentry, *dchild; + struct inode *dirp; + int err; + + err = nfserr_perm; + if (!flen) + goto out; + if (!(iap->ia_valid & ATTR_MODE)) + iap->ia_mode = 0; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); + if (err) + goto out; + + dentry = fhp->fh_dentry; + dirp = dentry->d_inode; + + /* Get all the sanity checks out of the way before + * we lock the parent. */ + err = nfserr_notdir; + if(!dirp->i_op || !dirp->i_op->lookup) + goto out; + err = nfserr_perm; + if(!dirp->i_op->create) + goto out; + + /* + * Compose the response file handle. + */ + dchild = lookup_dentry(fname, dget(dentry), 0); + err = PTR_ERR(dchild); + if(IS_ERR(dchild)) + goto out_nfserr; + fh_compose(resfhp, fhp->fh_export, dchild); + + /* + * We must lock the directory before we check for the inode. + */ + err = fh_lock_parent(fhp, dchild); + if (err) + goto out; + + if (dchild->d_inode) { + err = 0; + + if (resfhp->fh_handle.fh_ino == 0) + /* inode might have been instantiated while we slept */ + fh_update(resfhp); + + switch (createmode) { + case NFS3_CREATE_UNCHECKED: + if (! S_ISREG(dchild->d_inode->i_mode)) + err = nfserr_exist; + else { + iap->ia_valid &= ATTR_SIZE; + goto set_attr; + } + break; + case NFS3_CREATE_EXCLUSIVE: + if ( dchild->d_inode->i_mtime == verifier[0] + && dchild->d_inode->i_atime == verifier[1] + && dchild->d_inode->i_mode == S_IFREG + && dchild->d_inode->i_size == 0 ) + break; + /* fallthru */ + case NFS3_CREATE_GUARDED: + err = nfserr_exist; + } + goto out; + } + + err = dirp->i_op->create(dirp, dchild, iap->ia_mode); + if (err < 0) + goto out_nfserr; + + if (EX_ISSYNC(fhp->fh_export)) { + nfsd_sync_dir(dentry); + /* setattr will sync the child (or not) */ + } + + /* + * Update the filehandle to get the new inode info. + */ + fh_update(resfhp); + err = 0; + + if (createmode == NFS3_CREATE_EXCLUSIVE) { + /* Cram the verifier into atime/mtime */ + iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET; + iap->ia_mtime = verifier[0]; + iap->ia_atime = verifier[1]; + } + + /* Set file attributes. Mode has already been set and + * setting uid/gid works only for root. Irix appears to + * send along the gid when it tries to implement setgid + * directories via NFS. Clear out all that cruft. + */ + set_attr: + if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) + err = nfsd_setattr(rqstp, resfhp, iap); + + out: + fh_unlock(fhp); + return err; + + out_nfserr: + err = nfserrno(-err); + goto out; +} +#endif /* CONFIG_NFSD_V3 */ + /* * Truncate a file. * The calling routines must make sure to update the ctime @@ -940,7 +1186,8 @@ int nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, char *path, int plen, - struct svc_fh *resfhp) + struct svc_fh *resfhp, + struct iattr *iap) { struct dentry *dentry, *dnew; struct inode *dirp; @@ -981,6 +1228,15 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (!err) { if (EX_ISSYNC(fhp->fh_export)) nfsd_sync_dir(dentry); + if (iap) { + iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/; + if (iap->ia_valid) { + iap->ia_valid |= ATTR_CTIME; + err = notify_change(dnew, iap); + if (!err && EX_ISSYNC(fhp->fh_export)) + write_inode_now(dentry->d_inode); + } + } } else err = nfserrno(-err); } @@ -1150,6 +1406,15 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, * Lock the parent directories. */ nfsd_double_down(&tdir->i_sem, &fdir->i_sem); + +#ifdef CONFIG_NFSD_V3 + /* Fill in the pre-op attr for the wcc data for both + * tdir and fdir + */ + fill_pre_wcc(ffhp); + fill_pre_wcc(tfhp); +#endif /* CONFIG_NFSD_V3 */ + err = -ENOENT; /* GAM3 check for parent changes after locking. */ if (nfsd_check_parent(fdentry, odentry) && @@ -1163,6 +1428,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, } else dprintk("nfsd: Caught race in nfsd_rename"); +#ifdef CONFIG_NFSD_V3 + /* Fill in the post-op attr for the wcc data for both + * tdir and fdir + */ + fill_post_wcc(ffhp); + fill_post_wcc(tfhp); +#endif /* CONFIG_NFSD_V3 */ nfsd_double_up(&tdir->i_sem, &fdir->i_sem); dput(ndentry); @@ -1232,14 +1504,23 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, rdentry->d_count++; nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem); + +#ifdef CONFIG_NFSD_V3 + fill_pre_wcc(fhp); +#else fhp->fh_locked = 1; +#endif /* CONFIG_NFSD_V3 */ err = -ENOENT; if (nfsd_check_parent(dentry, rdentry)) err = vfs_rmdir(dirp, rdentry); rdentry->d_count--; +#ifdef CONFIG_NFSD_V3 + fill_post_wcc(fhp); +#else fhp->fh_locked = 0; +#endif /* CONFIG_NFSD_V3 */ nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem); dput(rdentry); @@ -1262,10 +1543,11 @@ out_nfserr: /* * Read entries from a directory. + * The verifier is an NFSv3 thing we ignore for now. */ int nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, - encode_dent_fn func, u32 *buffer, int *countp) + encode_dent_fn func, u32 *buffer, int *countp, u32 *verf) { struct inode *inode; u32 *p; @@ -1291,6 +1573,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, cd.rqstp = rqstp; cd.buffer = buffer; cd.buflen = *countp; /* count of words */ + cd.dirfh = fhp; /* * Read the directory entries. This silly loop is necessary because @@ -1320,8 +1603,14 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, /* If we didn't fill the buffer completely, we're at EOF */ eof = !cd.eob; - if (cd.offset) - *cd.offset = htonl(file.f_pos); + if (cd.offset) { +#ifdef CONFIG_NFSD_V3 + if (rqstp->rq_vers == 3) + (void)enc64(cd.offset, file.f_pos); + else +#endif /* CONFIG_NFSD_V3 */ + *cd.offset = htonl(file.f_pos); + } p = cd.buffer; *p++ = 0; /* no more entries */ diff --git a/include/linux/ide.h b/include/linux/ide.h index bba7533f6f12..67376905e81e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -299,6 +299,8 @@ typedef struct ide_drive_s { thresholds_t smart_thresholds; values_t smart_values; #endif + int last_lun; /* last logical unit */ + int forced_lun; /* if hdxlun was given at boot */ } ide_drive_t; /* diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 5799d3d70cc4..0303ea57f4fb 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -4,7 +4,7 @@ * Hodge-podge collection of knfsd-related stuff. * I will sort this out later. * - * Copyright (C) 1995 Olaf Kirch + * Copyright (C) 1995-1997 Olaf Kirch */ #ifndef LINUX_NFSD_NFSD_H @@ -61,6 +61,9 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); * Procedure table for NFSv2 */ extern struct svc_procedure nfsd_procedures2[]; +#ifdef CONFIG_NFSD_V3 +extern struct svc_procedure nfsd_procedures3[]; +#endif /* CONFIG_NFSD_V3 */ extern struct svc_program nfsd_program; /* @@ -74,11 +77,20 @@ void nfsd_racache_init(void); void nfsd_racache_shutdown(void); int nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); +#ifdef CONFIG_NFSD_V3 +int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *); +#endif /* CONFIG_NFSD_V3 */ int nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *); int nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res); +#ifdef CONFIG_NFSD_V3 +int nfsd_create_v3(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + struct svc_fh *res, int createmode, + u32 *verifier); +#endif /* CONFIG_NFSD_V3 */ int nfsd_open(struct svc_rqst *, struct svc_fh *, int, int, struct file *); void nfsd_close(struct file *); @@ -90,7 +102,7 @@ int nfsd_readlink(struct svc_rqst *, struct svc_fh *, char *, int *); int nfsd_symlink(struct svc_rqst *, struct svc_fh *, char *name, int len, char *path, int plen, - struct svc_fh *res); + struct svc_fh *res, struct iattr *); int nfsd_link(struct svc_rqst *, struct svc_fh *, char *, int, struct svc_fh *); int nfsd_rename(struct svc_rqst *, @@ -104,9 +116,13 @@ int nfsd_truncate(struct svc_rqst *, struct svc_fh *, unsigned long size); int nfsd_readdir(struct svc_rqst *, struct svc_fh *, loff_t, encode_dent_fn, - u32 *buffer, int *countp); + u32 *buffer, int *countp, u32 *verf); int nfsd_statfs(struct svc_rqst *, struct svc_fh *, struct statfs *); +#ifdef CONFIG_NFSD_V3 +int nfsd_commit(struct svc_rqst *, struct svc_fh *, + off_t, unsigned long); +#endif /* CONFIG_NFSD_V3 */ int nfsd_notify_change(struct inode *, struct iattr *); int nfsd_permission(struct svc_export *, struct dentry *, int); diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index f12b87153fea..726e8f27f580 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -86,8 +86,33 @@ typedef struct svc_fh { struct knfs_fh fh_handle; /* FH data */ struct dentry * fh_dentry; /* validated dentry */ struct svc_export * fh_export; /* export pointer */ +#ifdef CONFIG_NFSD_V3 + unsigned char fh_post_saved; /* post-op attrs saved */ + unsigned char fh_pre_saved; /* pre-op attrs saved */ +#endif /* CONFIG_NFSD_V3 */ unsigned char fh_locked; /* inode locked by us */ unsigned char fh_dverified; /* dentry has been checked */ + +#ifdef CONFIG_NFSD_V3 + /* Pre-op attributes saved during fh_lock */ + __u64 fh_pre_size; /* size before operation */ + time_t fh_pre_mtime; /* mtime before oper */ + time_t fh_pre_ctime; /* ctime before oper */ + + /* Post-op attributes saved in fh_unlock */ + umode_t fh_post_mode; /* i_mode */ + nlink_t fh_post_nlink; /* i_nlink */ + uid_t fh_post_uid; /* i_uid */ + gid_t fh_post_gid; /* i_gid */ + __u64 fh_post_size; /* i_size */ + unsigned long fh_post_blocks; /* i_blocks */ + unsigned long fh_post_blksize;/* i_blksize */ + kdev_t fh_post_rdev; /* i_rdev */ + time_t fh_post_atime; /* i_atime */ + time_t fh_post_mtime; /* i_mtime */ + time_t fh_post_ctime; /* i_ctime */ +#endif /* CONFIG_NFSD_V3 */ + } svc_fh; /* @@ -128,6 +153,53 @@ fh_init(struct svc_fh *fhp) return fhp; } +#ifdef CONFIG_NFSD_V3 +/* + * Fill in the pre_op attr for the wcc data + */ +static inline void +fill_pre_wcc(struct svc_fh *fhp) +{ + struct inode *inode; + + inode = fhp->fh_dentry->d_inode; + if (!fhp->fh_pre_saved) { + fhp->fh_pre_mtime = inode->i_mtime; + fhp->fh_pre_ctime = inode->i_ctime; + fhp->fh_pre_size = inode->i_size; + fhp->fh_pre_saved = 1; + } + fhp->fh_locked = 1; +} + +/* + * Fill in the post_op attr for the wcc data + */ +static inline void +fill_post_wcc(struct svc_fh *fhp) +{ + struct inode *inode = fhp->fh_dentry->d_inode; + + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + + fhp->fh_post_mode = inode->i_mode; + fhp->fh_post_nlink = inode->i_nlink; + fhp->fh_post_uid = inode->i_uid; + fhp->fh_post_gid = inode->i_gid; + fhp->fh_post_size = inode->i_size; + fhp->fh_post_blksize = inode->i_blksize; + fhp->fh_post_blocks = inode->i_blocks; + fhp->fh_post_rdev = inode->i_rdev; + fhp->fh_post_atime = inode->i_atime; + fhp->fh_post_mtime = inode->i_mtime; + fhp->fh_post_ctime = inode->i_ctime; + fhp->fh_post_saved = 1; + fhp->fh_locked = 0; +} +#endif /* CONFIG_NFSD_V3 */ + + /* * Lock a file handle/inode */ @@ -152,7 +224,11 @@ fh_lock(struct svc_fh *fhp) inode = dentry->d_inode; down(&inode->i_sem); +#ifdef CONFIG_NFSD_V3 + fill_pre_wcc(fhp); +#else fhp->fh_locked = 1; +#endif /* CONFIG_NFSD_V3 */ } /* @@ -165,11 +241,16 @@ fh_unlock(struct svc_fh *fhp) printk(KERN_ERR "fh_unlock: fh not verified!\n"); if (fhp->fh_locked) { +#ifdef CONFIG_NFSD_V3 + fill_post_wcc(fhp); + up(&fhp->fh_dentry->d_inode->i_sem); +#else struct dentry *dentry = fhp->fh_dentry; struct inode *inode = dentry->d_inode; fhp->fh_locked = 0; up(&inode->i_sem); +#endif /* CONFIG_NFSD_V3 */ } } #endif /* __KERNEL__ */ diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index 54e11c549164..7b787bb93557 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -3,17 +3,18 @@ * * XDR types for NFSv3 in nfsd. * - * Copyright (C) 1996, Olaf Kirch + * Copyright (C) 1996-1998, Olaf Kirch */ -#ifndef LINUX_NFSD_XDR3_H -#define LINUX_NFSD_XDR3_H +#ifndef _LINUX_NFSD_XDR3_H +#define _LINUX_NFSD_XDR3_H #include struct nfsd3_sattrargs { struct svc_fh fh; struct iattr attrs; + int check_guard; time_t guardtime; }; @@ -88,7 +89,7 @@ struct nfsd3_symlinkargs { struct nfsd3_readdirargs { struct svc_fh fh; - __u32 cookie; + __u64 cookie; __u32 dircount; __u32 count; __u32 * verf; @@ -97,7 +98,7 @@ struct nfsd3_readdirargs { struct nfsd3_commitargs { struct svc_fh fh; __u64 offset; - __u64 count; + __u32 count; }; struct nfsd3_attrstat { @@ -105,7 +106,8 @@ struct nfsd3_attrstat { struct svc_fh fh; }; -struct nfsd3_lookupres { +/* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */ +struct nfsd3_diropres { __u32 status; struct svc_fh dirfh; struct svc_fh fh; @@ -137,12 +139,6 @@ struct nfsd3_writeres { int committed; }; -struct nfsd3_createres { - __u32 status; - struct svc_fh dirfh; - struct svc_fh fh; -}; - struct nfsd3_renameres { __u32 status; struct svc_fh ffh; @@ -158,10 +154,11 @@ struct nfsd3_linkres { struct nfsd3_readdirres { __u32 status; struct svc_fh fh; - __u32 * list_end; + int count; + __u32 verf[2]; }; -struct nfsd3_statfsres { +struct nfsd3_fsstatres { __u32 status; struct statfs stats; __u32 invarsec; @@ -184,6 +181,8 @@ struct nfsd3_pathconfres { __u32 status; __u32 p_link_max; __u32 p_name_max; + __u32 p_no_trunc; + __u32 p_chown_restricted; __u32 p_case_insensitive; __u32 p_case_preserving; }; @@ -194,7 +193,7 @@ struct nfsd3_commitres { }; /* dummy type for release */ -struct nfsd3_fhandle2 { +struct nfsd3_fhandle_pair { __u32 dummy; struct svc_fh fh1; struct svc_fh fh2; @@ -213,16 +212,15 @@ union nfsd3_xdrstore { struct nfsd3_linkargs linkargs; struct nfsd3_symlinkargs symlinkargs; struct nfsd3_readdirargs readdirargs; - struct nfsd3_lookupres lookupres; + struct nfsd3_diropres diropres; struct nfsd3_accessres accessres; struct nfsd3_readlinkres readlinkres; struct nfsd3_readres readres; struct nfsd3_writeres writeres; - struct nfsd3_createres createres; struct nfsd3_renameres renameres; struct nfsd3_linkres linkres; struct nfsd3_readdirres readdirres; - struct nfsd3_statfsres statfsres; + struct nfsd3_fsstatres fsstatres; struct nfsd3_fsinfores fsinfores; struct nfsd3_pathconfres pathconfres; struct nfsd3_commitres commitres; @@ -230,39 +228,87 @@ union nfsd3_xdrstore { #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) -void nfsxdr_init(void); - int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *); -int nfs3svc_decode_sattr3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *, struct nfsd3_sattrargs *); -int nfs3svc_decode_dirop3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *, struct nfsd3_diropargs *); -int nfs3svc_decode_read3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *, + struct nfsd3_accessargs *); +int nfs3svc_decode_readargs(struct svc_rqst *, u32 *, struct nfsd3_readargs *); -int nfs3svc_decode_write3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *, struct nfsd3_writeargs *); -int nfs3svc_decode_create3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_createargs(struct svc_rqst *, u32 *, + struct nfsd3_createargs *); +int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *, struct nfsd3_createargs *); -int nfs3svc_decode_rename3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *, + struct nfsd3_mknodargs *); +int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *, struct nfsd3_renameargs *); -int nfs3svc_decode_link3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *, struct nfsd3_linkargs *); -int nfs3svc_decode_symlink3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *, struct nfsd3_symlinkargs *); -int nfs3svc_decode_readdir3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *, struct nfsd3_readdirargs *); +int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *, + struct nfsd3_readdirargs *); +int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *, + struct nfsd3_commitargs *); +int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *); +int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *, + struct nfsd3_attrstat *); +int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *, + struct nfsd3_attrstat *); +int nfs3svc_encode_diropres(struct svc_rqst *, u32 *, + struct nfsd3_diropres *); +int nfs3svc_encode_accessres(struct svc_rqst *, u32 *, + struct nfsd3_accessres *); int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd3_readlinkres *); int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *); -int nfs3svc_encode_statfsres(struct svc_rqst *, u32 *, - struct nfsd3_statfsres *); +int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *); +int nfs3svc_encode_createres(struct svc_rqst *, u32 *, + struct nfsd3_diropres *); +int nfs3svc_encode_renameres(struct svc_rqst *, u32 *, + struct nfsd3_renameres *); +int nfs3svc_encode_linkres(struct svc_rqst *, u32 *, + struct nfsd3_linkres *); int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd3_readdirres *); +int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *, + struct nfsd3_fsstatres *); +int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *, + struct nfsd3_fsinfores *); +int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *, + struct nfsd3_pathconfres *); +int nfs3svc_encode_commitres(struct svc_rqst *, u32 *, + struct nfsd3_commitres *); + int nfs3svc_release_fhandle(struct svc_rqst *, u32 *, - struct nfsd_fhandle *); + struct nfsd3_attrstat *); int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *, - struct nfsd3_fhandle2 *); + struct nfsd3_fhandle_pair *); int nfs3svc_encode_entry(struct readdir_cd *, const char *name, - int namlen, unsigned long offset, ino_t ino); + int namlen, off_t offset, ino_t ino); +int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, + int namlen, off_t offset, ino_t ino); + +#ifdef __KERNEL__ + +/* + * This is needed in nfs_readdir for encoding NFS3 directory cookies. + */ +static inline u32 * +enc64(u32 *p, u64 val) +{ + *p++ = htonl(val >> 32); + *p++ = htonl(val & 0xffffffff); + return p; +} + +#endif /* __KERNEL__ */ -#endif /* LINUX_NFSD_XDR3_H */ +#endif /* _LINUX_NFSD_XDR3_H */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 96bcf9fa81fc..5d761bb409a2 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -106,13 +106,11 @@ swp_entry_t __get_swap_page(unsigned short count) offset = scan_swap_map(p, count); swap_device_unlock(p); if (offset) { - int curtp = type; - entry = SWP_ENTRY(type,offset); type = swap_info[type].next; if (type < 0 || p->prio != swap_info[type].prio) { - swap_list.next = curtp; + swap_list.next = swap_list.head; } else { swap_list.next = type; } diff --git a/net/decnet/Makefile b/net/decnet/Makefile index f12aad2a45f8..8a44ccac8f1b 100644 --- a/net/decnet/Makefile +++ b/net/decnet/Makefile @@ -16,9 +16,7 @@ ifeq ($(CONFIG_DECNET_FW),y) O_OBJS += dn_fw.o endif -ifeq ($(CONFIG_SYSCTL),y) O_OBJS += sysctl_net_decnet.o -endif include $(TOPDIR)/Rules.make diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 87e28378c78b..f024b8cf9268 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -291,7 +291,15 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) kfree(t); } } -#endif +#else /* CONFIG_SYSCTL */ +static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) +{ +} +static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms) +{ +} + +#endif /* CONFIG_SYSCTL */ static struct dn_ifaddr *dn_dev_alloc_ifa(void) { diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 39218c777bd2..5dcb0ef49c30 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -32,6 +32,8 @@ int decnet_time_wait = 30; int decnet_dn_count = 3; int decnet_di_count = 5; int decnet_dr_count = 5; + +#ifdef CONFIG_SYSCTL extern int decnet_dst_gc_interval; static int min_decnet_time_wait[] = { 5 }; static int max_decnet_time_wait[] = { 600 }; @@ -471,3 +473,12 @@ void dn_unregister_sysctl(void) unregister_sysctl_table(dn_table_header); } +#else /* CONFIG_SYSCTL */ +void dn_unregister_sysctl(void) +{ +} +void dn_register_sysctl(void) +{ +} + +#endif diff --git a/net/netsyms.c b/net/netsyms.c index a6e577158634..7fdae70eae2c 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -68,6 +68,8 @@ extern int udp_port_rover; #endif +extern int netdev_finish_unregister(struct net_device *dev); + #include #if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \ @@ -223,6 +225,7 @@ EXPORT_SYMBOL(br_avl_find_addr); #ifdef CONFIG_INET /* Internet layer registration */ +EXPORT_SYMBOL(inetdev_lock); EXPORT_SYMBOL(inet_add_protocol); EXPORT_SYMBOL(inet_del_protocol); EXPORT_SYMBOL(ip_route_output); @@ -521,8 +524,10 @@ EXPORT_SYMBOL(init_hippi_dev); EXPORT_SYMBOL(unregister_hipdev); #endif +#ifdef CONFIG_SYSCTL EXPORT_SYMBOL(sysctl_wmem_max); EXPORT_SYMBOL(sysctl_rmem_max); +#endif #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include -- 2.39.5