]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.32pre2 2.3.32pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:29:09 +0000 (15:29 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:29:09 +0000 (15:29 -0500)
34 files changed:
CREDITS
Documentation/Configure.help
Documentation/ide.txt
drivers/block/ide-probe.c
drivers/block/ide.c
drivers/char/msp3400.c
drivers/i2o/i2o_core.c
drivers/net/rclanmtl.c
drivers/net/sb1000.c
drivers/net/tlan.c
drivers/net/tlan.h
drivers/scsi/53c8xx_d.h
drivers/scsi/g_NCR5380.c
drivers/scsi/g_NCR5380.h
drivers/scsi/ide-scsi.c
drivers/scsi/sim710_d.h
drivers/sound/mad16.c
drivers/sound/sb_ess.c
fs/Config.in
fs/nfsd/Makefile
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/vfs.c
include/linux/ide.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/nfsfh.h
include/linux/nfsd/xdr3.h
mm/swapfile.c
net/decnet/Makefile
net/decnet/dn_dev.c
net/decnet/sysctl_net_decnet.c
net/netsyms.c

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