]> err.no Git - linux-2.6/blobdiff - fs/nfs/dir.c
NFS: Fix a race in sillyrename
[linux-2.6] / fs / nfs / dir.c
index 82878a19538d32efa1373fccc1586b7314b00ce5..35334539d9475dc0188bdb80f4a1d15ef70b56a9 100644 (file)
@@ -211,9 +211,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        unlock_page(page);
        return 0;
  error:
-       SetPageError(page);
        unlock_page(page);
-       nfs_zap_caches(inode);
        desc->error = error;
        return -EIO;
 }
@@ -429,7 +427,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                }
 
                res = filldir(dirent, entry->name, entry->len, 
-                             file->f_pos, fileid, d_type);
+                             file->f_pos, nfs_compat_user_ino64(fileid),
+                             d_type);
                if (res < 0)
                        break;
                file->f_pos++;
@@ -563,6 +562,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        nfs_fattr_init(&fattr);
        desc->entry = &my_entry;
 
+       nfs_block_sillyrename(dentry);
        while(!desc->entry->eof) {
                res = readdir_search_pagecache(desc);
 
@@ -593,6 +593,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        break;
                }
        }
+       nfs_unblock_sillyrename(dentry);
        unlock_kernel();
        if (res > 0)
                res = 0;
@@ -670,6 +671,19 @@ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigne
        return nd->flags & mask;
 }
 
+/*
+ * Use intent information to check whether or not we're going to do
+ * an O_EXCL create using this path component.
+ */
+static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+{
+       if (NFS_PROTO(dir)->version == 2)
+               return 0;
+       if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
+               return 0;
+       return (nd->intent.open.flags & O_EXCL) != 0;
+}
+
 /*
  * Inode and filehandle revalidation for lookups.
  *
@@ -693,6 +707,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
                                (S_ISREG(inode->i_mode) ||
                                 S_ISDIR(inode->i_mode)))
                        goto out_force;
+               return 0;
        }
        return nfs_revalidate_inode(server, inode);
 out_force:
@@ -756,7 +771,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        }
 
        /* Force a full look up iff the parent directory has changed */
-       if (nfs_check_verifier(dir, dentry)) {
+       if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
                if (nfs_lookup_verify_inode(inode, nd))
                        goto out_zap_parent;
                goto out_valid;
@@ -850,33 +865,10 @@ struct dentry_operations nfs_dentry_operations = {
        .d_iput         = nfs_dentry_iput,
 };
 
-/*
- * Use intent information to check whether or not we're going to do
- * an O_EXCL create using this path component.
- */
-static inline
-int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
-{
-       if (NFS_PROTO(dir)->version == 2)
-               return 0;
-       if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
-               return 0;
-       return (nd->intent.open.flags & O_EXCL) != 0;
-}
-
-static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr)
-{
-       struct nfs_server *server = NFS_SERVER(dir);
-
-       if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
-               /* Revalidate fsid using the parent directory */
-               return __nfs_revalidate_inode(server, dir);
-       return 0;
-}
-
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
        struct dentry *res;
+       struct dentry *parent;
        struct inode *inode = NULL;
        int error;
        struct nfs_fh fhandle;
@@ -905,31 +897,31 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
                goto out_unlock;
        }
 
+       parent = dentry->d_parent;
+       /* Protect against concurrent sillydeletes */
+       nfs_block_sillyrename(parent);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
        if (error == -ENOENT)
                goto no_entry;
        if (error < 0) {
                res = ERR_PTR(error);
-               goto out_unlock;
-       }
-       error = nfs_reval_fsid(dir, &fattr);
-       if (error < 0) {
-               res = ERR_PTR(error);
-               goto out_unlock;
+               goto out_unblock_sillyrename;
        }
        inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
        res = (struct dentry *)inode;
        if (IS_ERR(res))
-               goto out_unlock;
+               goto out_unblock_sillyrename;
 
 no_entry:
        res = d_materialise_unique(dentry, inode);
        if (res != NULL) {
                if (IS_ERR(res))
-                       goto out_unlock;
+                       goto out_unblock_sillyrename;
                dentry = res;
        }
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+out_unblock_sillyrename:
+       nfs_unblock_sillyrename(parent);
 out_unlock:
        unlock_kernel();
 out:
@@ -1524,10 +1516,11 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
        lock_kernel();
+       d_drop(dentry);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
                atomic_inc(&inode->i_count);
-               d_instantiate(dentry, inode);
+               d_add(dentry, inode);
        }
        unlock_kernel();
        return error;
@@ -1778,7 +1771,7 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
        cache = nfs_access_search_rbtree(inode, cred);
        if (cache == NULL)
                goto out;
-       if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)))
+       if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
                goto out_stale;
        res->jiffies = cache->jiffies;
        res->cred = cache->cred;