ceph: track and report error of async metadata operation
[linux-2.6-block.git] / fs / ceph / caps.c
index ce0f5658720ab9d06764c1f63dbe3d267ffb336f..321ba9b30968bbd6d875c0ff00eb8d33555bc779 100644 (file)
@@ -2261,35 +2261,45 @@ static int unsafe_request_wait(struct inode *inode)
 
 int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
+       struct ceph_file_info *fi = file->private_data;
        struct inode *inode = file->f_mapping->host;
        struct ceph_inode_info *ci = ceph_inode(inode);
        u64 flush_tid;
-       int ret;
+       int ret, err;
        int dirty;
 
        dout("fsync %p%s\n", inode, datasync ? " datasync" : "");
 
        ret = file_write_and_wait_range(file, start, end);
-       if (ret < 0)
-               goto out;
-
        if (datasync)
                goto out;
 
        dirty = try_flush_caps(inode, &flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
 
-       ret = unsafe_request_wait(inode);
+       err = unsafe_request_wait(inode);
 
        /*
         * only wait on non-file metadata writeback (the mds
         * can recover size and mtime, so we don't need to
         * wait for that)
         */
-       if (!ret && (dirty & ~CEPH_CAP_ANY_FILE_WR)) {
-               ret = wait_event_interruptible(ci->i_cap_wq,
+       if (!err && (dirty & ~CEPH_CAP_ANY_FILE_WR)) {
+               err = wait_event_interruptible(ci->i_cap_wq,
                                        caps_are_flushed(inode, flush_tid));
        }
+
+       if (err < 0)
+               ret = err;
+
+       if (errseq_check(&ci->i_meta_err, READ_ONCE(fi->meta_err))) {
+               spin_lock(&file->f_lock);
+               err = errseq_check_and_advance(&ci->i_meta_err,
+                                              &fi->meta_err);
+               spin_unlock(&file->f_lock);
+               if (err < 0)
+                       ret = err;
+       }
 out:
        dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret);
        return ret;