]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/dir.c
NFSv4: Don't revalidate the directory in nfs_atomic_lookup()
[karo-tx-linux.git] / fs / nfs / dir.c
index 9f8ec3c3e6a7787a1fa7cab3d308a93bede677db..9ca38ab0e0a7d0c2c36229ac58fab9b413aa9121 100644 (file)
@@ -200,9 +200,6 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        desc->timestamp = timestamp;
        desc->timestamp_valid = 1;
        SetPageUptodate(page);
-       spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
-       spin_unlock(&inode->i_lock);
        /* Ensure consistent page alignment of the data.
         * Note: assumes we have exclusive access to this mapping either
         *       through inode->i_mutex or some other mechanism.
@@ -490,9 +487,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                                                page,
                                                NFS_SERVER(inode)->dtsize,
                                                desc->plus);
-       spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
-       spin_unlock(&inode->i_lock);
        desc->page = page;
        desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
        if (desc->error >= 0) {
@@ -652,9 +646,14 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
        if (IS_ROOT(dentry))
                return 1;
-       if (dentry->d_time == NFS_I(dir)->cache_change_attribute)
-               return 1;
-       return 0;
+       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+               return 0;
+       /* Revalidate nfsi->cache_change_attribute before we declare a match */
+       if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+               return 0;
+       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+               return 0;
+       return 1;
 }
 
 static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
@@ -741,7 +740,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        int error;
        struct nfs_fh fhandle;
        struct nfs_fattr fattr;
-       unsigned long verifier;
 
        parent = dget_parent(dentry);
        lock_kernel();
@@ -749,10 +747,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
        inode = dentry->d_inode;
 
-       /* Revalidate parent directory attribute cache */
-       if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
-               goto out_zap_parent;
-
        if (!inode) {
                if (nfs_neg_need_reval(dir, dentry, nd))
                        goto out_bad;
@@ -776,7 +770,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        if (NFS_STALE(inode))
                goto out_bad;
 
-       verifier = nfs_save_change_attribute(dir);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
        if (error)
                goto out_bad;
@@ -785,7 +778,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
                goto out_bad;
 
-       nfs_set_verifier(dentry, verifier);
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  out_valid:
        unlock_kernel();
        dput(parent);
@@ -796,7 +789,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
 out_zap_parent:
        nfs_zap_caches(dir);
  out_bad:
-       NFS_CACHEINV(dir);
+       nfs_mark_for_revalidate(dir);
        if (inode && S_ISDIR(inode->i_mode)) {
                /* Purge readdir caches. */
                nfs_zap_caches(inode);
@@ -937,14 +930,8 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
 no_entry:
        res = d_materialise_unique(dentry, inode);
        if (res != NULL) {
-               struct dentry *parent;
                if (IS_ERR(res))
                        goto out_unlock;
-               /* Was a directory renamed! */
-               parent = dget_parent(res);
-               if (!IS_ROOT(parent))
-                       nfs_mark_for_revalidate(parent->d_inode);
-               dput(parent);
                dentry = res;
        }
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
@@ -998,28 +985,16 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
        }
        dentry->d_op = NFS_PROTO(dir)->dentry_ops;
 
-       /* Let vfs_create() deal with O_EXCL */
+       /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
+        * the dentry. */
        if (nd->intent.open.flags & O_EXCL) {
-               d_add(dentry, NULL);
+               d_instantiate(dentry, NULL);
                goto out;
        }
 
        /* Open the file on the server */
        lock_kernel();
-       /* Revalidate parent directory attribute cache */
-       error = nfs_revalidate_inode(NFS_SERVER(dir), dir);
-       if (error < 0) {
-               res = ERR_PTR(error);
-               unlock_kernel();
-               goto out;
-       }
-
-       if (nd->intent.open.flags & O_CREAT) {
-               nfs_begin_data_update(dir);
-               res = nfs4_atomic_open(dir, dentry, nd);
-               nfs_end_data_update(dir);
-       } else
-               res = nfs4_atomic_open(dir, dentry, nd);
+       res = nfs4_atomic_open(dir, dentry, nd);
        unlock_kernel();
        if (IS_ERR(res)) {
                error = PTR_ERR(res);
@@ -1053,7 +1028,6 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct dentry *parent = NULL;
        struct inode *inode = dentry->d_inode;
        struct inode *dir;
-       unsigned long verifier;
        int openflags, ret = 0;
 
        parent = dget_parent(dentry);
@@ -1081,10 +1055,9 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
         * change attribute *before* we do the RPC call.
         */
        lock_kernel();
-       verifier = nfs_save_change_attribute(dir);
        ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
-       if (!ret)
-               nfs_set_verifier(dentry, verifier);
+       if (ret == 1)
+               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
 out:
        dput(parent);
@@ -1180,32 +1153,40 @@ out_renew:
 int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
                                struct nfs_fattr *fattr)
 {
+       struct dentry *parent = dget_parent(dentry);
+       struct inode *dir = parent->d_inode;
        struct inode *inode;
        int error = -EACCES;
 
+       d_drop(dentry);
+
        /* We may have been initialized further down */
        if (dentry->d_inode)
-               return 0;
+               goto out;
        if (fhandle->size == 0) {
-               struct inode *dir = dentry->d_parent->d_inode;
                error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
                if (error)
-                       return error;
+                       goto out_error;
        }
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        if (!(fattr->valid & NFS_ATTR_FATTR)) {
                struct nfs_server *server = NFS_SB(dentry->d_sb);
                error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
                if (error < 0)
-                       return error;
+                       goto out_error;
        }
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
        error = PTR_ERR(inode);
        if (IS_ERR(inode))
-               return error;
-       d_instantiate(dentry, inode);
-       if (d_unhashed(dentry))
-               d_rehash(dentry);
+               goto out_error;
+       d_add(dentry, inode);
+out:
+       dput(parent);
        return 0;
+out_error:
+       nfs_mark_for_revalidate(dir);
+       dput(parent);
+       return error;
 }
 
 /*
@@ -1231,12 +1212,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
                open_flags = nd->intent.open.flags;
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
-       nfs_end_data_update(dir);
        if (error != 0)
                goto out_err;
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
        return 0;
 out_err:
@@ -1264,12 +1242,9 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
        attr.ia_valid = ATTR_MODE;
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
-       nfs_end_data_update(dir);
        if (status != 0)
                goto out_err;
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
        return 0;
 out_err:
@@ -1293,12 +1268,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        attr.ia_mode = mode | S_IFDIR;
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
-       nfs_end_data_update(dir);
        if (error != 0)
                goto out_err;
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
        return 0;
 out_err:
@@ -1315,12 +1287,10 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
        /* Ensure the VFS deletes this inode */
        if (error == 0 && dentry->d_inode != NULL)
                clear_nlink(dentry->d_inode);
-       nfs_end_data_update(dir);
        unlock_kernel();
 
        return error;
@@ -1378,17 +1348,13 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 
        qsilly.name = silly;
        qsilly.len  = strlen(silly);
-       nfs_begin_data_update(dir);
        if (dentry->d_inode) {
-               nfs_begin_data_update(dentry->d_inode);
                error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
                                dir, &qsilly);
                nfs_mark_for_revalidate(dentry->d_inode);
-               nfs_end_data_update(dentry->d_inode);
        } else
                error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
                                dir, &qsilly);
-       nfs_end_data_update(dir);
        if (!error) {
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                d_move(dentry, sdentry);
@@ -1422,19 +1388,15 @@ static int nfs_safe_remove(struct dentry *dentry)
                goto out;
        }
 
-       nfs_begin_data_update(dir);
        if (inode != NULL) {
                nfs_inode_return_delegation(inode);
-               nfs_begin_data_update(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
                /* The VFS may want to delete this inode */
                if (error == 0)
                        drop_nlink(inode);
                nfs_mark_for_revalidate(inode);
-               nfs_end_data_update(inode);
        } else
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
-       nfs_end_data_update(dir);
 out:
        return error;
 }
@@ -1526,9 +1488,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
                memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
        kunmap_atomic(kaddr, KM_USER0);
 
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
-       nfs_end_data_update(dir);
        if (error != 0) {
                dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
                        dir->i_sb->s_id, dir->i_ino,
@@ -1568,15 +1528,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();
-       nfs_begin_data_update(dir);
-       nfs_begin_data_update(inode);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
                atomic_inc(&inode->i_count);
                d_instantiate(dentry, inode);
        }
-       nfs_end_data_update(inode);
-       nfs_end_data_update(dir);
        unlock_kernel();
        return error;
 }
@@ -1679,15 +1635,9 @@ go_ahead:
                d_delete(new_dentry);
        }
 
-       nfs_begin_data_update(old_dir);
-       nfs_begin_data_update(new_dir);
-       nfs_begin_data_update(old_inode);
        error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
                                           new_dir, &new_dentry->d_name);
        nfs_mark_for_revalidate(old_inode);
-       nfs_end_data_update(old_inode);
-       nfs_end_data_update(new_dir);
-       nfs_end_data_update(old_dir);
 out:
        if (rehash)
                d_rehash(rehash);