// SPDX-License-Identifier: GPL-2.0/* * virtio-fs: Virtio Filesystem * Copyright (C) 2018 Red Hat, Inc. */#include<linux/fs.h>#include<linux/module.h>#include<linux/virtio.h>#include<linux/virtio_fs.h>#include<linux/delay.h>#include<linux/fs_context.h>#include<linux/highmem.h>#include"fuse_i.h"/* List of virtio-fs device instances and a lock for the list. Also provides * mutual exclusion in device removal and mounting path */staticDEFINE_MUTEX(virtio_fs_mutex);staticLIST_HEAD(virtio_fs_instances);enum{VQ_HIPRIO,VQ_REQUEST};/* Per-virtqueue state */structvirtio_fs_vq{spinlock_tlock;structvirtqueue*vq;/* protected by ->lock */structwork_structdone_work;structlist_headqueued_reqs;structlist_headend_reqs;/* End these requests */structdelayed_workdispatch_work;structfuse_dev*fud;boolconnected;longin_flight;charname[24];}____cacheline_aligned_in_smp;/* A virtio-fs device instance */structvirtio_fs{structkrefrefcount;structlist_headlist;/* on virtio_fs_instances */char*tag;structvirtio_fs_vq*vqs;unsignedintnvqs;/* number of virtqueues */unsignedintnum_request_queues;/* number of request queues */};structvirtio_fs_forget{structfuse_in_headerih;structfuse_forget_inarg;/* This request can be temporarily queued on virt queue */structlist_headlist;};staticinlinestructvirtio_fs_vq*vq_to_fsvq(structvirtqueue*vq){structvirtio_fs*fs=vq->vdev->priv;return&fs->vqs[vq->index];}staticinlinestructfuse_pqueue*vq_to_fpq(structvirtqueue*vq){return&vq_to_fsvq(vq)->fud->pq;}staticvoidrelease_virtio_fs_obj(structkref*ref){structvirtio_fs*vfs=container_of(ref,structvirtio_fs,refcount);kfree(vfs->vqs);kfree(vfs);}/* Make sure virtiofs_mutex is held */staticvoidvirtio_fs_put(structvirtio_fs*fs){kref_put(&fs->refcount,release_virtio_fs_obj);}staticvoidvirtio_fs_fiq_release(structfuse_iqueue*fiq){structvirtio_fs*vfs=fiq->priv;mutex_lock(&virtio_fs_mutex);virtio_fs_put(vfs);mutex_unlock(&virtio_fs_mutex);}staticvoidvirtio_fs_drain_queue(structvirtio_fs_vq*fsvq){WARN_ON(fsvq->in_flight<0);/* Wait for in flight requests to finish.*/while(1){spin_lock(&fsvq->lock);if(!fsvq->in_flight){spin_unlock(&fsvq->lock);break;}spin_unlock(&fsvq->lock);/* TODO use completion instead of timeout */usleep_range(1000,2000);}flush_work(&fsvq->done_work);flush_delayed_work(&fsvq->dispatch_work);