fs/fuse kio: missed clean di->size.op in failed shrink request

Submitted by Pavel Butsykin on Dec. 14, 2018, 5:38 p.m.

Details

Message ID 20181214173818.2328-1-pbutsykin@virtuozzo.com
State New
Series "fs/fuse kio: missed clean di->size.op in failed shrink request"
Headers show

Commit Message

Pavel Butsykin Dec. 14, 2018, 5:38 p.m.
The state di->size.op is set to PCS_SIZE_SHRINK in order to postpone all read
requests during shrink request execution. But, if the shrink request fails in
__fuse_request_send(), then di->size.op is never cleaned up and it remains
PCS_SIZE_SHRINK forever, and pending read requests can remain hanging
indefinitely.

To fix this we can reuse req->end that actually _pcs_shrink_end() which already
has everything we need to cleanup shrink request.

There is no need to make a similar fix for ms since req->end callback is no
where used for sync(no background) requests except kio.

#VSTOR-18947

Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
---
 fs/fuse/dev.c                      | 4 ++++
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ce75d218025b..6fcbb117aa9c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -543,9 +543,13 @@  static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req,
 	if (!fiq->connected) {
 		spin_unlock(&fiq->waitq.lock);
 		req->out.h.error = -ENOTCONN;
+		if (req->end)
+			req->end(fc, req);
 	} else if (ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state)) {
 		spin_unlock(&fiq->waitq.lock);
 		req->out.h.error = -EIO;
+		if (req->end)
+			req->end(fc, req);
 	} else {
 		req->in.h.unique = fuse_get_unique(fiq);
 		queue_request(fiq, req);
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 3b1d819792b2..de54fedeb5e4 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -992,8 +992,9 @@  static void kpcs_setattr_end(struct fuse_conn *fc, struct fuse_req *req)
 	u64 old_size;
 
 	BUG_ON(req->in.h.opcode != FUSE_SETATTR);
-	TRACE("update size: ino:%lu old_sz:%lld new:%lld\n",
-	      req->io_inode->i_ino, di->fileinfo.attr.size, outarg->attr.size);
+	TRACE("update size: ino:%lu old_sz:%lld new:%lld, error: %d\n",
+	      req->io_inode->i_ino, di->fileinfo.attr.size, outarg->attr.size,
+	      req->out.h.error);
 
 	if (req->out.h.error)
 		goto fail;

Comments

Kirill Tkhai Dec. 17, 2018, 8:55 a.m.
On 14.12.2018 20:38, Pavel Butsykin wrote:
> The state di->size.op is set to PCS_SIZE_SHRINK in order to postpone all read
> requests during shrink request execution. But, if the shrink request fails in
> __fuse_request_send(), then di->size.op is never cleaned up and it remains
> PCS_SIZE_SHRINK forever, and pending read requests can remain hanging
> indefinitely.
> 
> To fix this we can reuse req->end that actually _pcs_shrink_end() which already
> has everything we need to cleanup shrink request.
> 
> There is no need to make a similar fix for ms since req->end callback is no
> where used for sync(no background) requests except kio.
> 
> #VSTOR-18947
> 
> Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>

Reviewed-by: Kirill Tkhai <ktkhai@virtuozzo.com>

> ---
>  fs/fuse/dev.c                      | 4 ++++
>  fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 5 +++--
>  2 files changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index ce75d218025b..6fcbb117aa9c 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -543,9 +543,13 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req,
>  	if (!fiq->connected) {
>  		spin_unlock(&fiq->waitq.lock);
>  		req->out.h.error = -ENOTCONN;
> +		if (req->end)
> +			req->end(fc, req);
>  	} else if (ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state)) {
>  		spin_unlock(&fiq->waitq.lock);
>  		req->out.h.error = -EIO;
> +		if (req->end)
> +			req->end(fc, req);
>  	} else {
>  		req->in.h.unique = fuse_get_unique(fiq);
>  		queue_request(fiq, req);
> diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
> index 3b1d819792b2..de54fedeb5e4 100644
> --- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
> +++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
> @@ -992,8 +992,9 @@ static void kpcs_setattr_end(struct fuse_conn *fc, struct fuse_req *req)
>  	u64 old_size;
>  
>  	BUG_ON(req->in.h.opcode != FUSE_SETATTR);
> -	TRACE("update size: ino:%lu old_sz:%lld new:%lld\n",
> -	      req->io_inode->i_ino, di->fileinfo.attr.size, outarg->attr.size);
> +	TRACE("update size: ino:%lu old_sz:%lld new:%lld, error: %d\n",
> +	      req->io_inode->i_ino, di->fileinfo.attr.size, outarg->attr.size,
> +	      req->out.h.error);
>  
>  	if (req->out.h.error)
>  		goto fail;
>