drm/edid/firmware: Add built-in edid/1280x720.bin firmware
[platform/kernel/linux-starfive.git] / io_uring / poll.c
index ab5ae47..869e1d2 100644 (file)
@@ -668,6 +668,14 @@ static void io_async_queue_proc(struct file *file, struct wait_queue_head *head,
        __io_queue_proc(&apoll->poll, pt, head, &apoll->double_poll);
 }
 
+/*
+ * We can't reliably detect loops in repeated poll triggers and issue
+ * subsequently failing. But rather than fail these immediately, allow a
+ * certain amount of retries before we give up. Given that this condition
+ * should _rarely_ trigger even once, we should be fine with a larger value.
+ */
+#define APOLL_MAX_RETRY                128
+
 static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req,
                                             unsigned issue_flags)
 {
@@ -678,16 +686,23 @@ static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req,
        if (req->flags & REQ_F_POLLED) {
                apoll = req->apoll;
                kfree(apoll->double_poll);
-       } else if (!(issue_flags & IO_URING_F_UNLOCKED) &&
-                  (entry = io_alloc_cache_get(&ctx->apoll_cache)) != NULL) {
+       } else if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+               entry = io_alloc_cache_get(&ctx->apoll_cache);
+               if (entry == NULL)
+                       goto alloc_apoll;
                apoll = container_of(entry, struct async_poll, cache);
+               apoll->poll.retries = APOLL_MAX_RETRY;
        } else {
+alloc_apoll:
                apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
                if (unlikely(!apoll))
                        return NULL;
+               apoll->poll.retries = APOLL_MAX_RETRY;
        }
        apoll->double_poll = NULL;
        req->apoll = apoll;
+       if (unlikely(!--apoll->poll.retries))
+               return NULL;
        return apoll;
 }
 
@@ -709,8 +724,6 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
                return IO_APOLL_ABORTED;
        if (!file_can_poll(req->file))
                return IO_APOLL_ABORTED;
-       if ((req->flags & (REQ_F_POLLED|REQ_F_PARTIAL_IO)) == REQ_F_POLLED)
-               return IO_APOLL_ABORTED;
        if (!(req->flags & REQ_F_APOLL_MULTISHOT))
                mask |= EPOLLONESHOT;
 
@@ -729,6 +742,7 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
        apoll = io_req_alloc_apoll(req, issue_flags);
        if (!apoll)
                return IO_APOLL_ABORTED;
+       req->flags &= ~(REQ_F_SINGLE_POLL | REQ_F_DOUBLE_POLL);
        req->flags |= REQ_F_POLLED;
        ipt.pt._qproc = io_async_queue_proc;
 
@@ -979,8 +993,9 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
        struct io_hash_bucket *bucket;
        struct io_kiocb *preq;
        int ret2, ret = 0;
-       bool locked;
+       bool locked = true;
 
+       io_ring_submit_lock(ctx, issue_flags);
        preq = io_poll_find(ctx, true, &cd, &ctx->cancel_table, &bucket);
        ret2 = io_poll_disarm(preq);
        if (bucket)
@@ -992,12 +1007,10 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
                goto out;
        }
 
-       io_ring_submit_lock(ctx, issue_flags);
        preq = io_poll_find(ctx, true, &cd, &ctx->cancel_table_locked, &bucket);
        ret2 = io_poll_disarm(preq);
        if (bucket)
                spin_unlock(&bucket->lock);
-       io_ring_submit_unlock(ctx, issue_flags);
        if (ret2) {
                ret = ret2;
                goto out;
@@ -1021,7 +1034,7 @@ found:
                if (poll_update->update_user_data)
                        preq->cqe.user_data = poll_update->new_user_data;
 
-               ret2 = io_poll_add(preq, issue_flags);
+               ret2 = io_poll_add(preq, issue_flags & ~IO_URING_F_UNLOCKED);
                /* successfully updated, don't complete poll request */
                if (!ret2 || ret2 == -EIOCBQUEUED)
                        goto out;
@@ -1029,9 +1042,9 @@ found:
 
        req_set_fail(preq);
        io_req_set_res(preq, -ECANCELED, 0);
-       locked = !(issue_flags & IO_URING_F_UNLOCKED);
        io_req_task_complete(preq, &locked);
 out:
+       io_ring_submit_unlock(ctx, issue_flags);
        if (ret < 0) {
                req_set_fail(req);
                return ret;