mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-03 23:58:05 +00:00
fuse update for 5.5
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCXedyjQAKCRDh3BK/laaZ PCR7AQCf+bb3/so1bygFeblBTT4UZbYZRXz2nZNSA5tgJvafWwD+I4MlqR+tEixb gZEusbtAVrtm3hJrBc+1fA1wacGhmAg= =Jg/0 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7ce4fab819
6 changed files with 134 additions and 115 deletions
|
@ -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)
|
||||||
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)
|
||||||
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
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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);
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
|
|
||||||
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 {
|
||||||
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 {
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
#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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
|
Loading…
Reference in a new issue