]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ceph: fix directory fsync
authorYan, Zheng <zyan@redhat.com>
Wed, 27 May 2015 03:19:34 +0000 (11:19 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 25 Jun 2015 08:49:30 +0000 (11:49 +0300)
fsync() on directory should flush dirty caps and wait for any
uncommitted directory opertions to commit. But ceph_dir_fsync()
only waits for uncommitted directory opertions.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
fs/ceph/caps.c
fs/ceph/dir.c

index e9b03b51b874331fc0f5b424b361e82c208bed80..dc988337f8413cb253b00c27ec14cace933dddf8 100644 (file)
@@ -1838,13 +1838,16 @@ static void sync_write_wait(struct inode *inode)
        struct ceph_osd_request *req;
        u64 last_tid;
 
+       if (!S_ISREG(inode->i_mode))
+               return;
+
        spin_lock(&ci->i_unsafe_lock);
        if (list_empty(head))
                goto out;
 
        /* set upper bound as _last_ entry in chain */
-       req = list_entry(head->prev, struct ceph_osd_request,
-                        r_unsafe_item);
+       req = list_last_entry(head, struct ceph_osd_request,
+                             r_unsafe_item);
        last_tid = req->r_tid;
 
        do {
@@ -1862,13 +1865,59 @@ static void sync_write_wait(struct inode *inode)
                 */
                if (list_empty(head))
                        break;
-               req = list_entry(head->next, struct ceph_osd_request,
-                                r_unsafe_item);
+               req = list_first_entry(head, struct ceph_osd_request,
+                                      r_unsafe_item);
        } while (req->r_tid < last_tid);
 out:
        spin_unlock(&ci->i_unsafe_lock);
 }
 
+/*
+ * wait for any uncommitted directory operations to commit.
+ */
+static int unsafe_dirop_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;
+
+       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);
+
+               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));
+               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;
+}
+
 int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
@@ -1882,24 +1931,30 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 
        ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
        if (ret < 0)
-               return ret;
+               goto out;
+
+       if (datasync)
+               goto out;
+
        mutex_lock(&inode->i_mutex);
 
        dirty = try_flush_caps(inode, flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
 
+       ret = unsafe_dirop_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 (!datasync && (dirty & ~CEPH_CAP_ANY_FILE_WR)) {
+       if (!ret && (dirty & ~CEPH_CAP_ANY_FILE_WR)) {
                ret = wait_event_interruptible(ci->i_cap_wq,
-                                      caps_are_flushed(inode, flush_tid));
+                                       caps_are_flushed(inode, flush_tid));
        }
-
-       dout("fsync %p%s done\n", inode, datasync ? " datasync" : "");
        mutex_unlock(&inode->i_mutex);
+out:
+       dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret);
        return ret;
 }
 
index 3dec27e36417e86913eb0a58a4363d8457082b80..424e23138c59c4a5d6c4366bae64464ae894a35f 100644 (file)
@@ -1223,60 +1223,6 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
        return size - left;
 }
 
-/*
- * an fsync() on a dir will wait for any uncommitted directory
- * operations to commit.
- */
-static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end,
-                         int datasync)
-{
-       struct inode *inode = file_inode(file);
-       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;
-
-       dout("dir_fsync %p\n", inode);
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret)
-               return ret;
-       mutex_lock(&inode->i_mutex);
-
-       spin_lock(&ci->i_unsafe_lock);
-       if (list_empty(head))
-               goto out;
-
-       req = list_entry(head->prev,
-                        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);
-
-               dout("dir_fsync %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));
-               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_entry(head->next,
-                                struct ceph_mds_request, r_unsafe_dir_item);
-       } while (req->r_tid < last_tid);
-out:
-       spin_unlock(&ci->i_unsafe_lock);
-       mutex_unlock(&inode->i_mutex);
-
-       return ret;
-}
-
 /*
  * We maintain a private dentry LRU.
  *
@@ -1347,7 +1293,7 @@ const struct file_operations ceph_dir_fops = {
        .open = ceph_open,
        .release = ceph_release,
        .unlocked_ioctl = ceph_ioctl,
-       .fsync = ceph_dir_fsync,
+       .fsync = ceph_fsync,
 };
 
 const struct file_operations ceph_snapdir_fops = {