On Sun, May 19, 2002 at 11:16:33AM +0200, Florian Schaefer wrote:
> today I compiled a new kernel for my new RH7.3 system and suddenly I get
> some oops when accessing coda.

Yeah, there is a race in iget4 that only recently became more noticable
and a change that went into the tree earlier broke mmap in some cases.

Some of the needed fixes have already been sent to Marcello, the iget4
race is something that I just finished cleaning up and I have been
running it only for about a week. I will probably send that one soon.

I'll attach the full diff from 2.4.19-pre8 to what I have right now.

> PS: How do I compile a coda-client from cvs source? The coda module seems
> to be for a server, isn't it?

It builds both the client and the server as a lot of the code is shared
(or at least there are a lot of dependencies) between the two. There are
only different install targets 'client-install' and 'server-install'.

Basically the steps to go through are 'cvs co coda', 'cd coda',
'./bootstrap.sh', './configure --prefix=/usr', 'make', 'make client-install'.

Jan


diff -urN orig/fs/coda/cnode.c coda1/fs/coda/cnode.c
--- orig/fs/coda/cnode.c        Fri May  3 13:43:44 2002
+++ coda1/fs/coda/cnode.c       Tue May 14 22:11:50 2002
@@ -57,6 +57,7 @@
         } else if (S_ISLNK(inode->i_mode)) {
                inode->i_op = &coda_symlink_inode_operations;
                inode->i_data.a_ops = &coda_symlink_aops;
+               inode->i_mapping = &inode->i_data;
        } else
                 init_special_inode(inode, inode->i_mode, attr->va_rdev);
 }
@@ -67,11 +68,14 @@
        struct inode *inode;
        struct coda_inode_info *cii;
        ino_t ino = coda_f2i(fid);
+       struct coda_sb_info *sbi = coda_sbp(sb);
 
+       down(&sbi->sbi_iget4_mutex);
        inode = iget4(sb, ino, coda_inocmp, fid);
 
        if ( !inode ) { 
                CDEBUG(D_CNODE, "coda_iget: no inode\n");
+               up(&sbi->sbi_iget4_mutex);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -80,9 +84,7 @@
        if (coda_isnullfid(&cii->c_fid))
                /* new, empty inode found... initializing */
                cii->c_fid = *fid;
-
-       /* we shouldnt see inode collisions anymore */
-       if (!coda_fideq(fid, &cii->c_fid)) BUG();
+       up(&sbi->sbi_iget4_mutex);
 
        /* always replace the attributes, type might have changed */
        coda_fill_inode(inode, attr);
@@ -147,6 +149,7 @@
        ino_t nr;
        struct inode *inode;
        struct coda_inode_info *cii;
+       struct coda_sb_info *sbi;
 
        if ( !sb ) {
                printk("coda_fid_to_inode: no sb!\n");
@@ -155,12 +158,14 @@
 
        CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
 
+       sbi = coda_sbp(sb);
        nr = coda_f2i(fid);
+       down(&sbi->sbi_iget4_mutex);
        inode = iget4(sb, nr, coda_inocmp, fid);
        if ( !inode ) {
                printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
                       sb, (long)nr);
-               return NULL;
+               goto out_unlock;
        }
 
        cii = ITOC(inode);
@@ -169,14 +174,16 @@
        if (coda_isnullfid(&cii->c_fid)) {
                inode->i_nlink = 0;
                iput(inode);
-               return NULL;
+               goto out_unlock;
        }
 
-       /* we shouldn't see inode collisions anymore */
-       if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
-
         CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
+       up(&sbi->sbi_iget4_mutex);
        return inode;
+
+out_unlock:
+       up(&sbi->sbi_iget4_mutex);
+       return NULL;
 }
 
 /* the CONTROL inode is made without asking attributes from Venus */
diff -urN orig/fs/coda/dir.c coda1/fs/coda/dir.c
--- orig/fs/coda/dir.c  Fri May  3 13:43:44 2002
+++ coda1/fs/coda/dir.c Fri May  3 13:50:40 2002
@@ -491,6 +491,7 @@
        struct dentry *coda_dentry = coda_file->f_dentry;
        struct coda_file_info *cfi;
        struct file *host_file;
+       int ret;
 
        cfi = CODA_FTOC(coda_file);
        if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();
@@ -498,12 +499,21 @@
 
        coda_vfs_stat.readdir++;
 
-       if ( host_file->f_op->readdir )
+       down(&host_file->f_dentry->d_inode->i_sem);
+       host_file->f_pos = coda_file->f_pos;
+
+       if ( !host_file->f_op->readdir ) {
+               /* Venus: we must read Venus dirents from the file */
+               ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
+       } else {
                /* potemkin case: we were handed a directory inode */
-               return vfs_readdir(host_file, filldir, dirent);
+               ret = vfs_readdir(host_file, filldir, dirent);
+       }
+
+       coda_file->f_pos = host_file->f_pos;
+       up(&host_file->f_dentry->d_inode->i_sem);
 
-       /* Venus: we must read Venus dirents from the file */
-       return coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
+       return ret;
 }
 
 static inline unsigned int CDT2DT(unsigned char cdt)
@@ -736,7 +746,6 @@
        return 0;
 
 return_bad_inode:
-       make_bad_inode(inode);
        unlock_kernel();
        return -EIO;
 }
diff -urN orig/fs/coda/file.c coda1/fs/coda/file.c
--- orig/fs/coda/file.c Fri May  3 13:43:44 2002
+++ coda1/fs/coda/file.c        Tue May 14 23:14:56 2002
@@ -48,7 +48,7 @@
 static ssize_t
 coda_file_write(struct file *coda_file, const char *buf, size_t count, loff_t *ppos)
 {
-       struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
+       struct inode *coda_inode = coda_file->f_dentry->d_inode;
        struct coda_file_info *cfi;
        struct file *host_file;
        ssize_t ret;
@@ -60,12 +60,11 @@
        if (!host_file->f_op || !host_file->f_op->write)
                return -EINVAL;
 
-       host_inode = host_file->f_dentry->d_inode;
        down(&coda_inode->i_sem);
 
        ret = host_file->f_op->write(host_file, buf, count, ppos);
 
-       coda_inode->i_size = host_inode->i_size;
+       coda_inode->i_size = host_file->f_dentry->d_inode->i_size;
        coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
        coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME;
        up(&coda_inode->i_sem);
@@ -77,7 +76,9 @@
 coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 {
        struct coda_file_info *cfi;
+       struct coda_inode_info *cii;
        struct file *host_file;
+       struct inode *coda_inode, *host_inode;
 
        cfi = CODA_FTOC(coda_file);
        if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();
@@ -86,6 +87,21 @@
        if (!host_file->f_op || !host_file->f_op->mmap)
                return -ENODEV;
 
+       coda_inode = coda_file->f_dentry->d_inode;
+       host_inode = host_file->f_dentry->d_inode;
+       if (coda_inode->i_mapping == &coda_inode->i_data)
+               coda_inode->i_mapping = host_inode->i_mapping;
+
+       /* only allow additional mmaps as long as userspace isn't changing
+        * the container file on us! */
+       else if (coda_inode->i_mapping != host_inode->i_mapping)
+               return -EBUSY;
+
+       /* keep track of how often the coda_inode/host_file has been mmapped */
+       cii = ITOC(coda_inode);
+       cii->c_mapcount++;
+       cfi->cfi_mapcount++;
+
        return host_file->f_op->mmap(host_file, vma);
 }
 
@@ -97,7 +113,6 @@
        unsigned short coda_flags = coda_flags_to_cflags(flags);
        struct coda_file_info *cfi;
 
-       lock_kernel();
        coda_vfs_stat.open++;
 
        cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
@@ -106,6 +121,8 @@
                return -ENOMEM;
        }
 
+       lock_kernel();
+
        error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
                           &host_file); 
        if (error || !host_file) {
@@ -117,6 +134,7 @@
        host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC);
 
        cfi->cfi_magic = CODA_MAGIC;
+       cfi->cfi_mapcount = 0;
        cfi->cfi_container = host_file;
        coda_load_creds(&cfi->cfi_cred);
 
@@ -169,6 +187,8 @@
        unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
        unsigned short coda_flags = coda_flags_to_cflags(flags);
        struct coda_file_info *cfi;
+       struct coda_inode_info *cii;
+       struct inode *host_inode;
        int err = 0;
 
        lock_kernel();
@@ -189,6 +209,16 @@
        if (use_coda_close)
                err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
                                  coda_flags, &cfi->cfi_cred);
+
+       host_inode = cfi->cfi_container->f_dentry->d_inode;
+       cii = ITOC(coda_inode);
+
+       /* did we mmap this file? */
+       if (coda_inode->i_mapping == &host_inode->i_data) {
+               cii->c_mapcount -= cfi->cfi_mapcount;
+               if (!cii->c_mapcount)
+                       coda_inode->i_mapping = &coda_inode->i_data;
+       }
 
        fput(cfi->cfi_container);
        kfree(coda_file->private_data);
diff -urN orig/fs/coda/inode.c coda1/fs/coda/inode.c
--- orig/fs/coda/inode.c        Fri May  3 13:43:44 2002
+++ coda1/fs/coda/inode.c       Tue May 14 22:22:51 2002
@@ -128,6 +128,7 @@
        sbi->sbi_sb = sb;
        sbi->sbi_vcomm = vc;
        INIT_LIST_HEAD(&sbi->sbi_cihead);
+       init_MUTEX(&sbi->sbi_iget4_mutex);
 
         sb->u.generic_sbp = sbi;
         sb->s_blocksize = 1024;        /* XXXXX  what do we put here?? */
@@ -194,6 +195,7 @@
             return;
         }
 
+       cii->c_mapcount = 0;
        list_add(&cii->c_cilist, &sbi->sbi_cihead);
 }
 
diff -urN orig/include/linux/coda_fs_i.h coda1/include/linux/coda_fs_i.h
--- orig/include/linux/coda_fs_i.h      Fri May  3 14:23:33 2002
+++ coda1/include/linux/coda_fs_i.h     Tue May 14 23:00:14 2002
@@ -20,6 +20,7 @@
         struct ViceFid     c_fid;      /* Coda identifier */
         u_short                   c_flags;     /* flags (see below) */
        struct list_head   c_cilist;    /* list of all coda inodes */
+       int                c_mapcount;  /* how often is this inode mmapped */
         struct coda_cred   c_cached_cred; /* credentials of cached perms */
         unsigned int       c_cached_perm; /* cached access permissions */
 };
@@ -30,6 +31,7 @@
 #define CODA_MAGIC 0xC0DAC0DA
 struct coda_file_info {
        int              cfi_magic;     /* magic number */
+       int              cfi_mapcount;  /* how often this file is mapped */
        struct file     *cfi_container; /* container file for this cnode */
        struct coda_cred cfi_cred;      /* credentials of opener */
 };
diff -urN orig/include/linux/coda_psdev.h coda1/include/linux/coda_psdev.h
--- orig/include/linux/coda_psdev.h     Wed Apr 25 19:18:54 2001
+++ coda1/include/linux/coda_psdev.h    Thu May  9 02:39:34 2002
@@ -11,6 +11,7 @@
        struct venus_comm * sbi_vcomm;
        struct super_block *sbi_sb;
        struct list_head    sbi_cihead;
+       struct semaphore    sbi_iget4_mutex;
 };
 
 /* communication pending/processing queues */

Reply via email to