fuse: Introduce a new notification type for resend pending requests
[linux-2.6-microblaze.git] / fs / fuse / dev.c
index 5a5fb56..3c15a6b 100644 (file)
@@ -1775,6 +1775,59 @@ copy_finish:
        return err;
 }
 
+/*
+ * Resending all processing queue requests.
+ *
+ * During a FUSE daemon panics and failover, it is possible for some inflight
+ * requests to be lost and never returned. As a result, applications awaiting
+ * replies would become stuck forever. To address this, we can use notification
+ * to trigger resending of these pending requests to the FUSE daemon, ensuring
+ * they are properly processed again.
+ *
+ * Please note that this strategy is applicable only to idempotent requests or
+ * if the FUSE daemon takes careful measures to avoid processing duplicated
+ * non-idempotent requests.
+ */
+static void fuse_resend(struct fuse_conn *fc)
+{
+       struct fuse_dev *fud;
+       struct fuse_req *req, *next;
+       struct fuse_iqueue *fiq = &fc->iq;
+       LIST_HEAD(to_queue);
+       unsigned int i;
+
+       spin_lock(&fc->lock);
+       if (!fc->connected) {
+               spin_unlock(&fc->lock);
+               return;
+       }
+
+       list_for_each_entry(fud, &fc->devices, entry) {
+               struct fuse_pqueue *fpq = &fud->pq;
+
+               spin_lock(&fpq->lock);
+               for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+                       list_splice_tail_init(&fpq->processing[i], &to_queue);
+               spin_unlock(&fpq->lock);
+       }
+       spin_unlock(&fc->lock);
+
+       list_for_each_entry_safe(req, next, &to_queue, list) {
+               __set_bit(FR_PENDING, &req->flags);
+       }
+
+       spin_lock(&fiq->lock);
+       /* iq and pq requests are both oldest to newest */
+       list_splice(&to_queue, &fiq->pending);
+       fiq->ops->wake_pending_and_unlock(fiq);
+}
+
+static int fuse_notify_resend(struct fuse_conn *fc)
+{
+       fuse_resend(fc);
+       return 0;
+}
+
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
@@ -1800,6 +1853,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
        case FUSE_NOTIFY_DELETE:
                return fuse_notify_delete(fc, size, cs);
 
+       case FUSE_NOTIFY_RESEND:
+               return fuse_notify_resend(fc);
+
        default:
                fuse_copy_finish(cs);
                return -EINVAL;