libceph: allow requests to return immediately on full conditions if caller wishes
authorJeff Layton <jlayton@redhat.com>
Tue, 4 Apr 2017 12:39:37 +0000 (08:39 -0400)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 4 May 2017 07:19:21 +0000 (09:19 +0200)
Usually, when the osd map is flagged as full or the pool is at quota,
write requests just hang. This is not what we want for cephfs, where
it would be better to simply report -ENOSPC back to userland instead
of stalling.

If the caller knows that it will want an immediate error return instead
of blocking on a full or at-quota error condition then allow it to set a
flag to request that behavior.

Set that flag in ceph_osdc_new_request (since ceph.ko is the only caller),
and on any other write request from ceph.ko.

A later patch will deal with requests that were submitted before the new
map showing the full condition came in.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/addr.c
fs/ceph/file.c
include/linux/ceph/osd_client.h
net/ceph/osd_client.c

index 1a3e1b40799a086037fe529e1b0ff02e302adb43..7e3fae334620193188353aa9c6d94d0f6d7353c0 100644 (file)
@@ -1892,6 +1892,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci,
        err = ceph_osdc_start_request(&fsc->client->osdc, rd_req, false);
 
        wr_req->r_mtime = ci->vfs_inode.i_mtime;
+       wr_req->r_abort_on_full = true;
        err2 = ceph_osdc_start_request(&fsc->client->osdc, wr_req, false);
 
        if (!err)
index ab4823e3e0d50df28e5a6425c84b8aa2027b4b2d..134c978141d006503a10b306780012ac40cb3f68 100644 (file)
@@ -781,6 +781,7 @@ static void ceph_aio_retry_work(struct work_struct *work)
        req->r_callback = ceph_aio_complete_req;
        req->r_inode = inode;
        req->r_priv = aio_req;
+       req->r_abort_on_full = true;
 
        ret = ceph_osdc_start_request(req->r_osdc, req, false);
 out:
index 3fc9e7754a9b03428b3508c92fca782d1e062d98..8cf644197b1a0bc56d24bfda5518a8ce547e6e29 100644 (file)
@@ -187,6 +187,7 @@ struct ceph_osd_request {
        struct timespec r_mtime;              /* ditto */
        u64 r_data_offset;                    /* ditto */
        bool r_linger;                        /* don't resend on failure */
+       bool r_abort_on_full;                 /* return ENOSPC when full */
 
        /* internal */
        unsigned long r_stamp;                /* jiffies, send or check time */
index feb666c2238109b034566b4a057b276b6dcbabd5..52a2019a2b644639ff463682b66de6fcde8ace1c 100644 (file)
@@ -961,6 +961,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                                       truncate_size, truncate_seq);
        }
 
+       req->r_abort_on_full = true;
        req->r_flags = flags;
        req->r_base_oloc.pool = layout->pool_id;
        req->r_base_oloc.pool_ns = ceph_try_get_string(layout->pool_ns);
@@ -1627,6 +1628,7 @@ static void maybe_request_map(struct ceph_osd_client *osdc)
                ceph_monc_renew_subs(&osdc->client->monc);
 }
 
+static void complete_request(struct ceph_osd_request *req, int err);
 static void send_map_check(struct ceph_osd_request *req);
 
 static void __submit_request(struct ceph_osd_request *req, bool wrlocked)
@@ -1636,6 +1638,7 @@ static void __submit_request(struct ceph_osd_request *req, bool wrlocked)
        enum calc_target_result ct_res;
        bool need_send = false;
        bool promoted = false;
+       bool need_abort = false;
 
        WARN_ON(req->r_tid);
        dout("%s req %p wrlocked %d\n", __func__, req, wrlocked);
@@ -1670,6 +1673,8 @@ again:
                pr_warn_ratelimited("FULL or reached pool quota\n");
                req->r_t.paused = true;
                maybe_request_map(osdc);
+               if (req->r_abort_on_full)
+                       need_abort = true;
        } else if (!osd_homeless(osd)) {
                need_send = true;
        } else {
@@ -1686,6 +1691,8 @@ again:
        link_request(osd, req);
        if (need_send)
                send_request(req);
+       else if (need_abort)
+               complete_request(req, -ENOSPC);
        mutex_unlock(&osd->lock);
 
        if (ct_res == CALC_TARGET_POOL_DNE)