Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[cascardo/linux.git] / fs / nfs / inode.c
index 00ad1c2..28a0a3c 100644 (file)
@@ -458,9 +458,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
-       dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
+       dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode),
+               (unsigned long long)NFS_FILEID(inode),
                nfs_display_fhandle_hash(fh),
                atomic_read(&inode->i_count));
 
@@ -870,8 +870,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        struct nfs_fattr *fattr = NULL;
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
-               inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n",
+               inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode));
 
        trace_nfs_revalidate_inode_enter(inode);
 
@@ -895,9 +895,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
        if (status != 0) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n",
                         inode->i_sb->s_id,
-                        (long long)NFS_FILEID(inode), status);
+                        (unsigned long long)NFS_FILEID(inode), status);
                if (status == -ESTALE) {
                        nfs_zap_caches(inode);
                        if (!S_ISDIR(inode->i_mode))
@@ -908,9 +908,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        status = nfs_refresh_inode(inode, fattr);
        if (status) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n",
                         inode->i_sb->s_id,
-                        (long long)NFS_FILEID(inode), status);
+                        (unsigned long long)NFS_FILEID(inode), status);
                goto err_out;
        }
 
@@ -919,9 +919,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        nfs_setsecurity(inode, fattr, label);
 
-       dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
+       dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n",
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode));
+               (unsigned long long)NFS_FILEID(inode));
 
 err_out:
        nfs4_label_free(label);
@@ -977,16 +977,17 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
                if (ret < 0)
                        return ret;
        }
-       spin_lock(&inode->i_lock);
-       nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
-       if (S_ISDIR(inode->i_mode))
+       if (S_ISDIR(inode->i_mode)) {
+               spin_lock(&inode->i_lock);
                memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
-       spin_unlock(&inode->i_lock);
+               spin_unlock(&inode->i_lock);
+       }
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
        nfs_fscache_wait_on_invalidate(inode);
 
-       dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
-                       inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n",
+                       inode->i_sb->s_id,
+                       (unsigned long long)NFS_FILEID(inode));
        return 0;
 }
 
@@ -1007,6 +1008,7 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
+       unsigned long *bitlock = &nfsi->flags;
        int ret = 0;
 
        /* swapfiles are not supposed to be shared. */
@@ -1018,12 +1020,46 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
                if (ret < 0)
                        goto out;
        }
-       if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
-               trace_nfs_invalidate_mapping_enter(inode);
-               ret = nfs_invalidate_mapping(inode, mapping);
-               trace_nfs_invalidate_mapping_exit(inode, ret);
+
+       /*
+        * We must clear NFS_INO_INVALID_DATA first to ensure that
+        * invalidations that come in while we're shooting down the mappings
+        * are respected. But, that leaves a race window where one revalidator
+        * can clear the flag, and then another checks it before the mapping
+        * gets invalidated. Fix that by serializing access to this part of
+        * the function.
+        *
+        * At the same time, we need to allow other tasks to see whether we
+        * might be in the middle of invalidating the pages, so we only set
+        * the bit lock here if it looks like we're going to be doing that.
+        */
+       for (;;) {
+               ret = wait_on_bit(bitlock, NFS_INO_INVALIDATING,
+                                 nfs_wait_bit_killable, TASK_KILLABLE);
+               if (ret)
+                       goto out;
+               spin_lock(&inode->i_lock);
+               if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
+                       spin_unlock(&inode->i_lock);
+                       continue;
+               }
+               if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+                       break;
+               spin_unlock(&inode->i_lock);
+               goto out;
        }
 
+       set_bit(NFS_INO_INVALIDATING, bitlock);
+       smp_wmb();
+       nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
+       spin_unlock(&inode->i_lock);
+       trace_nfs_invalidate_mapping_enter(inode);
+       ret = nfs_invalidate_mapping(inode, mapping);
+       trace_nfs_invalidate_mapping_exit(inode, ret);
+
+       clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
+       smp_mb__after_clear_bit();
+       wake_up_bit(bitlock, NFS_INO_INVALIDATING);
 out:
        return ret;
 }
@@ -1282,12 +1318,28 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
 }
 
+/*
+ * Don't trust the change_attribute, mtime, ctime or size if
+ * a pnfs LAYOUTCOMMIT is outstanding
+ */
+static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode,
+               struct nfs_fattr *fattr)
+{
+       if (pnfs_layoutcommit_outstanding(inode))
+               fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE |
+                               NFS_ATTR_FATTR_MTIME |
+                               NFS_ATTR_FATTR_CTIME |
+                               NFS_ATTR_FATTR_SIZE);
+}
+
 static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
        int ret;
 
        trace_nfs_refresh_inode_enter(inode);
 
+       nfs_inode_attrs_handle_layoutcommit(inode, fattr);
+
        if (nfs_inode_attrs_need_update(inode, fattr))
                ret = nfs_update_inode(inode, fattr);
        else
@@ -1434,7 +1486,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        unsigned long now = jiffies;
        unsigned long save_cache_validity;
 
-       dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
+       dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
                        __func__, inode->i_sb->s_id, inode->i_ino,
                        nfs_display_fhandle_hash(NFS_FH(inode)),
                        atomic_read(&inode->i_count), fattr->valid);
@@ -1455,7 +1507,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                /*
                * Big trouble! The inode has become a different object.
                */
-               printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
+               printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n",
                                __func__, inode->i_ino, inode->i_mode, fattr->mode);
                goto out_err;
        }
@@ -1517,8 +1569,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                if (new_isize != cur_isize) {
                        /* Do we perhaps have any outstanding writes, or has
                         * the file grown beyond our last write? */
-                       if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
-                            new_isize > cur_isize) {
+                       if ((nfsi->npages == 0) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        }
@@ -1641,10 +1692,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb)
                return NULL;
        nfsi->flags = 0UL;
        nfsi->cache_validity = 0UL;
-#ifdef CONFIG_NFS_V3_ACL
-       nfsi->acl_access = ERR_PTR(-EAGAIN);
-       nfsi->acl_default = ERR_PTR(-EAGAIN);
-#endif
 #if IS_ENABLED(CONFIG_NFS_V4)
        nfsi->nfs4_acl = NULL;
 #endif /* CONFIG_NFS_V4 */