procfs: reorder struct pid_dentry to save space on 64bit archs, and constify them
[powerpc.git] / fs / nfs / dir.c
index 481f889..625d8e5 100644 (file)
@@ -65,7 +65,7 @@ const struct file_operations nfs_dir_operations = {
        .fsync          = nfs_fsync_dir,
 };
 
-struct inode_operations nfs_dir_inode_operations = {
+const struct inode_operations nfs_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
        .link           = nfs_link,
@@ -81,7 +81,7 @@ struct inode_operations nfs_dir_inode_operations = {
 };
 
 #ifdef CONFIG_NFS_V3
-struct inode_operations nfs3_dir_inode_operations = {
+const struct inode_operations nfs3_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
        .link           = nfs_link,
@@ -104,7 +104,7 @@ struct inode_operations nfs3_dir_inode_operations = {
 #ifdef CONFIG_NFS_V4
 
 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
-struct inode_operations nfs4_dir_inode_operations = {
+const struct inode_operations nfs4_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_atomic_lookup,
        .link           = nfs_link,
@@ -142,18 +142,20 @@ nfs_opendir(struct inode *inode, struct file *filp)
        return res;
 }
 
-typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
+typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int);
 typedef struct {
        struct file     *file;
        struct page     *page;
        unsigned long   page_index;
-       u32             *ptr;
+       __be32          *ptr;
        u64             *dir_cookie;
        loff_t          current_index;
        struct nfs_entry *entry;
        decode_dirent_t decode;
        int             plus;
        int             error;
+       unsigned long   timestamp;
+       int             timestamp_valid;
 } nfs_readdir_descriptor_t;
 
 /* Now we cache directories properly, by stuffing the dirent
@@ -172,7 +174,7 @@ static
 int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
 {
        struct file     *file = desc->file;
-       struct inode    *inode = file->f_dentry->d_inode;
+       struct inode    *inode = file->f_path.dentry->d_inode;
        struct rpc_cred *cred = nfs_file_cred(file);
        unsigned long   timestamp;
        int             error;
@@ -183,7 +185,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
 
  again:
        timestamp = jiffies;
-       error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
+       error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page,
                                          NFS_SERVER(inode)->dtsize, desc->plus);
        if (error < 0) {
                /* We requested READDIRPLUS, but the server doesn't grok it */
@@ -195,6 +197,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
                }
                goto error;
        }
+       desc->timestamp = timestamp;
+       desc->timestamp_valid = 1;
        SetPageUptodate(page);
        spin_lock(&inode->i_lock);
        NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
@@ -203,8 +207,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
         * Note: assumes we have exclusive access to this mapping either
         *       through inode->i_mutex or some other mechanism.
         */
-       if (page->index == 0)
-               invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1);
+       if (page->index == 0 && invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1) < 0) {
+               /* Should never happen */
+               nfs_zap_mapping(inode, inode->i_mapping);
+       }
        unlock_page(page);
        return 0;
  error:
@@ -218,11 +224,15 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
 static inline
 int dir_decode(nfs_readdir_descriptor_t *desc)
 {
-       u32     *p = desc->ptr;
+       __be32  *p = desc->ptr;
        p = desc->decode(p, desc->entry, desc->plus);
        if (IS_ERR(p))
                return PTR_ERR(p);
        desc->ptr = p;
+       if (desc->timestamp_valid)
+               desc->entry->fattr->time_start = desc->timestamp;
+       else
+               desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
        return 0;
 }
 
@@ -306,7 +316,7 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc)
 static inline
 int find_dirent_page(nfs_readdir_descriptor_t *desc)
 {
-       struct inode    *inode = desc->file->f_dentry->d_inode;
+       struct inode    *inode = desc->file->f_path.dentry->d_inode;
        struct page     *page;
        int             status;
 
@@ -314,14 +324,16 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
                        __FUNCTION__, desc->page_index,
                        (long long) *desc->dir_cookie);
 
+       /* If we find the page in the page_cache, we cannot be sure
+        * how fresh the data is, so we will ignore readdir_plus attributes.
+        */
+       desc->timestamp_valid = 0;
        page = read_cache_page(inode->i_mapping, desc->page_index,
                               (filler_t *)nfs_readdir_filler, desc);
        if (IS_ERR(page)) {
                status = PTR_ERR(page);
                goto out;
        }
-       if (!PageUptodate(page))
-               goto read_error;
 
        /* NOTE: Someone else may have changed the READDIRPLUS flag */
        desc->page = page;
@@ -335,9 +347,6 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
  out:
        dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status);
        return status;
- read_error:
-       page_cache_release(page);
-       return -EIO;
 }
 
 /*
@@ -462,10 +471,11 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                     filldir_t filldir)
 {
        struct file     *file = desc->file;
-       struct inode    *inode = file->f_dentry->d_inode;
+       struct inode    *inode = file->f_path.dentry->d_inode;
        struct rpc_cred *cred = nfs_file_cred(file);
        struct page     *page = NULL;
        int             status;
+       unsigned long   timestamp;
 
        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
                        (unsigned long long)*desc->dir_cookie);
@@ -475,7 +485,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                status = -ENOMEM;
                goto out;
        }
-       desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie,
+       timestamp = jiffies;
+       desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
                                                page,
                                                NFS_SERVER(inode)->dtsize,
                                                desc->plus);
@@ -485,6 +496,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        desc->page = page;
        desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
        if (desc->error >= 0) {
+               desc->timestamp = timestamp;
+               desc->timestamp_valid = 1;
                if ((status = dir_decode(desc)) == 0)
                        desc->entry->prev_cookie = *desc->dir_cookie;
        } else
@@ -514,7 +527,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
  */
 static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-       struct dentry   *dentry = filp->f_dentry;
+       struct dentry   *dentry = filp->f_path.dentry;
        struct inode    *inode = dentry->d_inode;
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
@@ -530,7 +543,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        lock_kernel();
 
-       res = nfs_revalidate_mapping(inode, filp->f_mapping);
+       res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping);
        if (res < 0) {
                unlock_kernel();
                return res;
@@ -597,7 +610,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
 loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
 {
-       mutex_lock(&filp->f_dentry->d_inode->i_mutex);
+       mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
        switch (origin) {
                case 1:
                        offset += filp->f_pos;
@@ -613,7 +626,7 @@ loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
                ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;
        }
 out:
-       mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
+       mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
        return offset;
 }
 
@@ -635,7 +648,7 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
  * In the case it has, we assume that the dentries are untrustworthy
  * and may need to be looked up again.
  */
-static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
+static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
        if (IS_ROOT(dentry))
                return 1;
@@ -650,6 +663,12 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
        dentry->d_fsdata = (void *)verf;
 }
 
+static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
+{
+       if (time_after(verf, (unsigned long)dentry->d_fsdata))
+               nfs_set_verifier(dentry, verf);
+}
+
 /*
  * Whenever an NFS operation succeeds, we know that the dentry
  * is valid, so we update the revalidation timestamp.
@@ -783,7 +802,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
                goto out_bad;
 
        nfs_renew_times(dentry);
-       nfs_set_verifier(dentry, verifier);
+       nfs_refresh_verifier(dentry, verifier);
  out_valid:
        unlock_kernel();
        dput(parent);
@@ -841,6 +860,10 @@ static int nfs_dentry_delete(struct dentry *dentry)
 static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 {
        nfs_inode_return_delegation(inode);
+       if (S_ISDIR(inode->i_mode))
+               /* drop any readdir cache as it could easily be old */
+               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
                lock_kernel();
                drop_nlink(inode);
@@ -933,8 +956,17 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
 
 no_entry:
        res = d_materialise_unique(dentry, inode);
-       if (res != NULL)
+       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_renew_times(dentry);
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out_unlock:
@@ -1074,7 +1106,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        verifier = nfs_save_change_attribute(dir);
        ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
        if (!ret)
-               nfs_set_verifier(dentry, verifier);
+               nfs_refresh_verifier(dentry, verifier);
        unlock_kernel();
 out:
        dput(parent);
@@ -1091,7 +1123,7 @@ no_open:
 
 static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
 {
-       struct dentry *parent = desc->file->f_dentry;
+       struct dentry *parent = desc->file->f_path.dentry;
        struct inode *dir = parent->d_inode;
        struct nfs_entry *entry = desc->entry;
        struct dentry *dentry, *alias;
@@ -1112,8 +1144,21 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
        }
        name.hash = full_name_hash(name.name, name.len);
        dentry = d_lookup(parent, &name);
-       if (dentry != NULL)
-               return dentry;
+       if (dentry != NULL) {
+               /* Is this a positive dentry that matches the readdir info? */
+               if (dentry->d_inode != NULL &&
+                               (NFS_FILEID(dentry->d_inode) == entry->ino ||
+                               d_mountpoint(dentry))) {
+                       if (!desc->plus || entry->fh->size == 0)
+                               return dentry;
+                       if (nfs_compare_fh(NFS_FH(dentry->d_inode),
+                                               entry->fh) == 0)
+                               goto out_renew;
+               }
+               /* No, so d_drop to allow one to be created */
+               d_drop(dentry);
+               dput(dentry);
+       }
        if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR))
                return NULL;
        /* Note: caller is already holding the dir->i_mutex! */
@@ -1130,12 +1175,18 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
        alias = d_materialise_unique(dentry, inode);
        if (alias != NULL) {
                dput(dentry);
+               if (IS_ERR(alias))
+                       return NULL;
                dentry = alias;
        }
 
        nfs_renew_times(dentry);
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        return dentry;
+out_renew:
+       nfs_renew_times(dentry);
+       nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir));
+       return dentry;
 }
 
 /*
@@ -1430,6 +1481,8 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
        if (atomic_read(&dentry->d_count) > 1) {
                spin_unlock(&dentry->d_lock);
                spin_unlock(&dcache_lock);
+               /* Start asynchronous writeout of the inode */
+               write_inode_now(dentry->d_inode, 0);
                error = nfs_sillyrename(dir, dentry);
                unlock_kernel();
                return error;
@@ -1517,8 +1570,8 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
        pagevec_init(&lru_pvec, 0);
        if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0,
                                                        GFP_KERNEL)) {
-               if (!pagevec_add(&lru_pvec, page))
-                       __pagevec_lru_add(&lru_pvec);
+               pagevec_add(&lru_pvec, page);
+               pagevec_lru_add(&lru_pvec);
                SetPageUptodate(page);
                unlock_page(page);
        } else
@@ -1646,7 +1699,8 @@ go_ahead:
         * ... prune child dentries and writebacks if needed.
         */
        if (atomic_read(&old_dentry->d_count) > 1) {
-               nfs_wb_all(old_inode);
+               if (S_ISREG(old_inode->i_mode))
+                       nfs_wb_all(old_inode);
                shrink_dcache_parent(old_dentry);
        }
        nfs_inode_return_delegation(old_inode);
@@ -1671,7 +1725,7 @@ out:
        if (!error) {
                d_move(old_dentry, new_dentry);
                nfs_renew_times(new_dentry);
-               nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+               nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir));
        }
 
        /* new dentry created? */