Merge branches 'for-4.4/upstream-fixes', 'for-4.5/async-suspend', 'for-4.5/container...
[cascardo/linux.git] / fs / ceph / caps.c
index 27b5668..c69e125 100644 (file)
@@ -1655,9 +1655,8 @@ retry_locked:
            !S_ISDIR(inode->i_mode) &&          /* ignore readdir cache */
            ci->i_wrbuffer_ref == 0 &&          /* no dirty pages... */
            inode->i_data.nrpages &&            /* have cached pages */
-           (file_wanted == 0 ||                /* no open files */
-            (revoking & (CEPH_CAP_FILE_CACHE|
-                         CEPH_CAP_FILE_LAZYIO))) && /*  or revoking cache */
+           (revoking & (CEPH_CAP_FILE_CACHE|
+                        CEPH_CAP_FILE_LAZYIO)) && /*  or revoking cache */
            !tried_invalidate) {
                dout("check_caps trying to invalidate on %p\n", inode);
                if (try_nonblocking_invalidate(inode) < 0) {
@@ -1971,49 +1970,46 @@ out:
 }
 
 /*
- * wait for any uncommitted directory operations to commit.
+ * wait for any unsafe requests to complete.
  */
-static int unsafe_dirop_wait(struct inode *inode)
+static int unsafe_request_wait(struct inode *inode)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct list_head *head = &ci->i_unsafe_dirops;
-       struct ceph_mds_request *req;
-       u64 last_tid;
-       int ret = 0;
-
-       if (!S_ISDIR(inode->i_mode))
-               return 0;
+       struct ceph_mds_request *req1 = NULL, *req2 = NULL;
+       int ret, err = 0;
 
        spin_lock(&ci->i_unsafe_lock);
-       if (list_empty(head))
-               goto out;
-
-       req = list_last_entry(head, struct ceph_mds_request,
-                             r_unsafe_dir_item);
-       last_tid = req->r_tid;
-
-       do {
-               ceph_mdsc_get_request(req);
-               spin_unlock(&ci->i_unsafe_lock);
+       if (S_ISDIR(inode->i_mode) && !list_empty(&ci->i_unsafe_dirops)) {
+               req1 = list_last_entry(&ci->i_unsafe_dirops,
+                                       struct ceph_mds_request,
+                                       r_unsafe_dir_item);
+               ceph_mdsc_get_request(req1);
+       }
+       if (!list_empty(&ci->i_unsafe_iops)) {
+               req2 = list_last_entry(&ci->i_unsafe_iops,
+                                       struct ceph_mds_request,
+                                       r_unsafe_target_item);
+               ceph_mdsc_get_request(req2);
+       }
+       spin_unlock(&ci->i_unsafe_lock);
 
-               dout("unsafe_dirop_wait %p wait on tid %llu (until %llu)\n",
-                    inode, req->r_tid, last_tid);
-               ret = !wait_for_completion_timeout(&req->r_safe_completion,
-                                       ceph_timeout_jiffies(req->r_timeout));
+       dout("unsafe_requeset_wait %p wait on tid %llu %llu\n",
+            inode, req1 ? req1->r_tid : 0ULL, req2 ? req2->r_tid : 0ULL);
+       if (req1) {
+               ret = !wait_for_completion_timeout(&req1->r_safe_completion,
+                                       ceph_timeout_jiffies(req1->r_timeout));
                if (ret)
-                       ret = -EIO;  /* timed out */
-
-               ceph_mdsc_put_request(req);
-
-               spin_lock(&ci->i_unsafe_lock);
-               if (ret || list_empty(head))
-                       break;
-               req = list_first_entry(head, struct ceph_mds_request,
-                                      r_unsafe_dir_item);
-       } while (req->r_tid < last_tid);
-out:
-       spin_unlock(&ci->i_unsafe_lock);
-       return ret;
+                       err = -EIO;
+               ceph_mdsc_put_request(req1);
+       }
+       if (req2) {
+               ret = !wait_for_completion_timeout(&req2->r_safe_completion,
+                                       ceph_timeout_jiffies(req2->r_timeout));
+               if (ret)
+                       err = -EIO;
+               ceph_mdsc_put_request(req2);
+       }
+       return err;
 }
 
 int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
@@ -2039,7 +2035,7 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        dirty = try_flush_caps(inode, &flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
 
-       ret = unsafe_dirop_wait(inode);
+       ret = unsafe_request_wait(inode);
 
        /*
         * only wait on non-file metadata writeback (the mds