]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/fuse/virtio_fs.c
virtiofs: Do not send forget request "struct list_head" element
[linux.git] / fs / fuse / virtio_fs.c
index a5c86048b96edb59f85986935206f2c53972a170..da603e0cbd0da784dd6aff6bf70ed522cc94d3c9 100644 (file)
@@ -48,11 +48,15 @@ struct virtio_fs {
        unsigned int num_request_queues; /* number of request queues */
 };
 
-struct virtio_fs_forget {
+struct virtio_fs_forget_req {
        struct fuse_in_header ih;
        struct fuse_forget_in arg;
+};
+
+struct virtio_fs_forget {
        /* This request can be temporarily queued on virt queue */
        struct list_head list;
+       struct virtio_fs_forget_req req;
 };
 
 static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
@@ -313,17 +317,72 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work)
        }
 }
 
+/*
+ * Returns 1 if queue is full and sender should wait a bit before sending
+ * next request, 0 otherwise.
+ */
+static int send_forget_request(struct virtio_fs_vq *fsvq,
+                              struct virtio_fs_forget *forget,
+                              bool in_flight)
+{
+       struct scatterlist sg;
+       struct virtqueue *vq;
+       int ret = 0;
+       bool notify;
+       struct virtio_fs_forget_req *req = &forget->req;
+
+       spin_lock(&fsvq->lock);
+       if (!fsvq->connected) {
+               if (in_flight)
+                       dec_in_flight_req(fsvq);
+               kfree(forget);
+               goto out;
+       }
+
+       sg_init_one(&sg, req, sizeof(*req));
+       vq = fsvq->vq;
+       dev_dbg(&vq->vdev->dev, "%s\n", __func__);
+
+       ret = virtqueue_add_outbuf(vq, &sg, 1, forget, GFP_ATOMIC);
+       if (ret < 0) {
+               if (ret == -ENOMEM || ret == -ENOSPC) {
+                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n",
+                                ret);
+                       list_add_tail(&forget->list, &fsvq->queued_reqs);
+                       schedule_delayed_work(&fsvq->dispatch_work,
+                                             msecs_to_jiffies(1));
+                       if (!in_flight)
+                               inc_in_flight_req(fsvq);
+                       /* Queue is full */
+                       ret = 1;
+               } else {
+                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
+                                ret);
+                       kfree(forget);
+                       if (in_flight)
+                               dec_in_flight_req(fsvq);
+               }
+               goto out;
+       }
+
+       if (!in_flight)
+               inc_in_flight_req(fsvq);
+       notify = virtqueue_kick_prepare(vq);
+       spin_unlock(&fsvq->lock);
+
+       if (notify)
+               virtqueue_notify(vq);
+       return ret;
+out:
+       spin_unlock(&fsvq->lock);
+       return ret;
+}
+
 static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
 {
        struct virtio_fs_forget *forget;
        struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq,
                                                 dispatch_work.work);
-       struct virtqueue *vq = fsvq->vq;
-       struct scatterlist sg;
-       struct scatterlist *sgs[] = {&sg};
-       bool notify;
-       int ret;
-
        pr_debug("virtio-fs: worker %s called.\n", __func__);
        while (1) {
                spin_lock(&fsvq->lock);
@@ -335,43 +394,9 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
                }
 
                list_del(&forget->list);
-               if (!fsvq->connected) {
-                       dec_in_flight_req(fsvq);
-                       spin_unlock(&fsvq->lock);
-                       kfree(forget);
-                       continue;
-               }
-
-               sg_init_one(&sg, forget, sizeof(*forget));
-
-               /* Enqueue the request */
-               dev_dbg(&vq->vdev->dev, "%s\n", __func__);
-               ret = virtqueue_add_sgs(vq, sgs, 1, 0, forget, GFP_ATOMIC);
-               if (ret < 0) {
-                       if (ret == -ENOMEM || ret == -ENOSPC) {
-                               pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n",
-                                        ret);
-                               list_add_tail(&forget->list,
-                                               &fsvq->queued_reqs);
-                               schedule_delayed_work(&fsvq->dispatch_work,
-                                               msecs_to_jiffies(1));
-                       } else {
-                               pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
-                                        ret);
-                               dec_in_flight_req(fsvq);
-                               kfree(forget);
-                       }
-                       spin_unlock(&fsvq->lock);
-                       return;
-               }
-
-               notify = virtqueue_kick_prepare(vq);
                spin_unlock(&fsvq->lock);
-
-               if (notify)
-                       virtqueue_notify(vq);
-               pr_debug("virtio-fs: worker %s dispatched one forget request.\n",
-                        __func__);
+               if (send_forget_request(fsvq, forget, true))
+                       return;
        }
 }
 
@@ -684,12 +709,12 @@ static int virtio_fs_restore(struct virtio_device *vdev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-const static struct virtio_device_id id_table[] = {
+static const struct virtio_device_id id_table[] = {
        { VIRTIO_ID_FS, VIRTIO_DEV_ANY_ID },
        {},
 };
 
-const static unsigned int feature_table[] = {};
+static const unsigned int feature_table[] = {};
 
 static struct virtio_driver virtio_fs_driver = {
        .driver.name            = KBUILD_MODNAME,
@@ -710,14 +735,10 @@ __releases(fiq->lock)
 {
        struct fuse_forget_link *link;
        struct virtio_fs_forget *forget;
-       struct scatterlist sg;
-       struct scatterlist *sgs[] = {&sg};
+       struct virtio_fs_forget_req *req;
        struct virtio_fs *fs;
-       struct virtqueue *vq;
        struct virtio_fs_vq *fsvq;
-       bool notify;
        u64 unique;
-       int ret;
 
        link = fuse_dequeue_forget(fiq, 1, NULL);
        unique = fuse_get_unique(fiq);
@@ -728,57 +749,19 @@ __releases(fiq->lock)
 
        /* Allocate a buffer for the request */
        forget = kmalloc(sizeof(*forget), GFP_NOFS | __GFP_NOFAIL);
+       req = &forget->req;
 
-       forget->ih = (struct fuse_in_header){
+       req->ih = (struct fuse_in_header){
                .opcode = FUSE_FORGET,
                .nodeid = link->forget_one.nodeid,
                .unique = unique,
-               .len = sizeof(*forget),
+               .len = sizeof(*req),
        };
-       forget->arg = (struct fuse_forget_in){
+       req->arg = (struct fuse_forget_in){
                .nlookup = link->forget_one.nlookup,
        };
 
-       sg_init_one(&sg, forget, sizeof(*forget));
-
-       /* Enqueue the request */
-       spin_lock(&fsvq->lock);
-
-       if (!fsvq->connected) {
-               kfree(forget);
-               spin_unlock(&fsvq->lock);
-               goto out;
-       }
-
-       vq = fsvq->vq;
-       dev_dbg(&vq->vdev->dev, "%s\n", __func__);
-
-       ret = virtqueue_add_sgs(vq, sgs, 1, 0, forget, GFP_ATOMIC);
-       if (ret < 0) {
-               if (ret == -ENOMEM || ret == -ENOSPC) {
-                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later.\n",
-                                ret);
-                       list_add_tail(&forget->list, &fsvq->queued_reqs);
-                       schedule_delayed_work(&fsvq->dispatch_work,
-                                       msecs_to_jiffies(1));
-                       inc_in_flight_req(fsvq);
-               } else {
-                       pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
-                                ret);
-                       kfree(forget);
-               }
-               spin_unlock(&fsvq->lock);
-               goto out;
-       }
-
-       inc_in_flight_req(fsvq);
-       notify = virtqueue_kick_prepare(vq);
-
-       spin_unlock(&fsvq->lock);
-
-       if (notify)
-               virtqueue_notify(vq);
-out:
+       send_forget_request(fsvq, forget, false);
        kfree(link);
 }
 
@@ -1026,7 +1009,7 @@ __releases(fiq->lock)
        }
 }
 
-const static struct fuse_iqueue_ops virtio_fs_fiq_ops = {
+static const struct fuse_iqueue_ops virtio_fs_fiq_ops = {
        .wake_forget_and_unlock         = virtio_fs_wake_forget_and_unlock,
        .wake_interrupt_and_unlock      = virtio_fs_wake_interrupt_and_unlock,
        .wake_pending_and_unlock        = virtio_fs_wake_pending_and_unlock,