]> git.neil.brown.name Git - history.git/commitdiff
- Add QNX4 file system. 2.1.120pre3
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:32 +0000 (15:16 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:32 +0000 (15:16 -0500)
40 files changed:
Documentation/Configure.help
drivers/char/radio-miropcm20.c
drivers/scsi/seagate.c
fs/Config.in
fs/Makefile
fs/filesystems.c
fs/inode.c
fs/isofs/inode.c
fs/nfsd/export.c
fs/nfsd/lockd.c
fs/nfsd/nfsfh.c
fs/qnx4/BUGS [new file with mode: 0644]
fs/qnx4/Makefile [new file with mode: 0644]
fs/qnx4/README [new file with mode: 0644]
fs/qnx4/TODO [new file with mode: 0644]
fs/qnx4/bitmap.c [new file with mode: 0644]
fs/qnx4/dir.c [new file with mode: 0644]
fs/qnx4/file.c [new file with mode: 0644]
fs/qnx4/fsync.c [new file with mode: 0644]
fs/qnx4/inode.c [new file with mode: 0644]
fs/qnx4/namei.c [new file with mode: 0644]
fs/qnx4/symlinks.c [new file with mode: 0644]
fs/qnx4/truncate.c [new file with mode: 0644]
fs/read_write.c
include/asm-i386/checksum.h
include/linux/fs.h
include/linux/genhd.h
include/linux/nfsd/nfsfh.h
include/linux/qnx4_fs.h [new file with mode: 0644]
include/linux/qnx4_fs_i.h [new file with mode: 0644]
include/linux/qnx4_fs_sb.h [new file with mode: 0644]
include/linux/qnxtypes.h [new file with mode: 0644]
include/linux/swap.h
ipc/util.c
mm/swap_state.c
mm/swapfile.c
net/ipv4/ip_nat_dumb.c
net/ipv4/tcp.c
net/ipv4/udp.c
net/ipv6/udp.c

index f04f14bbf37e32866f38ec698f3067d5d7368121..28f0b0bf1907c1b223cc9045471aa1a31f112ba6 100644 (file)
@@ -6478,6 +6478,18 @@ CONFIG_ROMFS_FS
   If you don't know whether you need it, then you don't need it: say
   N.
 
+QNX filesystem support (EXPERIMENTAL)
+CONFIG_QNX4FS_FS  
+  This is the filesystem used by QNX 4. Say Y if you intend to mount
+  QNX hard disks and floppies.
+
+  This filesystem support is also available as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). The module is called qnx4.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. 
+
+  If unsure, say N.
+
 Kernel automounter support
 CONFIG_AUTOFS_FS
   The automounter is a tool to automatically mount remote filesystems
index ffc1d1908d9964cc8686077c2a824096bef16bdc..126a27771a256b87f474fe799a8174d97d979f64 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/init.h>                        /* Initdata                     */
 #include <asm/uaccess.h>               /* copy to/from user            */
 #include <linux/videodev.h>            /* kernel radio structs         */
-#include <linux/config.h>              /* CONFIG_RADIO_MIROPCM20       */
 #include "../sound/lowlevel/miroaci.h" /* ACI Control by acimixer      */
 
 static int users = 0;
index f5a316d313fd2f6a8d7c96997b8743adaa9c0c9a..703fb42aa9129afb9a997eab67e21edd54d72c7f 100644 (file)
@@ -87,7 +87,6 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 
index 25d71db41cf557d169ceebf7d7bf6348f89e6236..9565489d42b2e2baa5f313a55998557224d207c5 100644 (file)
@@ -77,6 +77,10 @@ if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS
+  tristate 'QNX filesystem support (EXPERIMENTAL)' CONFIG_QNX4FS_FS
+  if [ "$CONFIG_QNX4FS_FS" != "n" ]; then
+    bool '   QNXFS read-write support (FOR TESTING ONLY)' CONFIG_QNX4FS_RW
+  fi    
 fi
 bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
 endmenu
index ae3a870fb81a471d7e588bc0639a40ff83e1501a..6434205fb729ebb9e54fc813e69e3a96aa5ac8ad 100644 (file)
@@ -18,7 +18,7 @@ O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
                hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd nfsd \
-               nls devpts adfs
+               nls devpts adfs qnx4
 
 ifeq ($(CONFIG_QUOTA),y)
 O_OBJS += dquot.o
@@ -207,6 +207,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_QNX4FS_FS),y)
+SUB_DIRS += qnx4
+else
+  ifeq ($(CONFIG_QNX4FS_FS),m)
+  MOD_SUB_DIRS += qnx4
+  endif
+endif
+
 ifeq ($(CONFIG_AUTOFS_FS),y)
 SUB_DIRS += autofs
 else
index dcd1cf1d495d3981f22b37f6fabc61b68f9c5039..49b55fd667d663fabb7b81cda89f65c033e2aefd 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/ufs_fs.h>
 #include <linux/romfs_fs.h>
 #include <linux/auto_fs.h>
+#include <linux/qnx4_fs.h>
 #include <linux/ntfs_fs.h>
 #include <linux/hfs_fs.h>
 #include <linux/devpts_fs.h>
@@ -148,6 +149,10 @@ static void __init do_sys_setup(void)
        init_devpts_fs();
 #endif
 
+#ifdef CONFIG_QNX4FS_FS
+       init_qnx4_fs();
+#endif
+   
 #ifdef CONFIG_NLS
        init_nls();
 #endif
index c68ea1b4c5524fb444a7a98d9e8b47303ad8c558..bbd1cc21988ac76bbe1c040da9ee9ec796cfb125 100644 (file)
@@ -770,7 +770,13 @@ int fs_may_remount_ro(struct super_block *sb)
                inode = file->f_dentry->d_inode;
                if (!inode || inode->i_sb != sb)
                        continue;
-               if (S_ISREG(inode->i_mode) && file->f_mode & FMODE_WRITE)
+
+               /* File with pending delete? */
+               if (inode->i_nlink == 0)
+                       return 0;
+
+               /* Writable file? */
+               if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
                        return 0;
        }
        return 1; /* Tis' cool bro. */
index e752d1ce84bb63757a96426670890f86e0891b00..2c4d1e47d3df1119e22c31f73d95c0bdb4fe7f19 100644 (file)
@@ -130,18 +130,34 @@ struct iso9660_options{
 
 static int strnicmp(const char *s1, const char *s2, int len)
 {
-       int n = 0;
-       while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) {
-               s1++; s2++; n++;
-               if (n == len) return 0;
-       }
-       if (*s1 == 0 && *s2 == 0) return 0;
-       if (*s1 && *s2) {
-               if (*s1 > *s2) return 1;
-               return -1;
+       /* Yes, Virginia, it had better be unsigned */
+       unsigned char c1, c2;
+
+       while (len) {
+               c1 = *s1; c2 = *s2;
+               s1++; s2++;
+               if (!c1)
+                       goto end_of_string1;
+               if (!c2)
+                       goto end_of_string2;
+               if (c1 != c2) {
+                       c1 = tolower(c1);
+                       c2 = tolower(c2);
+                       if (c1 != c2)
+                               goto different;
+               }
+               len--;
        }
-       if (*s1) return 1;
-       return -1;
+       return 0;
+
+end_of_string1:
+       return c2 ? -1 : 0;
+
+end_of_string2:
+       return 1;
+
+different:
+       return c1 < c2 ? -1 : 1;
 }
 
 /*
index 0d214eecbe3f786d364f8a2c5388e5b977639bea..e30953bb2d93d608ae25822a59b1574c5d0150c3 100644 (file)
@@ -392,14 +392,15 @@ out:
 int
 exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, struct knfs_fh *f)
 {
-       struct svc_export       *exp = NULL;
-       struct svc_fh           fh;
+       struct svc_export       *exp;
        struct dentry           *dentry;
        struct inode            *inode;
+       struct svc_fh           fh;
 
        dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", clp->cl_ident, dev, ino);
 
-       if (!(exp = exp_get(clp, dev, ino)))
+       exp = exp_get(clp, dev, ino);
+       if (!exp)
                return -EPERM;
 
        dentry = exp->ex_dentry;
@@ -414,8 +415,11 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, struct knfs_fh *f)
                       dev, ino, inode->i_dev, inode->i_ino);
        }
 
-       dget(dentry);
-       fh_compose(&fh, exp, dentry);
+       /*
+        * fh must be initialized before calling fh_compose
+        */
+       fh_init(&fh);
+       fh_compose(&fh, exp, dget(dentry));
        memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
        fh_put(&fh);
 
index ccca2cc7c2a7a41679261fdce3c9df093e2bd9cf..e23f48e5b9515f3abd12d1b75ac30a679f71f549 100644 (file)
 static u32
 nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp)
 {
-       struct svc_fh   fh;
        u32             nfserr;
+       struct svc_fh   fh;
 
+       /* must initialize before using! */
+       fh_init(&fh);
        fh.fh_handle = *f;
        fh.fh_export = NULL;
-       fh.fh_dverified = 0;
 
        nfserr = nfsd_open(rqstp, &fh, S_IFREG, 0, filp);
        if (!nfserr)
index ce89d60bfcdaaf593abd96d48bbe3427ac39453a..b19fd711c0f29acfa0f34364fc6569cf1efcf487 100644 (file)
@@ -1107,7 +1107,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
 
        dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
                exp->ex_dev, exp->ex_ino,
-               dentry->d_parent->d_name.name, dentry->d_name.name,
+               parent->d_name.name, dentry->d_name.name,
                (inode ? inode->i_ino : 0));
 
        /*
@@ -1115,7 +1115,12 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
         * may not be done on error paths, but the cleanup must call fh_put.
         * Fix this soon!
         */
+       if (fhp->fh_dverified || fhp->fh_locked || fhp->fh_dentry) {
+               printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
+                       parent->d_name.name, dentry->d_name.name);
+       }
        fh_init(fhp);
+
        fhp->fh_handle.fh_dcookie = dentry;
        if (inode) {
                fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
diff --git a/fs/qnx4/BUGS b/fs/qnx4/BUGS
new file mode 100644 (file)
index 0000000..64d81b4
--- /dev/null
@@ -0,0 +1,21 @@
+Last update: 03-07-1998
+
+- Files in a subdir can't be accessed, I think that the inode information
+  is not correctly copied at some point. Solved 06-06-1998, Richard.
+  
+- At some point the mounted device can't be unmounted. I think that somewhere
+  in the code a buffer is not given free.
+
+- Make the '..' entry work, I give it a great chance that the above bug
+  (not given free) has something to do with this one, after a 'ls -l'
+  the mounted device can't be unmounted and that's where the '..' entry
+  is accessed.
+  Seems to be solved 21-06-1998, Frank.
+
+- File read function not correct, after the first block it goes beserk.
+  Solved 21-06-1998, Frank.
+
+- This fs will not work if not built as a module.
+  Solved 25-06-1998, Frank.
+
+- Write/truncate/delete functions don't update the bitmap.
diff --git a/fs/qnx4/Makefile b/fs/qnx4/Makefile
new file mode 100644 (file)
index 0000000..1988bb8
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux qnx4-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := qnx4.o
+O_OBJS   := inode.o dir.o namei.o file.o bitmap.o symlinks.o truncate.o \
+fsync.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/qnx4/README b/fs/qnx4/README
new file mode 100644 (file)
index 0000000..e730073
--- /dev/null
@@ -0,0 +1,9 @@
+
+  This is a snapshot of the QNX4 filesystem for Linux.
+  Please send diffs and remarks to <qnxfs@rtc-one.net> .
+  
+Credits :
+
+Richard "Scuba" A. Frowijn     <scuba@wxs.nl>
+Frank "Jedi/Sector One" Denis  <j@4u.net>
+
diff --git a/fs/qnx4/TODO b/fs/qnx4/TODO
new file mode 100644 (file)
index 0000000..fab3623
--- /dev/null
@@ -0,0 +1,31 @@
+Name       : QNX4 TODO list
+Last update: 29-06-1998
+
+    - qnx4_checkroot (inode.c), currently there's a look for the '/' in
+      the root direntry, if so then the current mounted device is a qnx4
+      partition. This has to be rewritten with a look for 'QNX4' in the
+      bootblock, it seems to me the savest way to ensure that the mounted
+      device is in fact a QNX4 partition.
+      Done 20-06-1998, Frank. But some disks (like QNX install floppies)
+      don't have 'QNX4' in their bootblock.
+      
+    - Bitmap functions. To find out the free space, largest free block, etc.
+      Partly done (RO), Richard, 05/06/1998. Optimized 20-06-1998, Frank.
+    
+    - Symbolic links. symlinks.c have to be rewritten.
+    
+    - Extended files.
+    
+    - Complete write, unlink and truncate functions : the bitmap should be
+updated.
+
+    - Porting to linux 2.1.99+ with dcache support. 20-06-1998, Frank.
+    
+    - Don't rewrite the file_read function : use the generic_file_read hook,
+      and write readpage instead. Done on 21-06-1998, Frank.
+
+    - Write dinit and dcheck.
+
+    - Solving the bugs.
+    
+    - Use le32_to_cpu and vice-versa for portability.
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
new file mode 100644 (file)
index 0000000..170f117
--- /dev/null
@@ -0,0 +1,195 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 28-05-1998 by Richard Frowijn : first release.
+ * 20-06-1998 by Frank Denis : basic optimisations.
+ * 25-06-1998 by Frank Denis : qnx4_is_free, qnx4_set_bitmap, qnx4_bmap .
+ * 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) .
+ */
+
+#include <linux/sched.h>
+#include <linux/qnx4_fs.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/bitops.h>
+
+int qnx4_new_block(struct super_block *sb)
+{
+       return 0;
+}
+
+void count_bits(const register char *bmPart, register int size,
+               int *const tf)
+{
+       char b;
+       int tot = *tf;
+
+       if (size > QNX4_BLOCK_SIZE) {
+               size = QNX4_BLOCK_SIZE;
+       }
+       do {
+               b = *bmPart++;
+               if ((b & 1) == 0)
+                       tot++;
+               if ((b & 2) == 0)
+                       tot++;
+               if ((b & 4) == 0)
+                       tot++;
+               if ((b & 8) == 0)
+                       tot++;
+               if ((b & 16) == 0)
+                       tot++;
+               if ((b & 32) == 0)
+                       tot++;
+               if ((b & 64) == 0)
+                       tot++;
+               if ((b & 128) == 0)
+                       tot++;
+               size--;
+       } while (size != 0);
+       *tf = tot;
+}
+
+unsigned long qnx4_count_free_blocks(struct super_block *sb)
+{
+       int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
+       int total = 0;
+       int total_free = 0;
+       int offset = 0;
+       int size = sb->u.qnx4_sb.BitMap->di_size;
+       struct buffer_head *bh;
+
+       while (total < size) {
+               if ((bh = bread(sb->s_dev, start + offset, QNX4_BLOCK_SIZE)) == NULL) {
+                       printk("qnx4: I/O error in counting free blocks\n");
+                       break;
+               }
+               count_bits(bh->b_data, size - total, &total_free);
+               brelse(bh);
+               total += QNX4_BLOCK_SIZE;
+       }
+
+       return total_free;
+}
+
+unsigned long qnx4_count_free_inodes(struct super_block *sb)
+{
+       return qnx4_count_free_blocks(sb) * QNX4_INODES_PER_BLOCK;      /* FIXME */
+}
+
+int qnx4_is_free(struct super_block *sb, int block)
+{
+       int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
+       int size = sb->u.qnx4_sb.BitMap->di_size;
+       struct buffer_head *bh;
+       const char *g;
+       int ret = -EIO;
+
+       start += block / (QNX4_BLOCK_SIZE * 8);
+       QNX4DEBUG(("qnx4: is_free requesting block [%lu], bitmap in block [%lu]\n",
+                  (unsigned long) block, (unsigned long) start));
+       (void) size;            /* CHECKME */
+       bh = bread(sb->s_dev, start, QNX4_BLOCK_SIZE);
+       if (bh == NULL) {
+               return -EIO;
+       }
+       g = bh->b_data + (block % QNX4_BLOCK_SIZE);
+       if (((*g) & (1 << (block % 8))) == 0) {
+               QNX4DEBUG(("qnx4: is_free -> block is free\n"));
+               ret = 1;
+       } else {
+               QNX4DEBUG(("qnx4: is_free -> block is busy\n"));
+               ret = 0;
+       }
+       brelse(bh);
+
+       return ret;
+}
+
+int qnx4_bmap(struct inode *inode, int block)
+{
+   QNX4DEBUG(("qnx4: bmap on block [%d]\n", block));
+   if (block < 0) {
+      return 0;
+   }
+   return !qnx4_is_free(inode->i_sb, block);
+}
+
+#ifdef CONFIG_QNX4FS_RW
+
+int qnx4_set_bitmap(struct super_block *sb, int block, int busy)
+{
+       int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
+       int size = sb->u.qnx4_sb.BitMap->di_size;
+       struct buffer_head *bh;
+       char *g;
+
+       start += block / (QNX4_BLOCK_SIZE * 8);
+       QNX4DEBUG(("qnx4: set_bitmap requesting block [%lu], bitmap in block [%lu]\n",
+                  (unsigned long) block, (unsigned long) start));
+       (void) size;            /* CHECKME */
+       bh = bread(sb->s_dev, start, QNX4_BLOCK_SIZE);
+       if (bh == NULL) {
+               return -EIO;
+       }
+       g = bh->b_data + (block % QNX4_BLOCK_SIZE);
+       if (busy == 0) {
+               (*g) &= ~(1 << (block % 8));
+       } else {
+               (*g) |= (1 << (block % 8));
+       }
+       mark_buffer_dirty(bh, 1);
+       brelse(bh);
+
+       return 0;
+}
+
+static void qnx4_clear_inode(struct inode *inode)
+{
+       struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
+
+       memset(qnx4_ino->i_reserved, 0, sizeof qnx4_ino->i_reserved);
+       qnx4_ino->i_size = 0;
+       qnx4_ino->i_num_xtnts = 0;
+       qnx4_ino->i_mode = 0;
+       qnx4_ino->i_status = 0;
+}
+
+void qnx4_free_inode(struct inode *inode)
+{
+       if (!inode) {
+               return;
+       }
+       if (!inode->i_dev) {
+               printk("free_inode: inode has no device\n");
+               return;
+       }
+       if (inode->i_count > 1) {
+               printk("free_inode: inode has count=%d\n", inode->i_count);
+               return;
+       }
+       if (inode->i_nlink) {
+               printk("free_inode: inode has nlink=%d\n", inode->i_nlink);
+               return;
+       }
+       if (!inode->i_sb) {
+               printk("free_inode: inode on nonexistent device\n");
+               return;
+       }
+       if (inode->i_ino < 1) {
+               printk("free_inode: inode 0 or nonexistent inode\n");
+               return;
+       }
+       qnx4_clear_inode(inode);
+       clear_inode(inode);
+}
+
+#endif
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
new file mode 100644 (file)
index 0000000..189c1a2
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 28-05-1998 by Richard Frowijn : first release.
+ * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support.
+ */
+
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/qnx4_fs.h>
+#include <linux/stat.h>
+
+#include <asm/segment.h>
+
+static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir);
+
+static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       unsigned int offset;
+       struct buffer_head *bh;
+       struct qnx4_inode_entry *de;
+       long blknum;
+       int i;
+       int size;
+
+       blknum = inode->u.qnx4_i.i_first_xtnt.xtnt_blk - 1 +
+           ((filp->f_pos >> 6) >> 3);
+
+       if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
+               return -EBADF;
+       }
+       QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
+       QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
+       QNX4DEBUG(("BlkNum              = %ld\n", (long) blknum));
+
+       while (filp->f_pos < inode->i_size) {
+               bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
+               i = (filp->f_pos - (((filp->f_pos >> 6) >> 3) << 9)) & 0x3f;
+               while (i < QNX4_INODES_PER_BLOCK) {
+                       offset = i * QNX4_DIR_ENTRY_SIZE;
+                       de = (struct qnx4_inode_entry *) (bh->b_data + offset);
+                       size = strlen(de->di_fname);
+                       if (size) {
+
+                               QNX4DEBUG(("qnx4_readdir:%s\n", de->di_fname));
+
+                               if ((de->di_mode) || (de->di_status == QNX4_FILE_LINK)) {
+                                       if (de->di_status) {
+                                               if (filldir(dirent, de->di_fname, size, filp->f_pos, de->di_first_xtnt.xtnt_blk) < 0) {
+                                                       brelse(bh);
+                                                       return 0;
+                                               }
+                                       }
+                               }
+                       }
+                       i++;
+                       filp->f_pos += QNX4_DIR_ENTRY_SIZE;
+               }
+               brelse(bh);
+               blknum++;
+       }
+       UPDATE_ATIME(inode);
+
+       return 0;
+}
+
+static struct file_operations qnx4_dir_operations =
+{
+       NULL,                   /* lseek - default */
+       NULL,                   /* read */
+       NULL,                   /* write - bad */
+       qnx4_readdir,           /* readdir */
+       NULL,                   /* poll - default */
+       NULL,                   /* ioctl - default */
+       NULL,                   /* mmap */
+       NULL,                   /* no special open code */
+        NULL,                   /* no special flush code */
+       NULL,                   /* no special release code */
+       file_fsync,             /* default fsync */
+       NULL,                   /* default fasync */
+       NULL,                   /* default check_media_change */
+       NULL,                   /* default revalidate */
+};
+
+struct inode_operations qnx4_dir_inode_operations =
+{
+       &qnx4_dir_operations,
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_create,
+#else
+       NULL,                   /* create */
+#endif
+       qnx4_lookup,
+       NULL,                   /* link */
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_unlink,            /* unlink */
+#else
+       NULL,
+#endif
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_rmdir,             /* rmdir */
+#else
+       NULL,
+#endif
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* smap */
+};
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
new file mode 100644 (file)
index 0000000..0e67165
--- /dev/null
@@ -0,0 +1,264 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 25-05-1998 by Richard Frowijn : first release.
+ * 21-06-1998 by Frank Denis : wrote qnx4_readpage to use generic_file_read.
+ * 27-06-1998 by Frank Denis : file overwriting.
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/qnx4_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/qnx4_fs.h>
+
+static int qnx4_readpage(struct file *file, struct page *page);
+
+#ifdef CONFIG_QNX4FS_RW
+static ssize_t qnx4_file_write(struct file *filp, const char *buf,
+                              size_t count, loff_t * ppos)
+{
+       struct dentry *dentry = filp->f_dentry;
+       struct inode *inode = dentry->d_inode;
+       struct qnx4_inode_info *qnx4_ino;
+       struct buffer_head *bh;
+       ssize_t result = -EBUSY, c;
+       off_t pos;
+       unsigned long start, block, extent_end;
+       char *p;
+
+       QNX4DEBUG(("qnx4: file_write(%s/%s (%d), %lu@%lu)\n",
+                  dentry->d_parent->d_name.name, dentry->d_name.name,
+         inode->i_count, (unsigned long) count, (unsigned long) *ppos));
+       if (inode == NULL) {
+               printk("qnx4: NULL inode for file_write\n");
+               return -EINVAL;
+       }
+       qnx4_ino = &inode->u.qnx4_i;
+       if (S_ISREG(inode->i_mode) == 0) {
+               printk("qnx4: write to non-file, mode %07o\n", inode->i_mode);
+               return -EINVAL;
+       }
+       if (count == 0) {
+               goto out;
+       }
+       if (filp->f_flags & O_APPEND) {
+               pos = inode->i_size;
+       } else {
+               pos = *ppos;
+       }
+       start = qnx4_ino->i_first_xtnt.xtnt_blk + ((pos >> 9) * 0) - 1;
+       result = 0;
+       extent_end = start + qnx4_ino->i_first_xtnt.xtnt_size - 1;
+       QNX4DEBUG(("qnx4: extent length : [%lu] bytes\n",
+                  qnx4_ino->i_first_xtnt.xtnt_size));
+       while (result < count) {
+               block = start + pos / QNX4_BLOCK_SIZE;
+               if (block > extent_end) {
+                       if (qnx4_is_free(inode->i_sb, block) <= 0) {
+                               printk("qnx4: next inode is busy -> write aborted.\n");
+                               result = -ENOSPC;
+                               break;
+                       }
+               }
+               if ((bh = bread(inode->i_dev, block,
+                               QNX4_BLOCK_SIZE)) == NULL) {
+                       printk("qnx4: I/O error on write.\n");
+                       result = -EIO;
+                       goto out;
+               }
+               if (bh == NULL) {
+                       if (result != 0) {
+                               result = -ENOSPC;
+                       }
+                       break;
+               }
+               if (block > extent_end) {
+                       qnx4_set_bitmap(inode->i_sb, block, 1);
+                       extent_end++;
+                       qnx4_ino->i_first_xtnt.xtnt_size = extent_end - start + 1;
+               }
+               c = QNX4_BLOCK_SIZE - (pos % QNX4_BLOCK_SIZE);
+               if (c > count - result) {
+                       c = count - result;
+               }
+               if (c != QNX4_BLOCK_SIZE && buffer_uptodate(bh) == 0) {
+                       ll_rw_block(WRITE, 1, &bh);
+                       wait_on_buffer(bh);
+                       if (buffer_uptodate(bh) == 0) {
+                               brelse(bh);
+                               if (result != 0) {
+                                       result = -EIO;
+                               }
+                               break;
+                       }
+               }
+               p = bh->b_data + (pos % QNX4_BLOCK_SIZE);
+               c -= copy_from_user(p, buf, c);
+               if (c == 0) {
+                       brelse(bh);
+                       if (result == 0) {
+                               result = -EFAULT;
+                       }
+                       break;
+               }
+               update_vm_cache(inode, pos, p, c);
+               mark_buffer_uptodate(bh, 1);
+               mark_buffer_dirty(bh, 0);
+               brelse(bh);
+               pos += c;
+               buf += c;
+               result += c;
+       }
+       if (pos > inode->i_size) {
+               inode->i_size = pos;
+       }
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       *ppos = pos;
+       mark_inode_dirty(inode);
+
+      out:
+       return result;
+}
+#endif
+
+/*
+ * We have moostly NULL's here: the current defaults are ok for
+ * the qnx4 filesystem.
+ */
+static struct file_operations qnx4_file_operations =
+{
+       NULL,                   /* lseek - default */
+       generic_file_read,      /* read */
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_file_write,        /* write */
+#else
+       NULL,
+#endif
+       NULL,                   /* readdir - bad */
+       NULL,                   /* poll - default */
+       NULL,                   /* ioctl - default */
+       generic_file_mmap,      /* mmap */
+       NULL,                   /* no special open is needed */
+        NULL,                   /* no special flush code */
+       NULL,                   /* release */
+#ifdef CONFIG_QNX4FS_RW   
+       qnx4_sync_file,         /* fsync */
+#else
+        NULL,
+#endif
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+       NULL                    /* lock */
+};
+
+struct inode_operations qnx4_file_inode_operations =
+{
+       &qnx4_file_operations,  /* default file operations */
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_create,            /* create */
+#else
+       NULL,
+#endif
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       qnx4_readpage,          /* readpage */
+       NULL,                   /* writepage */
+       qnx4_bmap,              /* bmap */
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_truncate,          /* truncate */
+#else
+       NULL,
+#endif
+       NULL,                   /* permission */
+       NULL                    /* smap */
+};
+
+static int qnx4_readpage(struct file *file, struct page *page)
+{
+       struct dentry *dentry = file->f_dentry;
+       struct inode *inode = dentry->d_inode;
+       struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
+       unsigned long buf;
+       unsigned long offset, avail, readlen;
+       unsigned long start;
+       unsigned long count;
+       struct buffer_head *bh;
+       int res = -EIO;
+
+       QNX4DEBUG(("qnx4: readpage offset=[%ld]\n", (long) page->offset));
+
+       if (qnx4_ino->i_xblk != 0) {
+               printk("qnx4: sorry, this file is extended, don't know how to handle it (yet) !\n");
+               return -EIO;
+       }
+       atomic_inc(&page->count);
+       set_bit(PG_locked, &page->flags);
+       buf = page_address(page);
+       clear_bit(PG_uptodate, &page->flags);
+       clear_bit(PG_error, &page->flags);
+       offset = page->offset;
+
+       if (offset < inode->i_size) {
+               res = 0;
+               avail = inode->i_size - offset;
+               readlen = MIN(avail, PAGE_SIZE);
+               start = qnx4_ino->i_first_xtnt.xtnt_blk + (offset >> 9) - 1;
+               count = PAGE_SIZE / QNX4_BLOCK_SIZE;
+               do {
+                       QNX4DEBUG(("qnx4: reading page starting at [%ld]\n", (long) start));
+                       if ((bh = bread(inode->i_dev, start, QNX4_BLOCK_SIZE)) == NULL) {
+                               printk("qnx4: data corrupted or I/O error.\n");
+                               res = -EIO;
+                       } else {
+                               memcpy((void *) buf, bh->b_data, QNX4_BLOCK_SIZE);
+                       }
+                       buf += QNX4_BLOCK_SIZE;
+                       start++;
+                       count--;
+               } while (count != 0);
+       }
+       if (res != 0) {
+               set_bit(PG_error, &page->flags);
+               memset((void *) buf, 0, PAGE_SIZE);
+       } else {
+               set_bit(PG_uptodate, &page->flags);
+       }
+       clear_bit(PG_locked, &page->flags);
+       wake_up(&page->wait);
+/*  free_page(buf); */
+
+       return res;
+}
diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c
new file mode 100644 (file)
index 0000000..8e7df05
--- /dev/null
@@ -0,0 +1,165 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 24-03-1998 by Richard Frowijn : first release.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/locks.h>
+
+#include <linux/fs.h>
+#include <linux/qnx4_fs.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#define blocksize QNX4_BLOCK_SIZE
+
+/*
+ * The functions for qnx4 fs file synchronization.
+ */
+
+#ifdef CONFIG_QNX4FS_RW
+
+static int sync_block(struct inode *inode, unsigned short *block, int wait)
+{
+       struct buffer_head *bh;
+       unsigned short tmp;
+
+       if (!*block)
+               return 0;
+       tmp = *block;
+       bh = get_hash_table(inode->i_dev, *block, blocksize);
+       if (!bh)
+               return 0;
+       if (*block != tmp) {
+               brelse(bh);
+               return 1;
+       }
+       if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
+               brelse(bh);
+               return -1;
+       }
+       if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+               brelse(bh);
+               return 0;
+       }
+       ll_rw_block(WRITE, 1, &bh);
+       bh->b_count--;
+       return 0;
+}
+
+static int sync_iblock(struct inode *inode, unsigned short *iblock,
+                      struct buffer_head **bh, int wait)
+{
+       int rc;
+       unsigned short tmp;
+
+       *bh = NULL;
+       tmp = *iblock;
+       if (!tmp)
+               return 0;
+       rc = sync_block(inode, iblock, wait);
+       if (rc)
+               return rc;
+       *bh = bread(inode->i_dev, tmp, blocksize);
+       if (tmp != *iblock) {
+               brelse(*bh);
+               *bh = NULL;
+               return 1;
+       }
+       if (!*bh)
+               return -1;
+       return 0;
+}
+
+static int sync_direct(struct inode *inode, int wait)
+{
+       int i;
+       int rc, err = 0;
+
+       for (i = 0; i < 7; i++) {
+               rc = sync_block(inode,
+                               (unsigned short *) inode->u.qnx4_i.i_first_xtnt.xtnt_blk + i, wait);
+               if (rc > 0)
+                       break;
+               if (rc)
+                       err = rc;
+       }
+       return err;
+}
+
+static int sync_indirect(struct inode *inode, unsigned short *iblock, int wait)
+{
+       int i;
+       struct buffer_head *ind_bh;
+       int rc, err = 0;
+
+       rc = sync_iblock(inode, iblock, &ind_bh, wait);
+       if (rc || !ind_bh)
+               return rc;
+
+       for (i = 0; i < 512; i++) {
+               rc = sync_block(inode,
+                               ((unsigned short *) ind_bh->b_data) + i,
+                               wait);
+               if (rc > 0)
+                       break;
+               if (rc)
+                       err = rc;
+       }
+       brelse(ind_bh);
+       return err;
+}
+
+static int sync_dindirect(struct inode *inode, unsigned short *diblock,
+                         int wait)
+{
+       int i;
+       struct buffer_head *dind_bh;
+       int rc, err = 0;
+
+       rc = sync_iblock(inode, diblock, &dind_bh, wait);
+       if (rc || !dind_bh)
+               return rc;
+
+       for (i = 0; i < 512; i++) {
+               rc = sync_indirect(inode,
+                               ((unsigned short *) dind_bh->b_data) + i,
+                                  wait);
+               if (rc > 0)
+                       break;
+               if (rc)
+                       err = rc;
+       }
+       brelse(dind_bh);
+       return err;
+}
+
+int qnx4_sync_file(struct file *file, struct dentry *dentry)
+{
+        struct inode *inode = dentry->d_inode;
+       int wait, err = 0;
+        
+        (void) file;
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+             S_ISLNK(inode->i_mode)))
+               return -EINVAL;
+
+       for (wait = 0; wait <= 1; wait++) {
+               err |= sync_direct(inode, wait);
+       }
+       err |= qnx4_sync_inode(inode);
+       return (err < 0) ? -EIO : 0;
+}
+
+#endif
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
new file mode 100644 (file)
index 0000000..0aa37dd
--- /dev/null
@@ -0,0 +1,462 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 01-06-1998 by Richard Frowijn : first release.
+ * 20-06-1998 by Frank Denis : Linux 2.1.99+ support, boot signature, misc.
+ * 30-06-1998 by Frank Denis : first step to write inodes.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/qnx4_fs.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+
+#define QNX4_VERSION  4
+#define QNX4_BMNAME   ".bitmap"
+#define CHECK_BOOT_SIGNATURE 0
+
+static struct super_operations qnx4_sops;
+
+#ifdef CONFIG_QNX4FS_RW
+
+int qnx4_sync_inode(struct inode *inode)
+{
+       int err = 0;
+# if 0
+       struct buffer_head *bh;
+
+       bh = qnx4_update_inode(inode);
+       if (bh && buffer_dirty(bh))
+       {
+               ll_rw_block(WRITE, 1, &bh);
+               wait_on_buffer(bh);
+               if (buffer_req(bh) && !buffer_uptodate(bh))
+               {
+                       printk ("IO error syncing qnx4 inode [%s:%08lx]\n",
+                               kdevname(inode->i_dev), inode->i_ino);
+                       err = -1;
+               }
+               brelse (bh);       
+       } else if (!bh) {
+               err = -1;
+       }
+# endif
+
+       return err;
+}
+
+static void qnx4_delete_inode(struct inode *inode)
+{
+       QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino));
+       inode->i_size = 0;
+       qnx4_truncate(inode);
+       qnx4_free_inode(inode);
+}
+
+static void qnx4_write_super(struct super_block *sb)
+{
+       QNX4DEBUG(("qnx4: write_super\n"));
+       sb->s_dirt = 0;
+}
+
+static void qnx4_put_inode(struct inode *inode)
+{
+       if (inode->i_nlink != 0) {
+               return;
+       }
+       inode->i_size = 0;
+}
+
+static void qnx4_write_inode(struct inode *inode)
+{
+       struct qnx4_inode_entry *raw_inode;
+       int block, ino;
+       struct buffer_head *bh;
+       ino = inode->i_ino;
+
+       QNX4DEBUG(("qnx4: write inode 1.\n"));
+       if (inode->i_nlink == 0) {
+               return;
+       }
+       if (!ino) {
+               printk("qnx4: bad inode number on dev %s: %d is out of range\n",
+                      kdevname(inode->i_dev), ino);
+               return;
+       }
+       QNX4DEBUG(("qnx4: write inode 2.\n"));
+       block = ino / QNX4_INODES_PER_BLOCK;
+       if (!(bh = bread(inode->i_dev, block, QNX4_BLOCK_SIZE))) {
+               printk("qnx4: major problem: unable to read inode from dev "
+                      "%s\n", kdevname(inode->i_dev));
+               return;
+       }
+       raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
+           (ino % QNX4_INODES_PER_BLOCK);
+       raw_inode->di_mode = inode->i_mode;
+       raw_inode->di_uid = inode->i_uid;
+       raw_inode->di_gid = inode->i_gid;
+       raw_inode->di_nlink = inode->i_nlink;
+       raw_inode->di_size = inode->i_size;
+       raw_inode->di_mtime = inode->i_mtime;
+       raw_inode->di_atime = inode->i_atime;
+       raw_inode->di_ctime = inode->i_ctime;
+       raw_inode->di_first_xtnt.xtnt_size = inode->i_blocks;
+       mark_buffer_dirty(bh, 1);
+       brelse(bh);
+}
+
+#endif
+
+static struct super_block *qnx4_read_super(struct super_block *, void *, int);
+static void qnx4_put_super(struct super_block *sb);
+static void qnx4_read_inode(struct inode *);
+static int qnx4_remount(struct super_block *sb, int *flags, char *data);
+static int qnx4_statfs(struct super_block *, struct statfs *, int);
+
+static struct super_operations qnx4_sops =
+{
+       qnx4_read_inode,
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_write_inode,
+#else
+       NULL,
+#endif
+       qnx4_put_inode,
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_delete_inode,
+       NULL,                   /* notify_change */
+#else
+       NULL,                   /* delete_inode */
+       NULL,                   /* notify_change */
+#endif
+       qnx4_put_super,
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_write_super,
+#else
+       NULL,
+#endif
+       qnx4_statfs,
+       qnx4_remount,
+       NULL                    /* clear_inode */
+};
+
+static int qnx4_remount(struct super_block *sb, int *flags, char *data)
+{
+       struct qnx4_sb_info *qs;
+
+       qs = &sb->u.qnx4_sb;
+       qs->Version = QNX4_VERSION;
+       if (*flags & MS_RDONLY) {
+               return 0;
+       }
+       mark_buffer_dirty(qs->sb_buf, 1);
+
+       return 0;
+}
+
+struct buffer_head *inode_getblk(struct inode *inode, int nr,
+                                int create)
+{
+       int tmp;
+       int tst;
+       struct buffer_head *result = NULL;
+
+       tst = nr;
+      repeat:
+       tmp = tst;
+       if (tmp) {
+               result = getblk(inode->i_dev, tmp, QNX4_BLOCK_SIZE);
+               if (tmp == tst) {
+                       return result;
+               }
+               brelse(result);
+               goto repeat;
+       }
+       if (!create) {
+               return NULL;
+       }
+#if 0
+       tmp = qnx4_new_block(inode->i_sb);
+       if (!tmp) {
+               return NULL;
+       }
+       result = getblk(inode->i_dev, tmp, QNX4_BLOCK_SIZE);
+       if (tst) {
+               qnx4_free_block(inode->i_sb, tmp);
+               brelse(result);
+               goto repeat;
+       }
+       tst = tmp;
+#endif
+       inode->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(inode);
+       return result;
+}
+
+struct buffer_head *qnx4_bread(struct inode *inode, int block, int create)
+{
+       struct buffer_head *bh;
+
+       bh = inode_getblk(inode, block, create);
+       if (!bh || buffer_uptodate(bh)) {
+               return bh;
+       }
+       ll_rw_block(READ, 1, &bh);
+       wait_on_buffer(bh);
+       if (buffer_uptodate(bh)) {
+               return bh;
+       }
+       brelse(bh);
+
+       return NULL;
+}
+
+static int qnx4_statfs(struct super_block *sb,
+                      struct statfs *buf, int bufsize)
+{
+       struct statfs tmp;
+
+       memset(&tmp, 0, sizeof tmp);
+       tmp.f_type = sb->s_magic;
+       tmp.f_bsize = sb->s_blocksize;
+       tmp.f_blocks = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
+       tmp.f_bfree = qnx4_count_free_blocks(sb);
+       tmp.f_bavail = tmp.f_bfree;
+       tmp.f_files = 0x00;     /* change this !!! */
+       tmp.f_ffree = qnx4_count_free_inodes(sb);
+       tmp.f_namelen = QNX4_NAME_MAX;
+
+       return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+}
+
+/*
+ * Check the root directory of the filesystem to make sure
+ * it really _is_ a qnx4 filesystem, and to check the size
+ * of the directory entry.
+ */
+static const char *qnx4_checkroot(struct super_block *s)
+{
+       struct buffer_head *bh;
+       struct qnx4_inode_entry *rootdir;
+       int rd, rl;
+       int i, j;
+       int found = 0;
+
+       if (s == NULL) {
+               return "no qnx4 filesystem (null superblock).";
+       }
+       if (*(s->u.qnx4_sb.sb->RootDir.di_fname) != '/') {
+               return "no qnx4 filesystem (no root dir).";
+       } else {
+               QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", kdevname(s->s_dev)));
+               rd = s->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk - 1;
+               rl = s->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size;
+               for (j = 0; j < rl; j++) {
+                       bh = bread(s->s_dev, rd + j, QNX4_BLOCK_SIZE);  /* root dir, first block */
+                       if (bh == NULL) {
+                               return "unable to read root entry.";
+                       }
+                       for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) {
+                               rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE);
+                               if (rootdir->di_fname != NULL) {
+                                       QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname));
+                                       if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) {
+                                               found = 1;
+                                               s->u.qnx4_sb.BitMap = rootdir;  /* keep bitmap inode known */
+                                               break;
+                                       }
+                               }
+                       }
+                       brelse(bh);
+                       if (found != 0) {
+                               break;
+                       }
+               }
+               if (found == 0) {
+                       return "bitmap file not found.";
+               }
+       }
+       return NULL;
+}
+
+static struct super_block *qnx4_read_super(struct super_block *s, 
+                                          void *data, int silent)
+{
+       struct buffer_head *bh;
+       kdev_t dev = s->s_dev;
+#if CHECK_BOOT_SIGNATURE
+       char *tmpc;
+#endif
+       const char *errmsg;
+
+       MOD_INC_USE_COUNT;
+       lock_super(s);
+       set_blocksize(dev, QNX4_BLOCK_SIZE);
+       s->s_blocksize = QNX4_BLOCK_SIZE;
+       s->s_blocksize_bits = 9;
+       s->s_dev = dev;
+
+#if CHECK_BOOT_SIGNATURE
+       bh = bread(dev, 0, QNX4_BLOCK_SIZE);
+       if (!bh) {
+               printk("qnx4: unable to read the boot sector\n");
+               goto outnobh;
+       }
+       tmpc = (char *) bh->b_data;
+       if (tmpc[4] != 'Q' || tmpc[5] != 'N' || tmpc[6] != 'X' ||
+           tmpc[7] != '4' || tmpc[8] != 'F' || tmpc[9] != 'S') {
+               printk("qnx4: wrong fsid in boot sector.\n");
+               goto out;
+       }
+       brelse(bh);
+#endif
+       bh = bread(dev, 1, QNX4_BLOCK_SIZE);
+       if (!bh) {
+               printk("qnx4: unable to read the superblock\n");
+               goto outnobh;
+       }
+       s->s_op = &qnx4_sops;
+       s->s_magic = QNX4_SUPER_MAGIC;
+#ifndef CONFIG_QNX4FS_RW
+       s->s_flags |= MS_RDONLY;        /* Yup, read-only yet */
+#endif
+       s->u.qnx4_sb.sb_buf = bh;
+       s->u.qnx4_sb.sb = (struct qnx4_super_block *) bh->b_data;
+       s->s_root =
+           d_alloc_root(iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK), NULL);
+       if (s->s_root == NULL) {
+               printk("qnx4: get inode failed\n");
+               goto out;
+       }
+       errmsg = qnx4_checkroot(s);
+       if (errmsg != NULL) {
+               printk("qnx4: %s\n", errmsg);
+               goto out;
+       }
+       brelse(bh);
+       unlock_super(s);
+       s->s_dirt = 1;
+
+       return s;
+
+      out:
+       brelse(bh);
+      outnobh:
+       s->s_dev = 0;
+       unlock_super(s);
+       MOD_DEC_USE_COUNT;
+
+       return NULL;
+}
+
+static void qnx4_put_super(struct super_block *sb)
+{
+       MOD_DEC_USE_COUNT;
+       return;
+}
+
+static void qnx4_read_inode(struct inode *inode)
+{
+       struct buffer_head *bh;
+       struct qnx4_inode_entry *raw_inode;
+       int block, ino;
+
+       ino = inode->i_ino;
+       inode->i_op = NULL;
+       inode->i_mode = 0;
+
+       QNX4DEBUG(("Reading inode : [%d]\n", ino));
+       if (!ino) {
+               printk("qnx4: bad inode number on dev %s: %d is out of range\n",
+                      kdevname(inode->i_dev), ino);
+               return;
+       }
+       block = ino / QNX4_INODES_PER_BLOCK;
+
+       if (!(bh = bread(inode->i_dev, block, QNX4_BLOCK_SIZE))) {
+               printk("qnx4: major problem: unable to read inode from dev "
+                      "%s\n", kdevname(inode->i_dev));
+               return;
+       }
+       raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
+           (ino % QNX4_INODES_PER_BLOCK);
+
+       inode->i_mode = raw_inode->di_mode;
+       inode->i_uid = raw_inode->di_uid;
+       inode->i_gid = raw_inode->di_gid;
+       inode->i_nlink = raw_inode->di_nlink;
+       inode->i_size = raw_inode->di_size;
+       inode->i_mtime = raw_inode->di_mtime;
+       inode->i_atime = raw_inode->di_atime;
+       inode->i_ctime = raw_inode->di_ctime;
+       inode->i_blocks = raw_inode->di_first_xtnt.xtnt_size;
+       inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
+
+       memcpy(&inode->u.qnx4_i, (struct qnx4_inode_info *) raw_inode, QNX4_DIR_ENTRY_SIZE);
+       inode->i_op = &qnx4_file_inode_operations;
+       if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &qnx4_file_inode_operations;
+       } else {
+               if (S_ISDIR(inode->i_mode)) {
+                       inode->i_op = &qnx4_dir_inode_operations;
+               } else {
+                       if (S_ISLNK(inode->i_mode)) {
+                               inode->i_op = &qnx4_symlink_inode_operations;
+                       } else {
+                               if (S_ISCHR(inode->i_mode)) {
+                                       inode->i_op = &chrdev_inode_operations;
+                               } else {
+                                       if (S_ISBLK(inode->i_mode)) {
+                                               inode->i_op = &blkdev_inode_operations;
+                                       } else {
+                                               if (S_ISFIFO(inode->i_mode)) {
+                                                       init_fifo(inode);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       brelse(bh);
+}
+
+static struct file_system_type qnx4_fs_type =
+{
+       "qnx4",
+       FS_REQUIRES_DEV,
+       qnx4_read_super,
+       NULL
+};
+
+__initfunc(int init_qnx4_fs(void))
+{
+       printk("QNX4 filesystem v0.2 registered.\n");
+       return register_filesystem(&qnx4_fs_type);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+       return init_qnx4_fs();
+}
+
+void cleanup_module(void)
+{
+       unregister_filesystem(&qnx4_fs_type);
+}
+
+#endif
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
new file mode 100644 (file)
index 0000000..4d91a2d
--- /dev/null
@@ -0,0 +1,278 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 01-06-1998 by Richard Frowijn : first release.
+ * 21-06-1998 by Frank Denis : dcache support, fixed error codes.
+ * 04-07-1998 by Frank Denis : first step for rmdir/unlink.
+ */
+
+#include <linux/sched.h>
+#include <linux/qnx4_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+#include <asm/segment.h>
+
+/*
+ * check if the filename is correct. For some obscure reason, qnx writes a
+ * new file twice in the directory entry, first with all possible options at 0
+ * and for a second time the way it is, they want us not to access the qnx
+ * filesystem when whe are using linux.
+ */
+static int qnx4_match(int len, const char *name,
+                     struct buffer_head *bh, unsigned long *offset)
+{
+       struct qnx4_inode_entry *de;
+       int namelen;
+
+       if (bh == NULL) {
+               printk("qnx4: matching unassigned buffer !\n");
+               return 0;
+       }
+       de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
+       *offset += QNX4_DIR_ENTRY_SIZE;
+       if ((de->di_status & 0x08) == 0x08) {
+               namelen = QNX4_NAME_MAX;
+       } else {
+               namelen = _SHORT_NAME_MAX;
+       }
+       /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+       if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) {
+               return 1;
+       }
+       if (len != strlen(de->di_fname)) {
+               return 0;
+       }
+       if (strncmp(name, de->di_fname, len) == 0) {
+               if ((de->di_mode) || (de->di_status == QNX4_FILE_LINK)) {
+                       if (de->di_status) {
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
+          const char *name, struct qnx4_inode_entry **res_dir, int *ino)
+{
+       unsigned long block, offset, blkofs;
+       struct buffer_head *bh;
+
+       *res_dir = NULL;
+       if (!dir || !dir->i_sb) {
+               if (!dir) {
+                       printk("qnx4: NULL dir.\n");
+               } else {
+                       printk("qnx4: no superblock on dir.\n");
+               }
+               return NULL;
+       }
+       bh = NULL;
+       blkofs = dir->u.qnx4_i.i_first_xtnt.xtnt_blk - 1;
+       offset = block = 0;
+       while (block * QNX4_BLOCK_SIZE + offset < dir->i_size) {
+               if (!bh) {
+                       bh = qnx4_bread(dir, block + blkofs, 0);
+                       if (!bh) {
+                               block++;
+                               continue;
+                       }
+               }
+               *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
+               if (qnx4_match(len, name, bh, &offset)) {
+                       *ino = (block + blkofs) * QNX4_INODES_PER_BLOCK +
+                           (offset / QNX4_DIR_ENTRY_SIZE) - 1;
+                       return bh;
+               }
+               if (offset < bh->b_size) {
+                       continue;
+               }
+               brelse(bh);
+               bh = NULL;
+               offset = 0;
+               block++;
+       }
+       brelse(bh);
+       *res_dir = NULL;
+       return NULL;
+}
+
+int qnx4_lookup(struct inode *dir, struct dentry *dentry)
+{
+       int ino;
+       struct qnx4_inode_entry *de;
+       struct qnx4_link_info *lnk;
+       struct buffer_head *bh;
+       const char *name = dentry->d_name.name;
+       int len = dentry->d_name.len;
+       struct inode *foundinode;
+
+       if (!dir) {
+               return -EBADF;
+       }
+       if (!S_ISDIR(dir->i_mode)) {
+               return -EBADF;
+       }
+       if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) {
+               return -ENOENT;
+       }
+       /* The entry is linked, let's get the real info */
+       if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
+               lnk = (struct qnx4_link_info *) de;
+               ino = (lnk->dl_inode_blk - 1) * QNX4_INODES_PER_BLOCK +
+                   lnk->dl_inode_ndx;
+       }
+       brelse(bh);
+
+       if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
+               QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
+               return -EACCES;
+       }
+       d_add(dentry, foundinode);
+
+       return 0;
+}
+
+#ifdef CONFIG_QNX4FS_RW
+int qnx4_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+       QNX4DEBUG(("qnx4: qnx4_create\n"));
+       if (dir == NULL) {
+               return -ENOENT;
+       }
+       return -ENOSPC;
+}
+
+int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       struct buffer_head *bh;
+       struct qnx4_inode_entry *de;
+       struct inode *inode;
+       int retval;
+       int ino;
+
+       QNX4DEBUG(("qnx4: qnx4_rmdir [%s]\n", dentry->d_name.name));
+       bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
+                            &de, &ino);
+       if (bh == NULL) {
+               return -ENOENT;
+       }
+       if ((inode = iget(dir->i_sb, ino)) == NULL) {
+               QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
+               retval = -EACCES;
+               goto end_rmdir;
+       }
+       retval = -EPERM;
+       if ((dir->i_mode & S_ISVTX) &&
+           current->fsuid != inode->i_uid &&
+           current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) {
+               QNX4DEBUG(("qnx4: rmdir->capabilities\n"));
+               goto end_rmdir;
+       }
+       if (inode->i_dev != dir->i_dev) {
+               QNX4DEBUG(("qnx4: rmdir->different devices\n"));
+               goto end_rmdir;
+       }
+       if (inode == dir) {     /* we may not delete ".", but "../dir" is ok */
+               QNX4DEBUG(("qnx4: inode==dir\n"));
+               goto end_rmdir;
+       }
+       if (!S_ISDIR(inode->i_mode)) {
+               QNX4DEBUG(("qnx4: rmdir->not a directory\n"));
+               retval = -ENOTDIR;
+               goto end_rmdir;
+       }
+#if 0
+       if (!empty_dir(inode)) {
+               retval = -ENOTEMPTY;
+               goto end_rmdir;
+       }
+#endif
+       if (dentry->d_count > 1) {
+               retval = -EBUSY;
+               goto end_rmdir;
+       }
+       if (inode->i_nlink != 2) {
+               QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink));
+       }
+       QNX4DEBUG(("qnx4: deleting directory\n"));
+       de->di_status = 0;
+       memset(de->di_fname, 0, sizeof de->di_fname);
+       de->di_mode = 0;
+       mark_buffer_dirty(bh, 1);
+       inode->i_nlink = 0;
+       mark_inode_dirty(inode);
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       dir->i_nlink--;
+       mark_inode_dirty(dir);
+       d_delete(dentry);
+       retval = 0;
+
+      end_rmdir:
+       brelse(bh);
+
+       return retval;
+}
+
+int qnx4_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct buffer_head *bh;
+       struct qnx4_inode_entry *de;
+       struct inode *inode;
+       int retval;
+       int ino;
+
+       QNX4DEBUG(("qnx4: qnx4_unlink [%s]\n", dentry->d_name.name));
+       bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
+                            &de, &ino);
+       if (bh == NULL) {
+               return -ENOENT;
+       }
+       if ((inode = iget(dir->i_sb, ino)) == NULL) {
+               QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
+               retval = -EACCES;
+               goto end_unlink;
+       }
+       retval = -EPERM;
+       if (S_ISDIR(inode->i_mode)) {
+               goto end_unlink;
+       }
+       if ((dir->i_mode & S_ISVTX) &&
+           current->fsuid != inode->i_uid &&
+           current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) {
+               goto end_unlink;
+       }
+       if (!inode->i_nlink) {
+               QNX4DEBUG(("Deleting nonexistent file (%s:%lu), %d\n",
+                          kdevname(inode->i_dev),
+                          inode->i_ino, inode->i_nlink));
+               inode->i_nlink = 1;
+       }
+       de->di_status = 0;
+       memset(de->di_fname, 0, sizeof de->di_fname);
+       de->di_mode = 0;
+       mark_buffer_dirty(bh, 1);
+       dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       mark_inode_dirty(dir);
+       inode->i_nlink--;
+       inode->i_ctime = dir->i_ctime;
+       mark_inode_dirty(inode);
+       d_delete(dentry);
+       retval = 0;
+
+      end_unlink:
+       brelse(bh);
+
+       return retval;
+}
+#endif
diff --git a/fs/qnx4/symlinks.c b/fs/qnx4/symlinks.c
new file mode 100644 (file)
index 0000000..3263601
--- /dev/null
@@ -0,0 +1,120 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 28-05-1998 by Richard Frowijn : first release.
+ * 21-06-1998 by Frank Denis : ugly changes to make it compile on Linux 2.1.99+
+ */
+
+/* THIS FILE HAS TO BE REWRITTEN */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/qnx4_fs.h>
+#include <linux/stat.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+static int qnx4_readlink(struct dentry *, char *, int);
+static struct dentry *qnx4_follow_link(struct dentry *, struct dentry *);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations qnx4_symlink_inode_operations =
+{
+       NULL,                   /* no file-operations */
+#ifdef CONFIG_QNX4FS_RW
+       qnx4_create,            /* create */
+#else
+       NULL,
+#endif
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       qnx4_readlink,          /* readlink */
+       qnx4_follow_link,       /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL                    /* permission */
+};
+
+static struct dentry *qnx4_follow_link(struct dentry *dentry,
+                                      struct dentry *base)
+{
+#if 0
+       struct inode *inode = dentry->d_inode;
+       struct buffer_head *bh;
+
+       if (!inode) {
+               return ERR_PTR(-ENOENT);
+       }
+       if (current->link_count > 5) {
+               return ERR_PTR(-ELOOP);
+       }
+       if (!(bh = qnx4_bread(inode, 0, 0))) {
+               return ERR_PTR(-EIO);
+       }
+       current->link_count++;
+       current->link_count--;
+       brelse(bh);
+       return 0;
+#else
+       printk("qnx4: qnx4_follow_link needs to be fixed.\n");
+       return ERR_PTR(-EIO);
+#endif
+}
+
+static int qnx4_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+       struct inode *inode = dentry->d_inode;
+       struct buffer_head *bh;
+       int i;
+       char c;
+       struct qnx4_inode_info *qnx4_ino;
+
+       QNX4DEBUG(("qnx4: qnx4_readlink() called\n"));
+
+       if (buffer == NULL || inode == NULL || !S_ISLNK(inode->i_mode)) {
+               return -EINVAL;
+       }
+       qnx4_ino = &inode->u.qnx4_i;
+       if (buflen > 1023) {
+               buflen = 1023;
+       }
+       bh = bread(inode->i_dev, qnx4_ino->i_first_xtnt.xtnt_blk,
+                  QNX4_BLOCK_SIZE);
+       QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
+                  bh->b_data));
+       if (bh == NULL) {
+               QNX4DEBUG(("qnx4: NULL symlink bh\n"));
+               return 0;
+       }
+       if (bh->b_data[0] != 0) {
+               i = 0;
+               while (i < buflen && (c = bh->b_data[i])) {
+                       i++;
+                       put_user(c, buffer++);
+               }
+               brelse(bh);
+               return i;
+       } else {
+               brelse(bh);
+               memcpy(buffer, "fixme", 5);
+               return 5;
+       }
+}
diff --git a/fs/qnx4/truncate.c b/fs/qnx4/truncate.c
new file mode 100644 (file)
index 0000000..928416d
--- /dev/null
@@ -0,0 +1,37 @@
+/* 
+ * QNX4 file system, Linux implementation.
+ * 
+ * Version : 0.1
+ * 
+ * Using parts of the xiafs filesystem.
+ * 
+ * History :
+ * 
+ * 30-06-1998 by Frank DENIS : ugly filler.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/qnx4_fs.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_QNX4FS_RW
+
+void qnx4_truncate(struct inode *inode)
+{
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+             S_ISLNK(inode->i_mode))) {
+               return;
+       }
+       if (!(S_ISDIR(inode->i_mode))) {
+               /* TODO */
+       }
+       QNX4DEBUG(("qnx4: qnx4_truncate called\n"));
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(inode);
+}
+
+#endif
index 1f5c69e674a1bb66602fbfae055a918d5fa004ed..e36a2d1e1add742d726554eb12bf4698142c3839 100644 (file)
@@ -288,7 +288,7 @@ asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
        file = fget(fd);
        if (!file)
                goto bad_file;
-       if (file->f_mode & FMODE_READ)
+       if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
                ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
        fput(file);
 
@@ -309,7 +309,7 @@ asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
        file = fget(fd);
        if (!file)
                goto bad_file;
-       if (file->f_mode & FMODE_WRITE) {
+       if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
                down(&file->f_dentry->d_inode->i_sem);
                ret = do_readv_writev(VERIFY_READ, file, vector, count);
                up(&file->f_dentry->d_inode->i_sem);
index 4d7a66fdf888f0f4336120dcb55f4ecd7015b25a..cad2910fe3e04bbda1b624e97f97d2b98dfe13a7 100644 (file)
@@ -195,4 +195,22 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
        return csum_fold(sum);
 }
 
+/* 
+ *     Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+                                   int len, int sum, int *err_ptr)
+{
+       int *src_err_ptr=NULL;
+
+       if (verify_area(VERIFY_WRITE, dst, len) == 0)
+               return csum_partial_copy_generic(src, dst, len, sum, src_err_ptr, err_ptr);
+
+       if (len)
+               *err_ptr = -EFAULT;
+
+       return sum;
+}
+
 #endif
index 40728572ca5e706870abcd3be728d173575b79d4..39506e6a33d18140f57958fe17a386590061a663 100644 (file)
@@ -272,6 +272,7 @@ static inline int buffer_protected(struct buffer_head * bh)
 #include <linux/smb_fs_i.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/adfs_fs_i.h>
+#include <linux/qnx4_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -381,6 +382,7 @@ struct inode {
                struct smb_inode_info           smbfs_i;
                struct hfs_inode_info           hfs_i;
                struct adfs_inode_info          adfs_i;
+               struct qnx4_inode_info          qnx4_i;    
                struct socket                   socket_i;
                void                            *generic_ip;
        } u;
@@ -534,6 +536,7 @@ extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
 #include <linux/smb_fs_sb.h>
 #include <linux/hfs_fs_sb.h>
 #include <linux/adfs_fs_sb.h>
+#include <linux/qnx4_fs_sb.h>
 
 extern struct list_head super_blocks;
 
@@ -575,6 +578,7 @@ struct super_block {
                struct smb_sb_info      smbfs_sb;
                struct hfs_sb_info      hfs_sb;
                struct adfs_sb_info     adfs_sb;
+               struct qnx4_sb_info     qnx4_sb;           
                void                    *generic_sbp;
        } u;
 };
index b2b747d20fbba6ab1f72b8b28812768ed35f57ac..18b8f35a5d3faad98a0cf3b8abe2032b9a2d0bbe 100644 (file)
@@ -49,7 +49,7 @@ struct partition {
        unsigned char end_cyl;          /* end cylinder */
        unsigned int start_sect;        /* starting sector counting from 0 */
        unsigned int nr_sects;          /* nr of sectors in partition */
-};
+} __attribute__((packed));
 
 struct hd_struct {
        long start_sect;
index d11d8e0c3a9c5de6264c9fd8b7044c34e34ed07f..e33eaa41865582da422312bf668ce6794b5c06a5 100644 (file)
@@ -110,9 +110,9 @@ void        nfsd_fh_free(void);
 static __inline__ struct svc_fh *
 fh_copy(struct svc_fh *dst, struct svc_fh *src)
 {
-       if (src->fh_dverified) {
+       if (src->fh_dverified || src->fh_locked) {
                struct dentry *dentry = src->fh_dentry;
-               printk("fh_copy: copying %s/%s, already verified!\n",
+               printk(KERN_ERR "fh_copy: copying %s/%s, already verified!\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name);
        }
                        
@@ -133,18 +133,24 @@ fh_init(struct svc_fh *fhp)
 static inline void
 fh_lock(struct svc_fh *fhp)
 {
-       struct inode    *inode = fhp->fh_dentry->d_inode;
+       struct dentry   *dentry = fhp->fh_dentry;
+       struct inode    *inode;
 
        /*
        dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n",
                        SVCFH_DEV(fhp), SVCFH_INO(fhp), fhp->fh_locked);
         */
+       if (!fhp->fh_dverified) {
+               printk(KERN_ERR "fh_lock: fh not verified!\n");
+               return;
+       }
        if (fhp->fh_locked) {
                printk(KERN_WARNING "fh_lock: %s/%s already locked!\n",
-                       fhp->fh_dentry->d_parent->d_name.name,
-                       fhp->fh_dentry->d_name.name);
+                       dentry->d_parent->d_name.name, dentry->d_name.name);
                return;
        }
+
+       inode = dentry->d_inode;
        down(&inode->i_sem);
        if (!fhp->fh_pre_mtime)
                fhp->fh_pre_mtime = inode->i_mtime;
@@ -157,8 +163,13 @@ fh_lock(struct svc_fh *fhp)
 static inline void
 fh_unlock(struct svc_fh *fhp)
 {
+       if (!fhp->fh_dverified)
+               printk(KERN_ERR "fh_unlock: fh not verified!\n");
+
        if (fhp->fh_locked) {
-               struct inode *inode = fhp->fh_dentry->d_inode;
+               struct dentry *dentry = fhp->fh_dentry;
+               struct inode *inode = dentry->d_inode;
+
                if (!fhp->fh_post_version)
                        fhp->fh_post_version = inode->i_version;
                fhp->fh_locked = 0;
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
new file mode 100644 (file)
index 0000000..eb2b3dc
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  Name                         : qnx4_fs.h
+ *  Author                       : Richard Frowijn
+ *  Function                     : qnx4 global filesystem definitions
+ *  Version                      : 1.0
+ *  Last modified                : 23-03-1998
+ *
+ *  History                      : 23-03-1998 created
+ */
+#ifndef _LINUX_QNX4_FS_H
+#define _LINUX_QNX4_FS_H
+
+#include <linux/qnxtypes.h>
+
+#define QNX4_ROOT_INO 1
+
+#define _MAX_XTNTS_PER_XBLK    60
+/* for di_status */
+#define QNX4_FILE_USED          0x01
+#define QNX4_FILE_MODIFIED      0x02
+#define QNX4_FILE_BUSY          0x04
+#define QNX4_FILE_LINK          0x08
+#define QNX4_FILE_INODE         0x10
+#define QNX4_FILE_FSYSCLEAN     0x20
+
+#define QNX4_I_MAP_SLOTS       8
+#define QNX4_Z_MAP_SLOTS       64
+#define QNX4_SUPER_MAGIC       0x002f  /* qnx4 fs detection */
+#define QNX4_VALID_FS          0x0001  /* Clean fs. */
+#define QNX4_ERROR_FS          0x0002  /* fs has errors. */
+#define QNX4_BLOCK_SIZE         0x200  /* blocksize of 512 bytes */
+#define QNX4_DIR_ENTRY_SIZE     0x040  /* dir entry size */
+#define QNX4_XBLK_ENTRY_SIZE    0x200  /* xblk entry size */
+#define QNX4_INODES_PER_BLOCK   0x08   /* 512 / 64 */
+
+/* for filenames */
+#define _SHORT_NAME_MAX        16
+#define QNX4_NAME_MAX          48
+
+/*
+ * This is the original qnx4 inode layout on disk.
+ */
+struct qnx4_inode_entry {
+       char di_fname[16];
+       off_t di_size;
+       _xtnt_t di_first_xtnt;
+       long di_xblk;
+       time_t di_ftime;
+       time_t di_mtime;
+       time_t di_atime;
+       time_t di_ctime;
+       _nxtnt_t di_num_xtnts;
+       mode_t di_mode;
+       muid_t di_uid;
+       mgid_t di_gid;
+       nlink_t di_nlink;
+       char di_zero[4];
+       _ftype_t di_type;
+       unsigned char di_status;
+};
+
+struct qnx4_link_info {
+       char dl_fname[QNX4_NAME_MAX];
+       long dl_inode_blk;
+       unsigned char dl_inode_ndx;
+       unsigned char dl_spare[10];
+       unsigned char dl_status;
+};
+
+struct qnx4_xblk {
+       long xblk_next_xblk;
+       long xblk_prev_xblk;
+       unsigned char xblk_num_xtnts;
+       char xblk_spare[3];
+       long xblk_num_blocks;
+       _xtnt_t xblk_xnts[_MAX_XTNTS_PER_XBLK];
+       char xblk_signature[8];
+       _xtnt_t xblk_first_xtnt;
+};
+
+struct qnx4_super_block {
+       struct qnx4_inode_entry RootDir;
+       struct qnx4_inode_entry Inode;
+       struct qnx4_inode_entry Boot;
+       struct qnx4_inode_entry AltBoot;
+};
+
+#ifdef __KERNEL__
+
+#define QNX4_DEBUG 0
+
+#if QNX4_DEBUG
+#define QNX4DEBUG(X) printk X
+#else
+#define QNX4DEBUG(X) (void) 0
+#endif
+
+extern int qnx4_lookup(struct inode *dir, struct dentry *dentry);
+extern unsigned long qnx4_count_free_inodes(struct super_block *sb);
+extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
+
+extern struct buffer_head *qnx4_getblk(struct inode *, int, int);
+extern struct buffer_head *qnx4_bread(struct inode *, int, int);
+
+extern int init_qnx4_fs(void);
+extern int qnx4_create(struct inode *dir, struct dentry *dentry, int mode);
+extern struct inode_operations qnx4_file_inode_operations;
+extern struct inode_operations qnx4_dir_inode_operations;
+extern struct inode_operations qnx4_symlink_inode_operations;
+extern int qnx4_is_free(struct super_block *sb, int block);
+extern int qnx4_set_bitmap(struct super_block *sb, int block, int busy);
+extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode);
+extern void qnx4_truncate(struct inode *inode);
+extern void qnx4_free_inode(struct inode *inode);
+extern int qnx4_unlink(struct inode *dir, struct dentry *dentry);
+extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
+extern int qnx4_sync_file(struct file *file, struct dentry *dentry);
+extern int qnx4_sync_inode(struct inode *inode);
+extern int qnx4_bmap(struct inode *inode, int block);
+
+#endif                         /* __KERNEL__ */
+
+#endif
diff --git a/include/linux/qnx4_fs_i.h b/include/linux/qnx4_fs_i.h
new file mode 100644 (file)
index 0000000..83d53e5
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Name                         : qnx4_fs_i.h
+ *  Author                       : Richard Frowijn
+ *  Function                     : qnx4 inode definitions
+ *  Version                      : 1.0
+ *  Last modified                : 25-05-1998
+ * 
+ *  History                      : 23-03-1998 created
+ * 
+ */
+#ifndef _QNX4_FS_I
+#define _QNX4_FS_I
+
+#include <linux/qnxtypes.h>
+
+/*
+ * qnx4 fs inode entry 
+ */
+struct qnx4_inode_info {
+       char i_reserved[16];    /* 16 */
+       off_t i_size;           /*  4 */
+       _xtnt_t i_first_xtnt;   /*  8 */
+       long i_xblk;            /*  4 */
+       time_t i_ftime;         /*  4 */
+       time_t i_mtime;         /*  4 */
+       time_t i_atime;         /*  4 */
+       time_t i_ctime;         /*  4 */
+       _nxtnt_t i_num_xtnts;   /*  2 */
+       mode_t i_mode;          /*  2 */
+       muid_t i_uid;           /*  2 */
+       mgid_t i_gid;           /*  2 */
+       nlink_t i_nlink;        /*  2 */
+       char i_zero[4];         /*  4 */
+       _ftype_t i_type;        /*  1 */
+       unsigned char i_status; /*  1 */
+};
+
+#endif
diff --git a/include/linux/qnx4_fs_sb.h b/include/linux/qnx4_fs_sb.h
new file mode 100644 (file)
index 0000000..9f28d3c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  Name                         : qnx4_fs_sb.h
+ *  Author                       : Richard Frowijn
+ *  Function                     : qnx4 superblock definitions
+ *  Version                      : 1.0
+ *  Last modified                : 20-05-1998
+ * 
+ *  History                      : 23-03-1998 created
+ * 
+ */
+#ifndef _QNX4_FS_SB
+#define _QNX4_FS_SB
+
+#include <linux/qnxtypes.h>
+
+/*
+ * qnx4 super-block data in memory
+ */
+
+struct qnx4_sb_info {
+       struct buffer_head *sb_buf;     /* superblock buffer */
+       struct qnx4_super_block *sb;    /* our superblock */
+       unsigned int Version;   /* may be useful */
+       struct qnx4_inode_entry *BitMap;        /* useful */
+};
+
+#endif
diff --git a/include/linux/qnxtypes.h b/include/linux/qnxtypes.h
new file mode 100644 (file)
index 0000000..054da0d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  Name                         : qnxtypes.h
+ *  Author                       : Richard Frowijn
+ *  Function                     : standard qnx types
+ *  Version                      : 1.0
+ *  Last modified                : 22-03-1998
+ * 
+ *  History                      : 22-03-1998 created
+ * 
+ */
+
+#ifndef _QNX4TYPES_H
+#define _QNX4TYPES_H
+
+typedef unsigned short _nxtnt_t;
+typedef unsigned char _ftype_t;
+
+typedef struct {
+       long xtnt_blk;
+       long xtnt_size;
+} _xtnt_t;
+
+typedef unsigned short muid_t;
+typedef unsigned short mgid_t;
+typedef unsigned long qnx_off_t;
+typedef unsigned short qnx_nlink_t;
+
+#endif
index aeeff7ef4e4b8a97d99074ad419682bce3664808..7cb0ddcf8efd4938e79a7ce50d53bf75c58e43d0 100644 (file)
@@ -75,6 +75,7 @@ extern int try_to_free_pages(unsigned int gfp_mask, int count);
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, unsigned long, char *, int);
 extern void rw_swap_page_nocache(int, unsigned long, char *);
+extern void swap_after_unlock_page (unsigned long entry);
 
 /* linux/mm/page_alloc.c */
 extern void swap_in(struct task_struct *, struct vm_area_struct *,
@@ -84,10 +85,15 @@ extern void swap_in(struct task_struct *, struct vm_area_struct *,
 /* linux/mm/swap_state.c */
 extern void show_swap_cache_info(void);
 extern int add_to_swap_cache(struct page *, unsigned long);
-extern void swap_duplicate(unsigned long);
-extern void swap_after_unlock_page (unsigned long entry);
+extern int swap_duplicate(unsigned long);
+extern int swap_check_entry(unsigned long);
 extern struct page * read_swap_cache_async(unsigned long, int);
 #define read_swap_cache(entry) read_swap_cache_async(entry, 1);
+/*
+ * Make these inline later once they are working properly.
+ */
+extern void delete_from_swap_cache(struct page *page);
+extern void free_page_and_swap_cache(unsigned long addr);
 
 /* linux/mm/swapfile.c */
 extern unsigned int nr_swapfiles;
@@ -100,6 +106,8 @@ struct swap_list_t {
        int next;       /* swapfile to be used next */
 };
 extern struct swap_list_t swap_list;
+int sys_swapoff(const char *);
+int sys_swapon(const char *, int);
 
 /*
  * vm_ops not present page codes for shared memory.
@@ -148,14 +156,6 @@ static inline int is_page_shared(struct page *page)
        return (count > 1);
 }
 
-/*
- * Make these inline later once they are working properly.
- */
-extern long find_in_swap_cache(struct page *page);
-extern int delete_from_swap_cache(struct page *page);
-extern void remove_from_swap_cache(struct page *page);
-extern void free_page_and_swap_cache(unsigned long addr);
-
 #endif /* __KERNEL__*/
 
 #endif /* _LINUX_SWAP_H */
index 1938d0be3f85aa5e49275da7febfddbaf8294b16..7cb2f24dd68d4daacafd7cabe1c5fabf072270c5 100644 (file)
@@ -125,4 +125,8 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
        return -ENOSYS;
 }
 
+void shm_unuse(unsigned long entry, unsigned long page)
+{
+}
+
 #endif /* CONFIG_SYSVIPC */
index a6c45008dc02d86dc459f9b805e32a7637421545..bbaf33d2cf71fd7f8a6d49ceb24f6626859f3af7 100644 (file)
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
-#ifdef SWAP_CACHE_INFO
-unsigned long swap_cache_add_total = 0;
-unsigned long swap_cache_add_success = 0;
-unsigned long swap_cache_del_total = 0;
-unsigned long swap_cache_del_success = 0;
-unsigned long swap_cache_find_total = 0;
-unsigned long swap_cache_find_success = 0;
-
 /* 
  * Keep a reserved false inode which we will use to mark pages in the
  * page cache are acting as swap cache instead of file cache. 
@@ -43,6 +35,13 @@ unsigned long swap_cache_find_success = 0;
  */
 struct inode swapper_inode;
 
+#ifdef SWAP_CACHE_INFO
+unsigned long swap_cache_add_total = 0;
+unsigned long swap_cache_add_success = 0;
+unsigned long swap_cache_del_total = 0;
+unsigned long swap_cache_del_success = 0;
+unsigned long swap_cache_find_total = 0;
+unsigned long swap_cache_find_success = 0;
 
 void show_swap_cache_info(void)
 {
@@ -63,13 +62,13 @@ int add_to_swap_cache(struct page *page, unsigned long entry)
               page_address(page), atomic_read(&page->count), entry);
 #endif
        if (PageTestandSetSwapCache(page)) {
-               printk("swap_cache: replacing non-empty entry %08lx "
+               printk(KERN_ERR "swap_cache: replacing non-empty entry %08lx "
                       "on page %08lx\n",
                       page->offset, page_address(page));
                return 0;
        }
        if (page->inode) {
-               printk("swap_cache: replacing page-cached entry "
+               printk(KERN_ERR "swap_cache: replacing page-cached entry "
                       "on page %08lx\n", page_address(page));
                return 0;
        }
@@ -85,12 +84,16 @@ int add_to_swap_cache(struct page *page, unsigned long entry)
 }
 
 /*
- * If swap_map[] reaches SWAP_MAP_MAX the entries are treated as "permanent".
+ * Verify that a swap entry is valid and increment its swap map count.
+ *
+ * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
+ * "permanent", but will be reclaimed by the next swapoff.
  */
-void swap_duplicate(unsigned long entry)
+int swap_duplicate(unsigned long entry)
 {
        struct swap_info_struct * p;
        unsigned long offset, type;
+       int result = 0;
 
        if (!entry)
                goto out;
@@ -105,36 +108,44 @@ void swap_duplicate(unsigned long entry)
                goto bad_offset;
        if (!p->swap_map[offset])
                goto bad_unused;
+       /*
+        * Entry is valid, so increment the map count.
+        */
        if (p->swap_map[offset] < SWAP_MAP_MAX)
                p->swap_map[offset]++;
        else {
                static int overflow = 0;
                if (overflow++ < 5)
-                       printk("swap_duplicate: entry %08lx map count=%d\n",
+                       printk(KERN_WARNING
+                               "swap_duplicate: entry %08lx map count=%d\n",
                                entry, p->swap_map[offset]);
                p->swap_map[offset] = SWAP_MAP_MAX;
        }
+       result = 1;
 #ifdef DEBUG_SWAP
        printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n",
               entry, p->swap_map[offset]);
 #endif
 out:
-       return;
+       return result;
 
 bad_file:
-       printk("swap_duplicate: Trying to duplicate nonexistent swap-page\n");
+       printk(KERN_ERR
+               "swap_duplicate: entry %08lx, nonexistent swap file\n", entry);
        goto out;
 bad_offset:
-       printk("swap_duplicate: offset exceeds max\n");
+       printk(KERN_ERR
+               "swap_duplicate: entry %08lx, offset exceeds max\n", entry);
        goto out;
 bad_unused:
-       printk("swap_duplicate at %8p: unused page\n", 
-              __builtin_return_address(0));
+       printk(KERN_ERR
+               "swap_duplicate at %8p: entry %08lx, unused page\n", 
+              __builtin_return_address(0), entry);
        goto out;
 }
 
 
-void remove_from_swap_cache(struct page *page)
+static inline void remove_from_swap_cache(struct page *page)
 {
        if (!page->inode) {
                printk ("VM: Removing swap cache page with zero inode hash "
@@ -163,7 +174,7 @@ void remove_from_swap_cache(struct page *page)
 }
 
 
-int delete_from_swap_cache(struct page *page)
+void delete_from_swap_cache(struct page *page)
 {
 #ifdef SWAP_CACHE_INFO
        swap_cache_del_total++;
@@ -180,9 +191,7 @@ int delete_from_swap_cache(struct page *page)
 #endif
                remove_from_swap_cache (page);
                swap_free (entry);
-               return 1;
        }
-       return 0;
 }
 
 /* 
@@ -218,57 +227,67 @@ static struct page * lookup_swap_cache(unsigned long entry)
                found = find_page(&swapper_inode, entry);
                if (!found)
                        return 0;
-               if (found->inode != &swapper_inode 
-                   || !PageSwapCache(found)) {
-                       __free_page(found);
-                       printk ("VM: Found a non-swapper swap page!\n");
-                       return 0;
-               }
+               if (found->inode != &swapper_inode || !PageSwapCache(found))
+                       goto out_bad;
                if (!PageLocked(found))
                        return found;
                __free_page(found);
                __wait_on_page(found);
        }
+
+out_bad:
+       printk (KERN_ERR "VM: Found a non-swapper swap page!\n");
+       __free_page(found);
+       return 0;
 }
 
 /* 
  * Locate a page of swap in physical memory, reserving swap cache space
  * and reading the disk if it is not already cached.  If wait==0, we are
  * only doing readahead, so don't worry if the page is already locked.
+ *
+ * A failure return means that either the page allocation failed or that
+ * the swap entry is no longer in use.
  */
 
 struct page * read_swap_cache_async(unsigned long entry, int wait)
 {
-       struct page *found_page, *new_page = 0;
-       unsigned long new_page_addr = 0;
+       struct page *found_page, *new_page;
+       unsigned long new_page_addr;
        
 #ifdef DEBUG_SWAP
        printk("DebugVM: read_swap_cache_async entry %08lx%s\n",
               entry, wait ? ", wait" : "");
 #endif
-repeat:
+       /*
+        * Look for the page in the swap cache.
+        */
        found_page = lookup_swap_cache(entry);
-       if (found_page) {
-               if (new_page)
-                       __free_page(new_page);
-               return found_page;
-       }
+       if (found_page)
+               goto out;
+
+       new_page_addr = __get_free_page(GFP_KERNEL);
+       if (!new_page_addr)
+               goto out;       /* Out of memory */
+       new_page = mem_map + MAP_NR(new_page_addr);
+
+       /*
+        * Check the swap cache again, in case we stalled above.
+        */
+       found_page = lookup_swap_cache(entry);
+       if (found_page)
+               goto out_free_page;
+       /*
+        * Make sure the swap entry is still in use.
+        */
+       if (!swap_duplicate(entry))     /* Account for the swap cache */
+               goto out_free_page;
+       /* 
+        * Add it to the swap cache and read its contents.
+        */
+       if (!add_to_swap_cache(new_page, entry))
+               goto out_free_page;
 
-       /* The entry is not present.  Lock down a new page, add it to
-        * the swap cache and read its contents. */
-       if (!new_page) {
-               new_page_addr = __get_free_page(GFP_KERNEL);
-               if (!new_page_addr)
-                       return 0;       /* Out of memory */
-               new_page = mem_map + MAP_NR(new_page_addr);
-               goto repeat;            /* We might have stalled */
-       }
-       
-       if (!add_to_swap_cache(new_page, entry)) {
-               free_page(new_page_addr);
-               return 0;
-       }
-       swap_duplicate(entry);          /* Account for the swap cache */
        set_bit(PG_locked, &new_page->flags);
        rw_swap_page(READ, entry, (char *) new_page_addr, wait);
 #ifdef DEBUG_SWAP
@@ -277,5 +296,9 @@ repeat:
               entry, (char *) page_address(new_page));
 #endif
        return new_page;
-}
 
+out_free_page:
+       __free_page(new_page);
+out:
+       return found_page;
+}
index 65c4b9463257f8f930c043cda2e48ff8f914658a..d218a75678610e8268acf4b06d991d2d9d41f8cc 100644 (file)
@@ -297,30 +297,36 @@ static int try_to_unuse(unsigned int type)
 {
        struct swap_info_struct * si = &swap_info[type];
        struct task_struct *p;
-       unsigned long page = 0;
        struct page *page_map;
-       unsigned long entry;
+       unsigned long entry, page;
        int i;
 
        while (1) {
                /*
                 * Find a swap page in use and read it in.
                 */
-               for (i = 1 , entry = 0; i < si->max ; i++) {
+               for (i = 1; i < si->max ; i++) {
                        if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) {
-                               entry = SWP_ENTRY(type, i);
-                               break;
+                               goto found_entry;
                        }
                }
-               if (!entry)
-                       break;
+               break;
+
+       found_entry:
+               entry = SWP_ENTRY(type, i);
 
                /* Get a page for the entry, using the existing swap
                    cache page if there is one.  Otherwise, get a clean
                    page and read the swap into it. */
                page_map = read_swap_cache(entry);
-               if (!page_map)
-                       return -ENOMEM;
+               if (!page_map) {
+                       /*
+                        * Continue searching if the entry became unused.
+                        */
+                       if (si->swap_map[i] == 0)
+                               continue;
+                       return -ENOMEM;
+               }
                page = page_address(page_map);
                read_lock(&tasklist_lock);
                for_each_task(p)
@@ -331,11 +337,15 @@ static int try_to_unuse(unsigned int type)
                    page we've been using. */
                if (PageSwapCache(page_map))
                        delete_from_swap_cache(page_map);
-               free_page(page);
+               __free_page(page_map);
+               /*
+                * Check for and clear any overflowed swap map counts.
+                */
                if (si->swap_map[i] != 0) {
                        if (si->swap_map[i] != SWAP_MAP_MAX)
-                               printk("try_to_unuse: entry %08lx "
-                                      "not in use\n", entry);
+                               printk(KERN_ERR
+                                       "try_to_unuse: entry %08lx count=%d\n",
+                                       entry, si->swap_map[i]);
                        si->swap_map[i] = 0;
                        nr_swap_pages++;
                }
@@ -376,10 +386,9 @@ asmlinkage int sys_swapoff(const char * specialfile)
                prev = type;
        }
        err = -EINVAL;
-       if (type < 0){
-               dput(dentry);
-               goto out;
-       }
+       if (type < 0)
+               goto out_dput;
+
        if (prev < 0) {
                swap_list.head = p->next;
        } else {
@@ -392,7 +401,6 @@ asmlinkage int sys_swapoff(const char * specialfile)
        p->flags = SWP_USED;
        err = try_to_unuse(type);
        if (err) {
-               dput(dentry);
                /* re-insert swap space back into swap_list */
                for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
                        if (p->prio >= swap_info[i].prio)
@@ -403,7 +411,7 @@ asmlinkage int sys_swapoff(const char * specialfile)
                else
                        swap_info[prev].next = p - swap_info;
                p->flags = SWP_WRITEOK;
-               goto out;
+               goto out_dput;
        }
        if(p->swap_device){
                memset(&filp, 0, sizeof(filp));         
@@ -418,9 +426,9 @@ asmlinkage int sys_swapoff(const char * specialfile)
        }
        dput(dentry);
 
-       nr_swap_pages -= p->pages;
-       dput(p->swap_file);
+       dentry = p->swap_file;
        p->swap_file = NULL;
+       nr_swap_pages -= p->pages;
        p->swap_device = 0;
        vfree(p->swap_map);
        p->swap_map = NULL;
@@ -428,6 +436,9 @@ asmlinkage int sys_swapoff(const char * specialfile)
        p->swap_lockmap = NULL;
        p->flags = 0;
        err = 0;
+
+out_dput:
+       dput(dentry);
 out:
        unlock_kernel();
        return err;
@@ -719,4 +730,3 @@ void si_swapinfo(struct sysinfo *val)
        val->totalswap <<= PAGE_SHIFT;
        return;
 }
-
index 4d9d7e64799d217eae0dbff26d28b03dd4a69a80..c48ea92631a98c5b4c655e1cc1d8d48bbd82743e 100644 (file)
@@ -23,7 +23,6 @@
  * NOTE:       It is just working model of real NAT.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
index 4eeecac2cceb69767427de2d8c9b53bbf975925f..30a0b0dd65bde072eec2674c83ec5f63dfe72905 100644 (file)
@@ -573,11 +573,25 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
        mask = 0;
        if (sk->err)
                mask = POLLERR;
+
+       /*
+        * POLLHUP is certainly not done right. But poll() doesn't
+        * have a notion of HUP in just one direction, and for a
+        * socket the read side is more interesting.
+        *
+        * Some poll() documentation says that POLLHUP is incompatible
+        * with the POLLOUT/POLLWR flags, so somebody should check this
+        * all. But careful, it tends to be safer to return too many
+        * bits than too few, and you can easily break real applications
+        * if you don't tell them that something has hung up!
+        *
+        * Check-me.
+        */
+       if (sk->shutdown & RCV_SHUTDOWN)
+               mask |= POLLHUP;
+
        /* Connected? */
-       if ((1 << sk->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV|TCPF_CLOSE)) {
-               if (sk->shutdown & RCV_SHUTDOWN)
-                       mask |= POLLHUP;
-               
+       if ((1 << sk->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
                if ((tp->rcv_nxt != tp->copied_seq) &&
                    (tp->urg_seq != tp->copied_seq ||
                     tp->rcv_nxt != tp->copied_seq+1 ||
index b06a61e2a6f500e06e35a844ffae8216950b8feb..eab552c365d93e0623c036c2474ad82a07100fa2 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The User Datagram Protocol (UDP).
  *
- * Version:    $Id: udp.c,v 1.59 1998/08/27 16:54:55 davem Exp $
+ * Version:    $Id: udp.c,v 1.61 1998/08/29 17:11:10 freitag Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -82,7 +82,7 @@
      MUST provide facility for checksumming (OK)
      MAY allow application to control checksumming (OK)
      MUST default to checksumming on (OK)
-     MUST discard silently datagrams with bad csums (OK)
+     MUST discard silently datagrams with bad csums (OK, except during debugging)
    4.1.3.5 (UDP Multihoming)
      MUST allow application to specify source address (OK)
      SHOULD be able to communicate the chosen src addr up to application
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/types.h>
-#include <linux/sched.h>
 #include <linux/fcntl.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/in.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
-#include <linux/termios.h>
 #include <linux/mm.h>
 #include <linux/config.h>
 #include <linux/inet.h>
 #include <net/snmp.h>
 #include <net/ip.h>
 #include <net/protocol.h>
-#include <net/tcp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/udp.h>
 #include <net/icmp.h>
 #include <net/route.h>
 #include <net/checksum.h>
-#include <linux/ipsec.h>
 
 /*
  *     Snmp MIB for the UDP layer
@@ -679,21 +675,6 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
                ufh.uh.dest = usin->sin_port;
                if (ufh.uh.dest == 0)
                        return -EINVAL;
-               /* XXX: is a one-behind cache for the dst_entry worth it?
-
-                  Nope. ip_route_output is slower than nothing, but it
-                  is enough fast to forget about caching its results.
-                  Really, checking route validity in general case
-                  is not much faster complete lookup.
-                  It was main reason why I removed it from 2.1.
-                  The second reason was that idle sockets held
-                  a lot of stray destinations.         --ANK
-
-                  Look: route depends on ALL the options,
-                  checking its validity is exactly on cycle
-                  of ip_route_output(). We save only start_bh_atomic()
-                  in SMP case. On UP we save nothing. --ANK
-                */
        } else {
                if (sk->state != TCP_ESTABLISHED)
                        return -ENOTCONN;
@@ -791,8 +772,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
 
        /* RFC1122: OK.  Provides the checksumming facility (MUST) as per */
        /* 4.1.3.4. It's configurable by the application via setsockopt() */
-       /* (MAY) and it defaults to on (MUST).  Almost makes up for the */
-       /* violation above. -- MS */
+       /* (MAY) and it defaults to on (MUST). */
 
        err = ip_build_xmit(sk,sk->no_check ? udp_getfrag_nosum : udp_getfrag,
                            &ufh, ulen, &ipc, rt, msg->msg_flags);
@@ -854,44 +834,10 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
        return(0);
 }
 
-#ifdef CONFIG_FILTER
+#if defined(CONFIG_FILTER) || !defined(HAVE_CSUM_COPY_USER) 
 #undef CONFIG_UDP_DELAY_CSUM
 #endif
 
-#ifdef CONFIG_UDP_DELAY_CSUM
-
-/* Please, read comments in net/checksum.h, asm/checksum.h
-
-   I commented out csum_partial_copy_to_user there because it did not
-   verify_area. Now I am even wondered, how clever was I that time 8)8)
-   If I did not it, I would step into this hole again.   --ANK
- */
-
-#ifndef _HAVE_ARCH_COPY_AND_CSUM_TO_USER
-#ifdef __i386__
-static __inline__
-unsigned int csum_and_copy_to_user (const char *src, char *dst,
-                                   int len, int sum, int *err_ptr)
-{
-       int *src_err_ptr=NULL;
-
-       if (verify_area(VERIFY_WRITE, dst, len) == 0)
-               return csum_partial_copy_generic(src, dst, len, sum, src_err_ptr, err_ptr);
-
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return sum;
-}
-#elif defined(__sparc__)
-#define csum_and_copy_to_user csum_partial_copy_to_user
-#else
-#undef CONFIG_UDP_DELAY_CSUM
-#endif
-#endif
-#endif
-
-
 /*
  *     This should be easy, if there is something there we
  *     return it, otherwise we block.
@@ -943,32 +889,21 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
                err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
                                              copied);
        } else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) {
-               if (csum_fold(csum_partial(skb->h.raw, ntohs(skb->h.uh->len), skb->csum))) {
-                       udp_statistics.UdpInErrors++;
-
-                       /* Error for blocking case is chosen to masquerade
-                          as some normal condition.
-                        */
-                       err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
-                       goto out_free;
-               }
+               if (csum_fold(csum_partial(skb->h.raw, ntohs(skb->h.uh->len), skb->csum))) 
+                       goto csum_copy_err;
                err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
                                              copied);
        } else {
-               unsigned int csum = csum_partial(skb->h.raw, sizeof(struct udphdr), skb->csum);
+               unsigned int csum;
 
                err = 0;
-               csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base, copied, csum, &err);
+               csum = csum_partial(skb->h.raw, sizeof(struct udphdr), skb->csum);
+               csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base, 
+                                            copied, csum, &err);
                if (err)
                        goto out_free;
-               if (csum_fold(csum)) {
-                       udp_statistics.UdpInErrors++;
-                       /* Error for blocking case is chosen to masquerade
-                          as some normal condition.
-                        */
-                       err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
-                       goto out_free;
-               }
+               if (csum_fold(csum)) 
+                       goto csum_copy_err;
        }
 #endif
        if (err)
@@ -1007,6 +942,18 @@ out_free:
        skb_free_datagram(sk, skb);
 out:
        return err;
+
+#ifdef CONFIG_UDP_DELAY_CSUM
+csum_copy_err:
+       udp_statistics.UdpInErrors++;
+       skb_free_datagram(sk, skb);
+
+       /* 
+        * Error for blocking case is chosen to masquerade
+        * as some normal condition.
+        */
+       return (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; 
+#endif
 }
 
 int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
@@ -1074,16 +1021,6 @@ static void udp_close(struct sock *sk, unsigned long timeout)
 
 static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
-       /*
-        *      Check the security clearance
-        */
-        
-       if(!ipsec_sk_policy(sk,skb))
-       {       
-               kfree_skb(skb);
-               return(0);
-       }
-        
        /*
         *      Charge it to the socket, dropping if the queue is full.
         */
@@ -1209,40 +1146,14 @@ int udp_rcv(struct sk_buff *skb, unsigned short len)
        if (uh->check &&
            (((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,ulen,saddr,daddr,skb->csum)) ||
             ((skb->ip_summed==CHECKSUM_NONE) &&
-             (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0)))))) {
-               /* <mea@utu.fi> wants to know, who sent it, to
-                  go and stomp on the garbage sender... */
-
-               /* RFC1122: OK.  Discards the bad packet silently (as far as */
-               /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
-
-               NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
-                      ntohl(saddr),ntohs(uh->source),
-                      ntohl(daddr),ntohs(uh->dest),
-                      ulen));
-               udp_statistics.UdpInErrors++;
-               kfree_skb(skb);
-               return(0);
-       }
+             (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0)))))) 
+               goto csum_error;
 #else
        if (uh->check==0)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        else if (skb->ip_summed==CHECKSUM_HW) {
-               if (udp_check(uh,ulen,saddr,daddr,skb->csum)) {
-                       /* <mea@utu.fi> wants to know, who sent it, to
-                          go and stomp on the garbage sender... */
-
-                       /* RFC1122: OK.  Discards the bad packet silently (as far as */
-                       /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
-
-                       NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
-                                       ntohl(saddr),ntohs(uh->source),
-                                       ntohl(daddr),ntohs(uh->dest),
-                                       ulen));
-                       udp_statistics.UdpInErrors++;
-                       kfree_skb(skb);
-                       return(0);
-               }
+               if (udp_check(uh,ulen,saddr,daddr,skb->csum)) 
+                       goto csum_error;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
                skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
@@ -1263,21 +1174,8 @@ int udp_rcv(struct sk_buff *skb, unsigned short len)
        if (sk == NULL) {
 #ifdef CONFIG_UDP_DELAY_CSUM
                if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
-                   csum_fold(csum_partial((char*)uh, ulen, skb->csum))) {
-                       /* <mea@utu.fi> wants to know, who sent it, to
-                          go and stomp on the garbage sender... */
-
-                       /* RFC1122: OK.  Discards the bad packet silently (as far as */
-                       /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
-
-                       NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
-                                       ntohl(saddr),ntohs(uh->source),
-                                       ntohl(daddr),ntohs(uh->dest),
-                                       ulen));
-                       udp_statistics.UdpInErrors++;
-                       kfree_skb(skb);
-                       return(0);
-               }
+                   csum_fold(csum_partial((char*)uh, ulen, skb->csum))) 
+                       goto csum_error;
 #endif
                udp_statistics.UdpNoPorts++;
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
@@ -1291,6 +1189,19 @@ int udp_rcv(struct sk_buff *skb, unsigned short len)
        }
        udp_deliver(sk, skb);
        return 0;
+
+csum_error:
+       /* 
+        * RFC1122: OK.  Discards the bad packet silently (as far as 
+        * the network is concerned, anyway) as per 4.1.3.4 (MUST). 
+        */
+       NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
+                       ntohl(saddr),ntohs(uh->source),
+                       ntohl(daddr),ntohs(uh->dest),
+                       ulen));
+       udp_statistics.UdpInErrors++;
+       kfree_skb(skb);
+       return(0);
 }
 
 struct proto udp_prot = {
@@ -1320,7 +1231,7 @@ struct proto udp_prot = {
        udp_v4_verify_bind,             /* verify_bind */
        128,                            /* max_header */
        0,                              /* retransmits */
-       "UDP",                          /* name */
+       "UDP",                          /* name */
        0,                              /* inuse */
        0                               /* highestinuse */
 };
index 90662cb28e8134d2723b4de602671baca5ed86f9..bfa701c97e600dae1ae0670d5376cf1927268ad2 100644 (file)
@@ -15,6 +15,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>