Commit 7ce4fab8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fuse-update-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse update from Miklos Szeredi:

 - Fix a regression introduced in the last release

 - Fix a number of issues with validating data coming from userspace

 - Some cleanups in virtiofs

* tag 'fuse-update-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: fix Kconfig indentation
  fuse: fix leak of fuse_io_priv
  virtiofs: Use completions while waiting for queue to be drained
  virtiofs: Do not send forget request "struct list_head" element
  virtiofs: Use a common function to send forget
  virtiofs: Fix old-style declaration
  fuse: verify nlink
  fuse: verify write return
  fuse: verify attributes
parents 0f137416 8d66fcb7
...@@ -34,7 +34,7 @@ config VIRTIO_FS ...@@ -34,7 +34,7 @@ config VIRTIO_FS
select VIRTIO select VIRTIO
help help
The Virtio Filesystem allows guests to mount file systems from the The Virtio Filesystem allows guests to mount file systems from the
host. host.
If you want to share files between guests or with the host, answer Y If you want to share files between guests or with the host, answer Y
or M. or M.
...@@ -248,7 +248,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) ...@@ -248,7 +248,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
kfree(forget); kfree(forget);
if (ret == -ENOMEM) if (ret == -ENOMEM)
goto out; goto out;
if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) if (ret || fuse_invalid_attr(&outarg.attr) ||
(outarg.attr.mode ^ inode->i_mode) & S_IFMT)
goto invalid; goto invalid;
forget_all_cached_acls(inode); forget_all_cached_acls(inode);
...@@ -319,6 +320,12 @@ int fuse_valid_type(int m) ...@@ -319,6 +320,12 @@ int fuse_valid_type(int m)
S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
} }
bool fuse_invalid_attr(struct fuse_attr *attr)
{
return !fuse_valid_type(attr->mode) ||
attr->size > LLONG_MAX;
}
int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
struct fuse_entry_out *outarg, struct inode **inode) struct fuse_entry_out *outarg, struct inode **inode)
{ {
...@@ -350,7 +357,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name ...@@ -350,7 +357,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
err = -EIO; err = -EIO;
if (!outarg->nodeid) if (!outarg->nodeid)
goto out_put_forget; goto out_put_forget;
if (!fuse_valid_type(outarg->attr.mode)) if (fuse_invalid_attr(&outarg->attr))
goto out_put_forget; goto out_put_forget;
*inode = fuse_iget(sb, outarg->nodeid, outarg->generation, *inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
...@@ -475,7 +482,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, ...@@ -475,7 +482,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
goto out_free_ff; goto out_free_ff;
err = -EIO; err = -EIO;
if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
fuse_invalid_attr(&outentry.attr))
goto out_free_ff; goto out_free_ff;
ff->fh = outopen.fh; ff->fh = outopen.fh;
...@@ -583,7 +591,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, ...@@ -583,7 +591,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
goto out_put_forget_req; goto out_put_forget_req;
err = -EIO; err = -EIO;
if (invalid_nodeid(outarg.nodeid)) if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
goto out_put_forget_req; goto out_put_forget_req;
if ((outarg.attr.mode ^ mode) & S_IFMT) if ((outarg.attr.mode ^ mode) & S_IFMT)
...@@ -862,7 +870,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, ...@@ -862,7 +870,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
spin_lock(&fi->lock); spin_lock(&fi->lock);
fi->attr_version = atomic64_inc_return(&fc->attr_version); fi->attr_version = atomic64_inc_return(&fc->attr_version);
inc_nlink(inode); if (likely(inode->i_nlink < UINT_MAX))
inc_nlink(inode);
spin_unlock(&fi->lock); spin_unlock(&fi->lock);
fuse_invalidate_attr(inode); fuse_invalidate_attr(inode);
fuse_update_ctime(inode); fuse_update_ctime(inode);
...@@ -942,7 +951,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, ...@@ -942,7 +951,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
args.out_args[0].value = &outarg; args.out_args[0].value = &outarg;
err = fuse_simple_request(fc, &args); err = fuse_simple_request(fc, &args);
if (!err) { if (!err) {
if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { if (fuse_invalid_attr(&outarg.attr) ||
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode); make_bad_inode(inode);
err = -EIO; err = -EIO;
} else { } else {
...@@ -1563,7 +1573,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, ...@@ -1563,7 +1573,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
goto error; goto error;
} }
if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { if (fuse_invalid_attr(&outarg.attr) ||
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode); make_bad_inode(inode);
err = -EIO; err = -EIO;
goto error; goto error;
......
...@@ -713,8 +713,10 @@ static ssize_t fuse_async_req_send(struct fuse_conn *fc, ...@@ -713,8 +713,10 @@ static ssize_t fuse_async_req_send(struct fuse_conn *fc,
ia->ap.args.end = fuse_aio_complete_req; ia->ap.args.end = fuse_aio_complete_req;
err = fuse_simple_background(fc, &ia->ap.args, GFP_KERNEL); err = fuse_simple_background(fc, &ia->ap.args, GFP_KERNEL);
if (err)
fuse_aio_complete_req(fc, &ia->ap.args, err);
return err ?: num_bytes; return num_bytes;
} }
static ssize_t fuse_send_read(struct fuse_io_args *ia, loff_t pos, size_t count, static ssize_t fuse_send_read(struct fuse_io_args *ia, loff_t pos, size_t count,
...@@ -1096,6 +1098,8 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia, ...@@ -1096,6 +1098,8 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
ia->write.in.flags = fuse_write_flags(iocb); ia->write.in.flags = fuse_write_flags(iocb);
err = fuse_simple_request(fc, &ap->args); err = fuse_simple_request(fc, &ap->args);
if (!err && ia->write.out.size > count)
err = -EIO;
offset = ap->descs[0].offset; offset = ap->descs[0].offset;
count = ia->write.out.size; count = ia->write.out.size;
......
...@@ -989,6 +989,8 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc); ...@@ -989,6 +989,8 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc);
*/ */
int fuse_valid_type(int m); int fuse_valid_type(int m);
bool fuse_invalid_attr(struct fuse_attr *attr);
/** /**
* Is current process allowed to perform filesystem operation? * Is current process allowed to perform filesystem operation?
*/ */
......
...@@ -184,7 +184,7 @@ static int fuse_direntplus_link(struct file *file, ...@@ -184,7 +184,7 @@ static int fuse_direntplus_link(struct file *file,
if (invalid_nodeid(o->nodeid)) if (invalid_nodeid(o->nodeid))
return -EIO; return -EIO;
if (!fuse_valid_type(o->attr.mode)) if (fuse_invalid_attr(&o->attr))
return -EIO; return -EIO;
fc = get_fuse_conn(dir); fc = get_fuse_conn(dir);
......
...@@ -35,6 +35,7 @@ struct virtio_fs_vq { ...@@ -35,6 +35,7 @@ struct virtio_fs_vq {
struct fuse_dev *fud; struct fuse_dev *fud;
bool connected; bool connected;
long in_flight; long in_flight;
struct completion in_flight_zero; /* No inflight requests */
char name[24]; char name[24];
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
...@@ -48,11 +49,15 @@ struct virtio_fs { ...@@ -48,11 +49,15 @@ struct virtio_fs {
unsigned int num_request_queues; /* number of request queues */ 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_in_header ih;
struct fuse_forget_in arg; struct fuse_forget_in arg;
};
struct virtio_fs_forget {
/* This request can be temporarily queued on virt queue */ /* This request can be temporarily queued on virt queue */
struct list_head list; struct list_head list;
struct virtio_fs_forget_req req;
}; };
static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
...@@ -81,6 +86,8 @@ static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq) ...@@ -81,6 +86,8 @@ static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq)
{ {
WARN_ON(fsvq->in_flight <= 0); WARN_ON(fsvq->in_flight <= 0);
fsvq->in_flight--; fsvq->in_flight--;
if (!fsvq->in_flight)
complete(&fsvq->in_flight_zero);
} }
static void release_virtio_fs_obj(struct kref *ref) static void release_virtio_fs_obj(struct kref *ref)
...@@ -111,22 +118,23 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq) ...@@ -111,22 +118,23 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq)
WARN_ON(fsvq->in_flight < 0); WARN_ON(fsvq->in_flight < 0);
/* Wait for in flight requests to finish.*/ /* Wait for in flight requests to finish.*/
while (1) { spin_lock(&fsvq->lock);
spin_lock(&fsvq->lock); if (fsvq->in_flight) {
if (!fsvq->in_flight) { /* We are holding virtio_fs_mutex. There should not be any
spin_unlock(&fsvq->lock); * waiters waiting for completion.
break; */
} reinit_completion(&fsvq->in_flight_zero);
spin_unlock(&fsvq->lock);
wait_for_completion(&fsvq->in_flight_zero);
} else {
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
/* TODO use completion instead of timeout */
usleep_range(1000, 2000);
} }
flush_work(&fsvq->done_work); flush_work(&fsvq->done_work);
flush_delayed_work(&fsvq->dispatch_work); flush_delayed_work(&fsvq->dispatch_work);
} }
static void virtio_fs_drain_all_queues(struct virtio_fs *fs) static void virtio_fs_drain_all_queues_locked(struct virtio_fs *fs)
{ {
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq;
int i; int i;
...@@ -137,6 +145,19 @@ static void virtio_fs_drain_all_queues(struct virtio_fs *fs) ...@@ -137,6 +145,19 @@ static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
} }
} }
static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
{
/* Provides mutual exclusion between ->remove and ->kill_sb
* paths. We don't want both of these draining queue at the
* same time. Current completion logic reinits completion
* and that means there should not be any other thread
* doing reinit or waiting for completion already.
*/
mutex_lock(&virtio_fs_mutex);
virtio_fs_drain_all_queues_locked(fs);
mutex_unlock(&virtio_fs_mutex);
}
static void virtio_fs_start_all_queues(struct virtio_fs *fs) static void virtio_fs_start_all_queues(struct virtio_fs *fs)
{ {
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq;
...@@ -313,17 +334,72 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) ...@@ -313,17 +334,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) static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
{ {
struct virtio_fs_forget *forget; struct virtio_fs_forget *forget;
struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq, struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq,
dispatch_work.work); 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__); pr_debug("virtio-fs: worker %s called.\n", __func__);
while (1) { while (1) {
spin_lock(&fsvq->lock); spin_lock(&fsvq->lock);
...@@ -335,43 +411,9 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) ...@@ -335,43 +411,9 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
} }
list_del(&forget->list); 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); spin_unlock(&fsvq->lock);
if (send_forget_request(fsvq, forget, true))
if (notify) return;
virtqueue_notify(vq);
pr_debug("virtio-fs: worker %s dispatched one forget request.\n",
__func__);
} }
} }
...@@ -556,6 +598,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, ...@@ -556,6 +598,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].end_reqs); INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].end_reqs);
INIT_DELAYED_WORK(&fs->vqs[VQ_HIPRIO].dispatch_work, INIT_DELAYED_WORK(&fs->vqs[VQ_HIPRIO].dispatch_work,
virtio_fs_hiprio_dispatch_work); virtio_fs_hiprio_dispatch_work);
init_completion(&fs->vqs[VQ_HIPRIO].in_flight_zero);
spin_lock_init(&fs->vqs[VQ_HIPRIO].lock); spin_lock_init(&fs->vqs[VQ_HIPRIO].lock);
/* Initialize the requests virtqueues */ /* Initialize the requests virtqueues */
...@@ -566,6 +609,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, ...@@ -566,6 +609,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
virtio_fs_request_dispatch_work); virtio_fs_request_dispatch_work);
INIT_LIST_HEAD(&fs->vqs[i].queued_reqs); INIT_LIST_HEAD(&fs->vqs[i].queued_reqs);
INIT_LIST_HEAD(&fs->vqs[i].end_reqs); INIT_LIST_HEAD(&fs->vqs[i].end_reqs);
init_completion(&fs->vqs[i].in_flight_zero);
snprintf(fs->vqs[i].name, sizeof(fs->vqs[i].name), snprintf(fs->vqs[i].name, sizeof(fs->vqs[i].name),
"requests.%u", i - VQ_REQUEST); "requests.%u", i - VQ_REQUEST);
callbacks[i] = virtio_fs_vq_done; callbacks[i] = virtio_fs_vq_done;
...@@ -659,7 +703,7 @@ static void virtio_fs_remove(struct virtio_device *vdev) ...@@ -659,7 +703,7 @@ static void virtio_fs_remove(struct virtio_device *vdev)
/* This device is going away. No one should get new reference */ /* This device is going away. No one should get new reference */
list_del_init(&fs->list); list_del_init(&fs->list);
virtio_fs_stop_all_queues(fs); virtio_fs_stop_all_queues(fs);
virtio_fs_drain_all_queues(fs); virtio_fs_drain_all_queues_locked(fs);
vdev->config->reset(vdev); vdev->config->reset(vdev);
virtio_fs_cleanup_vqs(vdev, fs); virtio_fs_cleanup_vqs(vdev, fs);
...@@ -684,12 +728,12 @@ static int virtio_fs_restore(struct virtio_device *vdev) ...@@ -684,12 +728,12 @@ static int virtio_fs_restore(struct virtio_device *vdev)
} }
#endif /* CONFIG_PM_SLEEP */ #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 }, { 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 = { static struct virtio_driver virtio_fs_driver = {
.driver.name = KBUILD_MODNAME, .driver.name = KBUILD_MODNAME,
...@@ -710,14 +754,10 @@ __releases(fiq->lock) ...@@ -710,14 +754,10 @@ __releases(fiq->lock)
{ {
struct fuse_forget_link *link; struct fuse_forget_link *link;
struct virtio_fs_forget *forget; struct virtio_fs_forget *forget;
struct scatterlist sg; struct virtio_fs_forget_req *req;
struct scatterlist *sgs[] = {&sg};
struct virtio_fs *fs; struct virtio_fs *fs;
struct virtqueue *vq;
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq;
bool notify;
u64 unique; u64 unique;
int ret;
link = fuse_dequeue_forget(fiq, 1, NULL); link = fuse_dequeue_forget(fiq, 1, NULL);
unique = fuse_get_unique(fiq); unique = fuse_get_unique(fiq);
...@@ -728,57 +768,19 @@ __releases(fiq->lock) ...@@ -728,57 +768,19 @@ __releases(fiq->lock)
/* Allocate a buffer for the request */ /* Allocate a buffer for the request */
forget = kmalloc(sizeof(*forget), GFP_NOFS | __GFP_NOFAIL); 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, .opcode = FUSE_FORGET,
.nodeid = link->forget_one.nodeid, .nodeid = link->forget_one.nodeid,
.unique = unique, .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, .nlookup = link->forget_one.nlookup,
}; };
sg_init_one(&sg, forget, sizeof(*forget)); send_forget_request(fsvq, forget, false);
/* 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:
kfree(link); kfree(link);
} }
...@@ -1026,7 +1028,7 @@ __releases(fiq->lock) ...@@ -1026,7 +1028,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_forget_and_unlock = virtio_fs_wake_forget_and_unlock,
.wake_interrupt_and_unlock = virtio_fs_wake_interrupt_and_unlock, .wake_interrupt_and_unlock = virtio_fs_wake_interrupt_and_unlock,
.wake_pending_and_unlock = virtio_fs_wake_pending_and_unlock, .wake_pending_and_unlock = virtio_fs_wake_pending_and_unlock,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment