From: Vivek Goyal <vgoyal@redhat.com>
To: Peng Tao <tao.peng@linux.alibaba.com>
Cc: virtio-fs@redhat.com
Subject: Re: [Virtio-fs] [PATCH] fuse: refcount FORGET requests
Date: Fri, 31 May 2019 09:22:28 -0400 [thread overview]
Message-ID: <20190531132228.GA26058@redhat.com> (raw)
In-Reply-To: <20190531092403.77976-1-tao.peng@linux.alibaba.com>
On Fri, May 31, 2019 at 05:24:03PM +0800, Peng Tao wrote:
> Right now FORGET requests are not tracked and they might be sent
> after DESTROY request.
How does that happen?
> Normally this is OK, since user space should
> be able to reject them knowing that the file system is already umounted.
> But if the same file system is mounted right again and the file is
> opened again, user space can be confused by the refcount decrement
> carried by the old FORGET requests.
>
> E.g., it can trigger an assertion in virtiofsd when running xfstests
> generic/129 and generic/130 together:
>
> unique: 23, opcode: FORGET (2), nodeid: 4, insize: 64, pid: 0
> forget 4 1 -2
> virtiofsd: contrib/virtiofsd/passthrough_ll.c:1044: unref_inode: Assertion `inode->refcount >= n' failed.
>
> To avoid confusing user space in such case, refcount FORGET requests so
> that fuse_sb_destroy() waits for all inflight requests before returning.
forgets are optional and destroy is supposed to cleanup any pending
state.
If this is a real issue, we probably need some notion of generation
number (either for the mount or for inode) and ignore forgets if
they don't belong to same generation.
Given this is per mount, probably some sort of number per init request
should make sense.
Thanks
Vivek
>
> Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
> ---
> fs/fuse/dev.c | 8 +++++++-
> fs/fuse/fuse_i.h | 8 ++++++++
> fs/fuse/virtio_fs.c | 10 ++++++++--
> 3 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index ee9dd38bc0f0..8f5617e07309 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -164,7 +164,7 @@ static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
> return !fc->initialized || (for_background && fc->blocked);
> }
>
> -static void fuse_drop_waiting(struct fuse_conn *fc)
> +void fuse_drop_waiting(struct fuse_conn *fc)
> {
> /*
> * lockess check of fc->connected is okay, because atomic_dec_and_test()
> @@ -177,6 +177,7 @@ static void fuse_drop_waiting(struct fuse_conn *fc)
> wake_up_all(&fc->blocked_waitq);
> }
> }
> +EXPORT_SYMBOL_GPL(fuse_drop_waiting);
>
> static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
> bool for_background)
> @@ -414,6 +415,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
>
> spin_lock(&fiq->waitq.lock);
> if (fiq->connected) {
> + atomic_inc(&fc->num_waiting);
> fiq->forget_list_tail->next = forget;
> fiq->forget_list_tail = forget;
> fiq->ops->wake_forget_and_unlock(fiq);
> @@ -1207,6 +1209,7 @@ static struct fuse_forget_link *dequeue_forget(struct fuse_iqueue *fiq,
> unsigned max,
> unsigned *countp)
> {
> + struct fuse_conn *fc = get_fuse_iqueue_conn(fiq);
> struct fuse_forget_link *head = fiq->forget_list_head.next;
> struct fuse_forget_link **newhead = &head;
> unsigned count;
> @@ -1222,6 +1225,9 @@ static struct fuse_forget_link *dequeue_forget(struct fuse_iqueue *fiq,
> if (countp != NULL)
> *countp = count;
>
> + while(count-- > 0)
> + fuse_drop_waiting(fc);
> +
> return head;
> }
>
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 7ac7f9a0b81b..609eafd60c30 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -923,6 +923,11 @@ static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
> return get_fuse_conn_super(inode->i_sb);
> }
>
> +static inline struct fuse_conn *get_fuse_iqueue_conn(struct fuse_iqueue *fiq)
> +{
> + return container_of(fiq, struct fuse_conn, iq);
> +}
> +
> static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
> {
> return container_of(inode, struct fuse_inode, inode);
> @@ -975,6 +980,9 @@ struct fuse_forget_link *fuse_alloc_forget(void);
> /* Used by READDIRPLUS */
> void fuse_force_forget(struct file *file, u64 nodeid);
>
> +/* Used by FORGET callback */
> +void fuse_drop_waiting(struct fuse_conn *fc);
> +
> /**
> * Initialize READ or READDIR request
> */
> diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
> index 18fc0dca0abc..466b88b944c0 100644
> --- a/fs/fuse/virtio_fs.c
> +++ b/fs/fuse/virtio_fs.c
> @@ -172,6 +172,7 @@ static void virtio_fs_hiprio_done_work(struct work_struct *work)
> {
> struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq,
> done_work);
> + struct fuse_conn *fc = fsvq->fud->fc;
> struct virtqueue *vq = fsvq->vq;
>
> /* Free completed FUSE_FORGET requests */
> @@ -182,8 +183,10 @@ static void virtio_fs_hiprio_done_work(struct work_struct *work)
>
> virtqueue_disable_cb(vq);
>
> - while ((req = virtqueue_get_buf(vq, &len)) != NULL)
> + while ((req = virtqueue_get_buf(vq, &len)) != NULL) {
> kfree(req);
> + fuse_drop_waiting(fc);
> + }
> } while (!virtqueue_enable_cb(vq) && likely(!virtqueue_is_broken(vq)));
> spin_unlock(&fsvq->lock);
> }
> @@ -695,7 +698,7 @@ __releases(fiq->waitq.lock)
> struct virtio_fs_vq *fsvq;
> bool notify;
> u64 unique;
> - int ret;
> + int ret = -ENOMEM;
>
> BUG_ON(!fiq->forget_list_head.next);
> link = fiq->forget_list_head.next;
> @@ -757,6 +760,9 @@ __releases(fiq->waitq.lock)
> if (notify)
> virtqueue_notify(vq);
> out:
> + if (ret < 0)
> + fuse_drop_waiting(fsvq->fud->fc);
> +
> kfree(link);
> }
>
> --
> 2.17.1
>
next prev parent reply other threads:[~2019-05-31 13:22 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-31 9:24 [Virtio-fs] [PATCH] fuse: refcount FORGET requests Peng Tao
2019-05-31 13:22 ` Vivek Goyal [this message]
2019-05-31 17:38 ` Liu Bo
2019-05-31 17:44 ` Vivek Goyal
2019-05-31 18:35 ` Liu Bo
2019-05-31 18:44 ` Liu Bo
2019-05-31 18:59 ` Vivek Goyal
2019-05-31 19:53 ` Liu Bo
2019-06-01 1:40 ` Tao Peng
2019-06-03 13:10 ` Vivek Goyal
2019-06-04 3:21 ` Tao Peng
2019-06-03 13:13 ` Vivek Goyal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190531132228.GA26058@redhat.com \
--to=vgoyal@redhat.com \
--cc=tao.peng@linux.alibaba.com \
--cc=virtio-fs@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.