]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/coda/dir.c
Merge branch 'master' into tk71
[mv-sheeva.git] / fs / coda / dir.c
index ccd98b0f2b0b9c3d37f10b101a86b36572054240..2b8dae4d121ee5ad7d42ff879ce1a7c496d295f0 100644 (file)
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/namei.h>
 
 #include <asm/uaccess.h>
 
 #include <linux/coda.h>
-#include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
-#include <linux/coda_fs_i.h>
-#include <linux/coda_cache.h>
+#include "coda_linux.h"
+#include "coda_cache.h"
 
 #include "coda_int.h"
 
@@ -47,7 +47,7 @@ static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
 
 /* dentry ops */
 static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
-static int coda_dentry_delete(struct dentry *);
+static int coda_dentry_delete(const struct dentry *);
 
 /* support routines */
 static int coda_venus_readdir(struct file *coda_file, void *buf,
@@ -60,7 +60,7 @@ static int coda_return_EIO(void)
 }
 #define CODA_EIO_ERROR ((void *) (coda_return_EIO))
 
-static const struct dentry_operations coda_dentry_operations =
+const struct dentry_operations coda_dentry_operations =
 {
        .d_revalidate   = coda_dentry_revalidate,
        .d_delete       = coda_dentry_delete,
@@ -116,21 +116,15 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc
                goto exit;
        }
 
-       lock_kernel();
-
        error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
                             &type, &resfid);
        if (!error)
                error = coda_cnode_make(&inode, &resfid, dir->i_sb);
 
-       unlock_kernel();
-
        if (error && error != -ENOENT)
                return ERR_PTR(error);
 
 exit:
-       entry->d_op = &coda_dentry_operations;
-
        if (inode && (type & CODA_NOCACHE))
                coda_flag_inode(inode, C_VATTR | C_PURGE);
 
@@ -138,30 +132,29 @@ exit:
 }
 
 
-int coda_permission(struct inode *inode, int mask)
+int coda_permission(struct inode *inode, int mask, unsigned int flags)
 {
-        int error = 0;
+       int error;
+
+       if (flags & IPERM_FLAG_RCU)
+               return -ECHILD;
 
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
  
        if (!mask)
-               return 0; 
+               return 0;
 
        if ((mask & MAY_EXEC) && !execute_ok(inode))
                return -EACCES;
 
-       lock_kernel();
-
        if (coda_cache_check(inode, mask))
-               goto out; 
+               return 0;
 
-        error = venus_access(inode->i_sb, coda_i2f(inode), mask);
+       error = venus_access(inode->i_sb, coda_i2f(inode), mask);
     
        if (!error)
                coda_cache_enter(inode, mask);
 
- out:
-       unlock_kernel();
        return error;
 }
 
@@ -200,41 +193,34 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
 /* creation routines: create, mknod, mkdir, link, symlink */
 static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd)
 {
-        int error=0;
+       int error;
        const char *name=de->d_name.name;
        int length=de->d_name.len;
        struct inode *inode;
        struct CodaFid newfid;
        struct coda_vattr attrs;
 
-       lock_kernel();
-
-       if (coda_isroot(dir) && coda_iscontrol(name, length)) {
-               unlock_kernel();
+       if (coda_isroot(dir) && coda_iscontrol(name, length))
                return -EPERM;
-       }
 
        error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 
                                0, mode, &newfid, &attrs);
-
-        if ( error ) {
-               unlock_kernel();
-               d_drop(de);
-               return error;
-       }
+       if (error)
+               goto err_out;
 
        inode = coda_iget(dir->i_sb, &newfid, &attrs);
-       if ( IS_ERR(inode) ) {
-               unlock_kernel();
-               d_drop(de);
-               return PTR_ERR(inode);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
+               goto err_out;
        }
 
        /* invalidate the directory cnode's attributes */
        coda_dir_update_mtime(dir);
-       unlock_kernel();
        d_instantiate(de, inode);
        return 0;
+err_out:
+       d_drop(de);
+       return error;
 }
 
 static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -246,36 +232,29 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
        int error;
        struct CodaFid newfid;
 
-       lock_kernel();
-
-       if (coda_isroot(dir) && coda_iscontrol(name, len)) {
-               unlock_kernel();
+       if (coda_isroot(dir) && coda_iscontrol(name, len))
                return -EPERM;
-       }
 
        attrs.va_mode = mode;
        error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
                               name, len, &newfid, &attrs);
-        
-        if ( error ) {
-               unlock_kernel();
-               d_drop(de);
-               return error;
-        }
+       if (error)
+               goto err_out;
          
        inode = coda_iget(dir->i_sb, &newfid, &attrs);
-       if ( IS_ERR(inode) ) {
-               unlock_kernel();
-               d_drop(de);
-               return PTR_ERR(inode);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
+               goto err_out;
        }
 
        /* invalidate the directory cnode's attributes */
        coda_dir_inc_nlink(dir);
        coda_dir_update_mtime(dir);
-       unlock_kernel();
        d_instantiate(de, inode);
        return 0;
+err_out:
+       d_drop(de);
+       return error;
 }
 
 /* try to make de an entry in dir_inodde linked to source_de */ 
@@ -287,52 +266,38 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
        int len = de->d_name.len;
        int error;
 
-       lock_kernel();
-
-       if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
-               unlock_kernel();
+       if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
                return -EPERM;
-       }
 
        error = venus_link(dir_inode->i_sb, coda_i2f(inode),
                           coda_i2f(dir_inode), (const char *)name, len);
-
        if (error) {
                d_drop(de);
-               goto out;
+               return error;
        }
 
        coda_dir_update_mtime(dir_inode);
-       atomic_inc(&inode->i_count);
+       ihold(inode);
        d_instantiate(de, inode);
        inc_nlink(inode);
-
-out:
-       unlock_kernel();
-       return(error);
+       return 0;
 }
 
 
 static int coda_symlink(struct inode *dir_inode, struct dentry *de,
                        const char *symname)
 {
-        const char *name = de->d_name.name;
+       const char *name = de->d_name.name;
        int len = de->d_name.len;
        int symlen;
-       int error = 0;
-
-       lock_kernel();
+       int error;
 
-       if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
-               unlock_kernel();
+       if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
                return -EPERM;
-       }
 
        symlen = strlen(symname);
-       if ( symlen > CODA_MAXPATHLEN ) {
-               unlock_kernel();
+       if (symlen > CODA_MAXPATHLEN)
                return -ENAMETOOLONG;
-       }
 
        /*
         * This entry is now negative. Since we do not create
@@ -343,10 +308,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
                              symname, symlen);
 
        /* mtime is no good anymore */
-       if ( !error )
+       if (!error)
                coda_dir_update_mtime(dir_inode);
 
-       unlock_kernel();
        return error;
 }
 
@@ -357,17 +321,12 @@ static int coda_unlink(struct inode *dir, struct dentry *de)
        const char *name = de->d_name.name;
        int len = de->d_name.len;
 
-       lock_kernel();
-
        error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
-       if ( error ) {
-               unlock_kernel();
+       if (error)
                return error;
-       }
 
        coda_dir_update_mtime(dir);
        drop_nlink(de->d_inode);
-       unlock_kernel();
        return 0;
 }
 
@@ -377,8 +336,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
        int len = de->d_name.len;
        int error;
 
-       lock_kernel();
-
        error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
        if (!error) {
                /* VFS may delete the child */
@@ -389,7 +346,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
                coda_dir_drop_nlink(dir);
                coda_dir_update_mtime(dir);
        }
-       unlock_kernel();
        return error;
 }
 
@@ -403,15 +359,12 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
        int new_length = new_dentry->d_name.len;
        int error;
 
-       lock_kernel();
-
        error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
                             coda_i2f(new_dir), old_length, new_length,
                             (const char *) old_name, (const char *)new_name);
-
-       if ( !error ) {
-               if ( new_dentry->d_inode ) {
-                       if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+       if (!error) {
+               if (new_dentry->d_inode) {
+                       if (S_ISDIR(new_dentry->d_inode->i_mode)) {
                                coda_dir_drop_nlink(old_dir);
                                coda_dir_inc_nlink(new_dir);
                        }
@@ -423,8 +376,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
                        coda_flag_inode(new_dir, C_VATTR);
                }
        }
-       unlock_kernel();
-
        return error;
 }
 
@@ -591,13 +542,14 @@ out:
 /* called when a cache lookup succeeds */
 static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
 {
-       struct inode *inode = de->d_inode;
+       struct inode *inode;
        struct coda_inode_info *cii;
 
-       if (!inode)
-               return 1;
-       lock_kernel();
-       if (coda_isroot(inode))
+       if (nd->flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       inode = de->d_inode;
+       if (!inode || coda_isroot(inode))
                goto out;
        if (is_bad_inode(inode))
                goto bad;
@@ -612,18 +564,17 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
        if (cii->c_flags & C_FLUSH) 
                coda_flag_inode_children(inode, C_FLUSH);
 
-       if (atomic_read(&de->d_count) > 1)
+       if (de->d_count > 1)
                /* pretend it's valid, but don't change the flags */
                goto out;
 
        /* clear the flags. */
+       spin_lock(&cii->c_lock);
        cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
-
+       spin_unlock(&cii->c_lock);
 bad:
-       unlock_kernel();
        return 0;
 out:
-       unlock_kernel();
        return 1;
 }
 
@@ -631,7 +582,7 @@ out:
  * This is the callback from dput() when d_count is going to 0.
  * We use this to unhash dentries with bad inodes.
  */
-static int coda_dentry_delete(struct dentry * dentry)
+static int coda_dentry_delete(const struct dentry * dentry)
 {
        int flags;
 
@@ -656,20 +607,19 @@ static int coda_dentry_delete(struct dentry * dentry)
 int coda_revalidate_inode(struct dentry *dentry)
 {
        struct coda_vattr attr;
-       int error = 0;
+       int error;
        int old_mode;
        ino_t old_ino;
        struct inode *inode = dentry->d_inode;
        struct coda_inode_info *cii = ITOC(inode);
 
-       lock_kernel();
-       if ( !cii->c_flags )
-               goto ok;
+       if (!cii->c_flags)
+               return 0;
 
        if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
                error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
-               if ( error )
-                       goto return_bad;
+               if (error)
+                       return -EIO;
 
                /* this inode may be lost if:
                   - it's ino changed 
@@ -688,17 +638,13 @@ int coda_revalidate_inode(struct dentry *dentry)
                /* the following can happen when a local fid is replaced 
                   with a global one, here we lose and declare the inode bad */
                if (inode->i_ino != old_ino)
-                       goto return_bad;
+                       return -EIO;
                
                coda_flag_inode_children(inode, C_FLUSH);
+
+               spin_lock(&cii->c_lock);
                cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
+               spin_unlock(&cii->c_lock);
        }
-
-ok:
-       unlock_kernel();
        return 0;
-
-return_bad:
-       unlock_kernel();
-       return -EIO;
 }