ceph: fix -EOLDSNAPC handling
authorYan, Zheng <zyan@redhat.com>
Mon, 14 Aug 2017 02:50:50 +0000 (10:50 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Wed, 6 Sep 2017 17:56:47 +0000 (19:56 +0200)
Need to drop cap reference before retry. Besides, it's better to
redo file write checks for each retry because we re-lock inode.

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/file.c

index 0e8986c696392959faf9bb13cfc9a03d6ba896cd..1ce80f66e9e596b9d2a912c55576c6ae3adab211 100644 (file)
@@ -1309,6 +1309,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if (!prealloc_cf)
                return -ENOMEM;
 
+retry_snap:
        inode_lock(inode);
 
        /* We can write back this queue in page reclaim */
@@ -1340,7 +1341,6 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
                        goto out;
        }
 
-retry_snap:
        /* FIXME: not complete since it doesn't account for being at quota */
        if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL)) {
                err = -ENOSPC;
@@ -1389,14 +1389,6 @@ retry_snap:
                                                         &prealloc_cf);
                else
                        written = ceph_sync_write(iocb, &data, pos, snapc);
-               if (written == -EOLDSNAPC) {
-                       dout("aio_write %p %llx.%llx %llu~%u"
-                               "got EOLDSNAPC, retrying\n",
-                               inode, ceph_vinop(inode),
-                               pos, (unsigned)count);
-                       inode_lock(inode);
-                       goto retry_snap;
-               }
                if (written > 0)
                        iov_iter_advance(from, written);
                ceph_put_snap_context(snapc);
@@ -1430,10 +1422,15 @@ retry_snap:
             ceph_cap_string(got));
        ceph_put_cap_refs(ci, got);
 
+       if (written == -EOLDSNAPC) {
+               dout("aio_write %p %llx.%llx %llu~%u" "got EOLDSNAPC, retrying\n",
+                    inode, ceph_vinop(inode), pos, (unsigned)count);
+               goto retry_snap;
+       }
+
        if (written >= 0) {
                if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_NEARFULL))
                        iocb->ki_flags |= IOCB_DSYNC;
-
                written = generic_write_sync(iocb, written);
        }