Merge tag 'arm-soc/for-4.8/defconfig' of http://github.com/Broadcom/stblinux into...
[cascardo/linux.git] / fs / ceph / caps.c
index cfaeef1..6f60d0a 100644 (file)
@@ -1656,7 +1656,7 @@ retry_locked:
         */
        if ((!is_delayed || mdsc->stopping) &&
            !S_ISDIR(inode->i_mode) &&          /* ignore readdir cache */
-           ci->i_wrbuffer_ref == 0 &&          /* no dirty pages... */
+           !(ci->i_wb_ref || ci->i_wrbuffer_ref) &&   /* no dirty pages... */
            inode->i_data.nrpages &&            /* have cached pages */
            (revoking & (CEPH_CAP_FILE_CACHE|
                         CEPH_CAP_FILE_LAZYIO)) && /*  or revoking cache */
@@ -1698,8 +1698,8 @@ retry_locked:
 
                revoking = cap->implemented & ~cap->issued;
                dout(" mds%d cap %p used %s issued %s implemented %s revoking %s\n",
-                    cap->mds, cap, ceph_cap_string(cap->issued),
-                    ceph_cap_string(cap_used),
+                    cap->mds, cap, ceph_cap_string(cap_used),
+                    ceph_cap_string(cap->issued),
                     ceph_cap_string(cap->implemented),
                     ceph_cap_string(revoking));
 
@@ -2317,7 +2317,7 @@ again:
 
        /* make sure file is actually open */
        file_wanted = __ceph_caps_file_wanted(ci);
-       if ((file_wanted & need) == 0) {
+       if ((file_wanted & need) != need) {
                dout("try_get_cap_refs need %s file_wanted %s, EBADF\n",
                     ceph_cap_string(need), ceph_cap_string(file_wanted));
                *err = -EBADF;
@@ -2393,6 +2393,9 @@ again:
                                snap_rwsem_locked = true;
                        }
                        *got = need | (have & want);
+                       if ((need & CEPH_CAP_FILE_RD) &&
+                           !(*got & CEPH_CAP_FILE_CACHE))
+                               ceph_disable_fscache_readpage(ci);
                        __take_cap_refs(ci, *got, true);
                        ret = 1;
                }
@@ -2412,12 +2415,26 @@ again:
                        goto out_unlock;
                }
 
-               if (!__ceph_is_any_caps(ci) &&
-                   ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) {
-                       dout("get_cap_refs %p forced umount\n", inode);
-                       *err = -EIO;
-                       ret = 1;
-                       goto out_unlock;
+               if (ci->i_ceph_flags & CEPH_I_CAP_DROPPED) {
+                       int mds_wanted;
+                       if (ACCESS_ONCE(mdsc->fsc->mount_state) ==
+                           CEPH_MOUNT_SHUTDOWN) {
+                               dout("get_cap_refs %p forced umount\n", inode);
+                               *err = -EIO;
+                               ret = 1;
+                               goto out_unlock;
+                       }
+                       mds_wanted = __ceph_caps_mds_wanted(ci);
+                       if ((mds_wanted & need) != need) {
+                               dout("get_cap_refs %p caps were dropped"
+                                    " (session killed?)\n", inode);
+                               *err = -ESTALE;
+                               ret = 1;
+                               goto out_unlock;
+                       }
+                       if ((mds_wanted & file_wanted) ==
+                           (file_wanted & (CEPH_CAP_FILE_RD|CEPH_CAP_FILE_WR)))
+                               ci->i_ceph_flags &= ~CEPH_I_CAP_DROPPED;
                }
 
                dout("get_cap_refs %p have %s needed %s\n", inode,
@@ -2487,7 +2504,7 @@ int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                        if (err == -EAGAIN)
                                continue;
                        if (err < 0)
-                               return err;
+                               ret = err;
                } else {
                        ret = wait_event_interruptible(ci->i_cap_wq,
                                        try_get_cap_refs(ci, need, want, endoff,
@@ -2496,8 +2513,15 @@ int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                                continue;
                        if (err < 0)
                                ret = err;
-                       if (ret < 0)
-                               return ret;
+               }
+               if (ret < 0) {
+                       if (err == -ESTALE) {
+                               /* session was killed, try renew caps */
+                               ret = ceph_renew_caps(&ci->vfs_inode);
+                               if (ret == 0)
+                                       continue;
+                       }
+                       return ret;
                }
 
                if (ci->i_inline_version != CEPH_INLINE_NONE &&
@@ -2533,6 +2557,9 @@ int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                break;
        }
 
+       if ((_got & CEPH_CAP_FILE_RD) && (_got & CEPH_CAP_FILE_CACHE))
+               ceph_fscache_revalidate_cookie(ci);
+
        *got = _got;
        return 0;
 }
@@ -2774,7 +2801,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        bool writeback = false;
        bool queue_trunc = false;
        bool queue_invalidate = false;
-       bool queue_revalidate = false;
        bool deleted_inode = false;
        bool fill_inline = false;
 
@@ -2807,7 +2833,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        if (!S_ISDIR(inode->i_mode) && /* don't invalidate readdir cache */
            ((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
            (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 &&
-           !ci->i_wrbuffer_ref) {
+           !(ci->i_wrbuffer_ref || ci->i_wb_ref)) {
                if (try_nonblocking_invalidate(inode)) {
                        /* there were locked pages.. invalidate later
                           in a separate thread. */
@@ -2816,8 +2842,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
                                ci->i_rdcache_revoking = ci->i_rdcache_gen;
                        }
                }
-
-               ceph_fscache_invalidate(inode);
        }
 
        /* side effects now are allowed */
@@ -2859,11 +2883,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
                }
        }
 
-       /* Do we need to revalidate our fscache cookie. Don't bother on the
-        * first cache cap as we already validate at cookie creation time. */
-       if ((issued & CEPH_CAP_FILE_CACHE) && ci->i_rdcache_gen > 1)
-               queue_revalidate = true;
-
        if (newcaps & CEPH_CAP_ANY_RD) {
                /* ctime/mtime/atime? */
                ceph_decode_timespec(&mtime, &grant->mtime);
@@ -2972,11 +2991,8 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        if (fill_inline)
                ceph_fill_inline_data(inode, NULL, inline_data, inline_len);
 
-       if (queue_trunc) {
+       if (queue_trunc)
                ceph_queue_vmtruncate(inode);
-               ceph_queue_revalidate(inode);
-       } else if (queue_revalidate)
-               ceph_queue_revalidate(inode);
 
        if (writeback)
                /*
@@ -3178,10 +3194,8 @@ static void handle_cap_trunc(struct inode *inode,
                                          truncate_seq, truncate_size, size);
        spin_unlock(&ci->i_ceph_lock);
 
-       if (queue_trunc) {
+       if (queue_trunc)
                ceph_queue_vmtruncate(inode);
-               ceph_fscache_invalidate(inode);
-       }
 }
 
 /*
@@ -3226,6 +3240,8 @@ retry:
 
        if (target < 0) {
                __ceph_remove_cap(cap, false);
+               if (!ci->i_auth_cap)
+                       ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
                goto out_unlock;
        }