NFS: Calculate page offsets algorithmically
[linux-2.6-microblaze.git] / fs / nfs / dir.c
index 7bc7cf6..6f0a38d 100644 (file)
@@ -69,18 +69,15 @@ const struct address_space_operations nfs_dir_aops = {
        .freepage = nfs_readdir_clear_array,
 };
 
-static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir)
+static struct nfs_open_dir_context *
+alloc_nfs_open_dir_context(struct inode *dir)
 {
        struct nfs_inode *nfsi = NFS_I(dir);
        struct nfs_open_dir_context *ctx;
-       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
        if (ctx != NULL) {
-               ctx->duped = 0;
                ctx->attr_gencount = nfsi->attr_gencount;
-               ctx->dir_cookie = 0;
-               ctx->dup_cookie = 0;
-               ctx->page_index = 0;
-               ctx->eof = false;
                spin_lock(&dir->i_lock);
                if (list_empty(&nfsi->open_files) &&
                    (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
@@ -89,6 +86,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir
                                                      NFS_INO_REVAL_FORCED);
                list_add(&ctx->list, &nfsi->open_files);
                clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags);
+               memcpy(ctx->verf, nfsi->cookieverf, sizeof(ctx->verf));
                spin_unlock(&dir->i_lock);
                return ctx;
        }
@@ -251,17 +249,20 @@ static const char *nfs_readdir_copy_name(const char *name, unsigned int len)
        return ret;
 }
 
+static size_t nfs_readdir_array_maxentries(void)
+{
+       return (PAGE_SIZE - sizeof(struct nfs_cache_array)) /
+              sizeof(struct nfs_cache_array_entry);
+}
+
 /*
  * Check that the next array entry lies entirely within the page bounds
  */
 static int nfs_readdir_array_can_expand(struct nfs_cache_array *array)
 {
-       struct nfs_cache_array_entry *cache_entry;
-
        if (array->page_full)
                return -ENOSPC;
-       cache_entry = &array->array[array->size + 1];
-       if ((char *)cache_entry - (char *)array > PAGE_SIZE) {
+       if (array->size == nfs_readdir_array_maxentries()) {
                array->page_full = 1;
                return -ENOSPC;
        }
@@ -320,6 +321,11 @@ static struct page *nfs_readdir_page_get_locked(struct address_space *mapping,
        return page;
 }
 
+static loff_t nfs_readdir_page_offset(struct page *page)
+{
+       return (loff_t)page->index * (loff_t)nfs_readdir_array_maxentries();
+}
+
 static u64 nfs_readdir_page_last_cookie(struct page *page)
 {
        struct nfs_cache_array *array;
@@ -450,7 +456,7 @@ static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array,
                if (array->array[i].cookie == desc->dir_cookie) {
                        struct nfs_inode *nfsi = NFS_I(file_inode(desc->file));
 
-                       new_pos = desc->current_index + i;
+                       new_pos = nfs_readdir_page_offset(desc->page) + i;
                        if (desc->attr_gencount != nfsi->attr_gencount ||
                            !nfs_readdir_inode_mapping_valid(nfsi)) {
                                desc->duped = 0;
@@ -1419,7 +1425,12 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
        if (flags & LOOKUP_REVAL)
                goto out_force;
 out:
-       return (inode->i_nlink == 0) ? -ESTALE : 0;
+       if (inode->i_nlink > 0 ||
+           (inode->i_nlink == 0 &&
+            test_bit(NFS_INO_PRESERVE_UNLINKED, &NFS_I(inode)->flags)))
+               return 0;
+       else
+               return -ESTALE;
 out_force:
        if (flags & LOOKUP_RCU)
                return -ECHILD;
@@ -1469,9 +1480,7 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
 {
        switch (error) {
        case 1:
-               dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
-                       __func__, dentry);
-               return 1;
+               break;
        case 0:
                /*
                 * We can't d_drop the root of a disconnected tree:
@@ -1480,13 +1489,10 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
                 * inodes on unmount and further oopses.
                 */
                if (inode && IS_ROOT(dentry))
-                       return 1;
-               dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
-                               __func__, dentry);
-               return 0;
+                       error = 1;
+               break;
        }
-       dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
-                               __func__, dentry, error);
+       trace_nfs_lookup_revalidate_exit(dir, dentry, 0, error);
        return error;
 }
 
@@ -1618,9 +1624,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
                goto out_bad;
 
        trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
-       error = nfs_lookup_revalidate_dentry(dir, dentry, inode);
-       trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
-       return error;
+       return nfs_lookup_revalidate_dentry(dir, dentry, inode);
 out_valid:
        return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
 out_bad:
@@ -2010,14 +2014,14 @@ no_open:
        if (!res) {
                inode = d_inode(dentry);
                if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
-                   !S_ISDIR(inode->i_mode))
+                   !(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
                        res = ERR_PTR(-ENOTDIR);
                else if (inode && S_ISREG(inode->i_mode))
                        res = ERR_PTR(-EOPENSTALE);
        } else if (!IS_ERR(res)) {
                inode = d_inode(res);
                if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
-                   !S_ISDIR(inode->i_mode)) {
+                   !(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) {
                        dput(res);
                        res = ERR_PTR(-ENOTDIR);
                } else if (inode && S_ISREG(inode->i_mode)) {
@@ -2330,7 +2334,8 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
 
        trace_nfs_unlink_enter(dir, dentry);
        spin_lock(&dentry->d_lock);
-       if (d_count(dentry) > 1) {
+       if (d_count(dentry) > 1 && !test_bit(NFS_INO_PRESERVE_UNLINKED,
+                                            &NFS_I(d_inode(dentry))->flags)) {
                spin_unlock(&dentry->d_lock);
                /* Start asynchronous writeout of the inode */
                write_inode_now(d_inode(dentry), 0);
@@ -2989,11 +2994,8 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
        /*
         * Determine which access bits we want to ask for...
         */
-       cache.mask = NFS_ACCESS_READ | NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND;
-       if (nfs_server_capable(inode, NFS_CAP_XATTR)) {
-               cache.mask |= NFS_ACCESS_XAREAD | NFS_ACCESS_XAWRITE |
-                   NFS_ACCESS_XALIST;
-       }
+       cache.mask = NFS_ACCESS_READ | NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND |
+                    nfs_access_xattr_mask(NFS_SERVER(inode));
        if (S_ISDIR(inode->i_mode))
                cache.mask |= NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
        else