S: Australia
N: Greg Page
-E: greg@caldera.com
+E: gpage@sovereign.org
D: IPX development and support
N: David Parsons
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
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
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
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.
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:
*
* "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.
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" */
int mode;
int norm;
int stereo;
+ int nicam_on;
int main, second; /* sound carrier */
int left, right; /* volume */
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;
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;
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:
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));
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 */
/* 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
{ 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
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__
unlock_kernel();
#endif
- dprintk("msp3400: thread: start\n");
+ printk("msp3400: daemon started\n");
if(msp->notify != NULL)
up(msp->notify);
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;
}
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);
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 */
/* 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 {
/* 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;
/* 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 {
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;
}
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);
}
return 0;
}
-
#if 0 /* not finished yet */
static int msp3410d_thread(void *data)
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);
{
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))
{
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);
}
break;
default:
- printk("Unknown private I2O msg received: 0x%x\n",
+ printk("Unknown private I2O msg received: 0x%lx\n",
p32[5]);
break;
}
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;
}
}
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;
}
}
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;
}
}
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/etherdevice.h>
+#include <linux/isapnp.h>
/* for SIOGCM/SIOSCM stuff */
+
#include <linux/if_cablemodem.h>
#ifdef SB1000_DEBUG
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);
static inline int sb1000_rx(struct net_device *dev);
static inline void sb1000_error_dpc(struct net_device *dev);
-\f
-/* 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;
}
\f
/*
* SB1000 hardware routines to be used during open/configuration phases
*/
+
const int TimeOutJiffies = (int)(8.75 * HZ);
static inline void nicedelay(unsigned long usecs)
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;
}
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-
+#include <linux/spinlock.h>
typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 );
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;
priv->speed = speed;
priv->sa_int = sa_int;
priv->debug = debug;
+
+ spin_lock_init(&priv->lock);
ether_setup( 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 );
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;
( 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 );
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 );
}
}
dev->interrupt--;
- sti();
+ spin_unlock(&priv->lock);
} /* TLan_HandleInterrupts */
struct net_device *dev = (struct net_device *) data;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
u32 elapsed;
+ unsigned long flags;
priv->timer.function = NULL;
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 ) {
} 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;
{
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);
dev->interrupt--;
if ( dev->interrupt == 0 )
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
return err;
{
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 );
dev->interrupt--;
if ( dev->interrupt == 0 )
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
} /* TLan_MiiWriteReg */
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 */
u8 tlanRev;
u8 tlanFullDuplex;
char devName[8];
+ spinlock_t lock;
} TLanPrivateInfo;
+/* DO NOT EDIT - Generated automatically by script_asm.pl */
static u32 SCRIPT[] = {
/*
break;
}
+#ifdef CONFIG_SCSI_G_NCR5380_PORT
if (ports) {
/* wakeup sequence for the NCR53C400A and DTC3181E*/
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;
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);
#define NCR5380_map_config memory
-#define NCR5380_map_type volatile unsigned char*
+#define NCR5380_map_type unsigned long
#define NCR5380_map_name base
{
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;
}
+/* DO NOT EDIT - Generated automatically by script_asm.pl */
static u32 SCRIPT[] = {
/*
*
* 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
* 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:
* 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"
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)
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;
*
* 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.
* 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
* - 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
* 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
/* 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;
*/
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
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;
}
/****************************************************************************
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
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)
*
* Process version 3 NFS requests.
*
- * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/linkage.h>
#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/malloc.h>
+#include <linux/major.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr3.h>
-
-typedef struct svc_rqst svc_rqst;
-typedef struct svc_buf svc_buf;
+#include <linux/nfs3.h>
#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)
{
*len = buf->buflen - buf->len - nr;
}
+/*
+ * NULL call.
+ */
static int
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,
{
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,
{
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,
* 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);
}
/*
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,
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);
* 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,
{
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);
}
* 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);
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
*
* XDR support for nfsd/protocol version 3.
*
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/types.h>
#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
*/
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)
{
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);
}
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;
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;
}
/*
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);
}
/*
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);
}
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);
}
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);
}
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;
{
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);
{
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++);
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);
/*
* 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);
}
/* 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);
}
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);
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);
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);
/* 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);
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);
}
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;
*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);
}
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);
}
*/
int
nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
- struct nfsd_fhandle *resp)
+ struct nfsd3_attrstat *resp)
{
fh_put(&resp->fh);
return 1;
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);
*/
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);
/* 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);
{ NFSERR_NXIO, ENXIO },
{ NFSERR_ACCES, EACCES },
{ NFSERR_EXIST, EEXIST },
+ { NFSERR_XDEV, EXDEV },
+ { NFSERR_MLINK, EMLINK },
{ NFSERR_NODEV, ENODEV },
{ NFSERR_NOTDIR, ENOTDIR },
{ NFSERR_ISDIR, EISDIR },
{ NFSERR_FBIG, EFBIG },
{ NFSERR_NOSPC, ENOSPC },
{ NFSERR_ROFS, EROFS },
+ { NFSERR_MLINK, EMLINK },
{ NFSERR_NAMETOOLONG, ENAMETOOLONG },
{ NFSERR_NOTEMPTY, ENOTEMPTY },
#ifdef EDQUOT
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)) {
*statp = rpc_system_err;
return 1;
}
+#endif /* CONFIG_NFSD_V3 */
/* Store reply in cache. */
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
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
};
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
+#ifdef CONFIG_NFSD_V3
+#include <linux/nfs3.h>
+#include <linux/nfsd/xdr3.h>
+#endif /* CONFIG_NFSD_V3 */
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
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;
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.
* 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 */
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
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.
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
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;
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);
}
* 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) &&
} 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);
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);
/*
* 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;
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
/* 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 */
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;
/*
* Hodge-podge collection of knfsd-related stuff.
* I will sort this out later.
*
- * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
*/
#ifndef LINUX_NFSD_NFSD_H
* 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;
/*
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 *);
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 *,
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);
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;
/*
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
*/
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 */
}
/*
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__ */
*
* XDR types for NFSv3 in nfsd.
*
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1996-1998, Olaf Kirch <okir@monad.swb.de>
*/
-#ifndef LINUX_NFSD_XDR3_H
-#define LINUX_NFSD_XDR3_H
+#ifndef _LINUX_NFSD_XDR3_H
+#define _LINUX_NFSD_XDR3_H
#include <linux/nfsd/xdr.h>
struct nfsd3_sattrargs {
struct svc_fh fh;
struct iattr attrs;
+ int check_guard;
time_t guardtime;
};
struct nfsd3_readdirargs {
struct svc_fh fh;
- __u32 cookie;
+ __u64 cookie;
__u32 dircount;
__u32 count;
__u32 * verf;
struct nfsd3_commitargs {
struct svc_fh fh;
__u64 offset;
- __u64 count;
+ __u32 count;
};
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;
int committed;
};
-struct nfsd3_createres {
- __u32 status;
- struct svc_fh dirfh;
- struct svc_fh fh;
-};
-
struct nfsd3_renameres {
__u32 status;
struct svc_fh ffh;
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;
__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;
};
};
/* dummy type for release */
-struct nfsd3_fhandle2 {
+struct nfsd3_fhandle_pair {
__u32 dummy;
struct svc_fh fh1;
struct svc_fh fh2;
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;
#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 */
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;
}
O_OBJS += dn_fw.o
endif
-ifeq ($(CONFIG_SYSCTL),y)
O_OBJS += sysctl_net_decnet.o
-endif
include $(TOPDIR)/Rules.make
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)
{
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 };
unregister_sysctl_table(dn_table_header);
}
+#else /* CONFIG_SYSCTL */
+void dn_unregister_sysctl(void)
+{
+}
+void dn_register_sysctl(void)
+{
+}
+
+#endif
#endif
+extern int netdev_finish_unregister(struct net_device *dev);
+
#include <linux/rtnetlink.h>
#if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \
#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);
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<linux/if_ltalk.h>