[PATCH v3 1/2] fscontext: do not consume log entries when returning -EMSGSIZE

Aleksa Sarai posted 2 patches 1 month, 4 weeks ago
[PATCH v3 1/2] fscontext: do not consume log entries when returning -EMSGSIZE
Posted by Aleksa Sarai 1 month, 4 weeks ago
Userspace generally expects APIs that return -EMSGSIZE to allow for them
to adjust their buffer size and retry the operation. However, the
fscontext log would previously clear the message even in the -EMSGSIZE
case.

Given that it is very cheap for us to check whether the buffer is too
small before we remove the message from the ring buffer, let's just do
that instead. While we're at it, refactor some fscontext_read() into a
separate helper to make the ring buffer logic a bit easier to read.

Fixes: 007ec26cdc9f ("vfs: Implement logging through fs_context")
Cc: David Howells <dhowells@redhat.com>
Cc: <stable@vger.kernel.org> # v5.2+
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
 fs/fsopen.c | 54 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/fs/fsopen.c b/fs/fsopen.c
index 1aaf4cb2afb2..538fdf814fbf 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -18,47 +18,53 @@
 #include "internal.h"
 #include "mount.h"
 
+static inline const char *fetch_message_locked(struct fc_log *log, size_t len,
+					       bool *need_free)
+{
+	const char *p;
+	int index;
+
+	if (unlikely(log->head == log->tail))
+		return ERR_PTR(-ENODATA);
+
+	index = log->tail & (ARRAY_SIZE(log->buffer) - 1);
+	p = log->buffer[index];
+	if (unlikely(strlen(p) > len))
+		return ERR_PTR(-EMSGSIZE);
+
+	log->buffer[index] = NULL;
+	*need_free = log->need_free & (1 << index);
+	log->need_free &= ~(1 << index);
+	log->tail++;
+
+	return p;
+}
+
 /*
  * Allow the user to read back any error, warning or informational messages.
+ * Only one message is returned for each read(2) call.
  */
 static ssize_t fscontext_read(struct file *file,
 			      char __user *_buf, size_t len, loff_t *pos)
 {
 	struct fs_context *fc = file->private_data;
-	struct fc_log *log = fc->log.log;
-	unsigned int logsize = ARRAY_SIZE(log->buffer);
 	ssize_t ret;
-	char *p;
+	const char *p;
 	bool need_free;
-	int index, n;
+	int n;
 
 	ret = mutex_lock_interruptible(&fc->uapi_mutex);
 	if (ret < 0)
 		return ret;
-
-	if (log->head == log->tail) {
-		mutex_unlock(&fc->uapi_mutex);
-		return -ENODATA;
-	}
-
-	index = log->tail & (logsize - 1);
-	p = log->buffer[index];
-	need_free = log->need_free & (1 << index);
-	log->buffer[index] = NULL;
-	log->need_free &= ~(1 << index);
-	log->tail++;
+	p = fetch_message_locked(fc->log.log, len, &need_free);
 	mutex_unlock(&fc->uapi_mutex);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
 
-	ret = -EMSGSIZE;
 	n = strlen(p);
-	if (n > len)
-		goto err_free;
-	ret = -EFAULT;
-	if (copy_to_user(_buf, p, n) != 0)
-		goto err_free;
+	if (copy_to_user(_buf, p, n))
+		n = -EFAULT;
 	ret = n;
-
-err_free:
 	if (need_free)
 		kfree(p);
 	return ret;

-- 
2.50.1
Re: [PATCH v3 1/2] fscontext: do not consume log entries when returning -EMSGSIZE
Posted by Al Viro 1 month, 4 weeks ago
On Thu, Aug 07, 2025 at 03:55:23AM +1000, Aleksa Sarai wrote:

> -		goto err_free;
> -	ret = -EFAULT;
> -	if (copy_to_user(_buf, p, n) != 0)
> -		goto err_free;
> +	if (copy_to_user(_buf, p, n))
> +		n = -EFAULT;
>  	ret = n;
> -
> -err_free:
>  	if (need_free)
>  		kfree(p);
>  	return ret;

Minor nit: seeing that there's only one path to that return, I would
rather turn it into
	return n;
and dropped the assignment to ret a few lines above.  Anyway, that's
trivially done when applying...

Anyway, who's carrying fscontext-related stuff this cycle?  I've got
a short series in that area, but there won't be much from me around
there - a plenty of tree-in-dcache stuff, quite a bit of mount-related
work, etc., but not a lot around the options-parsing machinery.

Christian, do you have any plans around that area?
Re: [PATCH v3 1/2] fscontext: do not consume log entries when returning -EMSGSIZE
Posted by Christian Brauner 1 month, 3 weeks ago
On Wed, Aug 06, 2025 at 08:07:51PM +0100, Al Viro wrote:
> On Thu, Aug 07, 2025 at 03:55:23AM +1000, Aleksa Sarai wrote:
> 
> > -		goto err_free;
> > -	ret = -EFAULT;
> > -	if (copy_to_user(_buf, p, n) != 0)
> > -		goto err_free;
> > +	if (copy_to_user(_buf, p, n))
> > +		n = -EFAULT;
> >  	ret = n;
> > -
> > -err_free:
> >  	if (need_free)
> >  		kfree(p);
> >  	return ret;
> 
> Minor nit: seeing that there's only one path to that return, I would
> rather turn it into
> 	return n;
> and dropped the assignment to ret a few lines above.  Anyway, that's
> trivially done when applying...
> 
> Anyway, who's carrying fscontext-related stuff this cycle?  I've got
> a short series in that area, but there won't be much from me around
> there - a plenty of tree-in-dcache stuff, quite a bit of mount-related
> work, etc., but not a lot around the options-parsing machinery.
> 
> Christian, do you have any plans around that area?

I've got a tree for that already and have applied related stuff there.
I've fixed up the comments from this thread.
Re: [PATCH v3 1/2] fscontext: do not consume log entries when returning -EMSGSIZE
Posted by Aleksa Sarai 1 month, 4 weeks ago
On 2025-08-06, Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Thu, Aug 07, 2025 at 03:55:23AM +1000, Aleksa Sarai wrote:
> 
> > -		goto err_free;
> > -	ret = -EFAULT;
> > -	if (copy_to_user(_buf, p, n) != 0)
> > -		goto err_free;
> > +	if (copy_to_user(_buf, p, n))
> > +		n = -EFAULT;
> >  	ret = n;
> > -
> > -err_free:
> >  	if (need_free)
> >  		kfree(p);
> >  	return ret;
> 
> Minor nit: seeing that there's only one path to that return, I would
> rather turn it into
> 	return n;
> and dropped the assignment to ret a few lines above.  Anyway, that's
> trivially done when applying...

It felt odd to use "return ret;" at the start and switch to "return n;"
at the end, but feel free to change it when applying.

> Anyway, who's carrying fscontext-related stuff this cycle?  I've got
> a short series in that area, but there won't be much from me around
> there - a plenty of tree-in-dcache stuff, quite a bit of mount-related
> work, etc., but not a lot around the options-parsing machinery.
> 
> Christian, do you have any plans around that area?

-- 
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
https://www.cyphar.com/
Re: [PATCH v3 1/2] fscontext: do not consume log entries when returning -EMSGSIZE
Posted by Al Viro 1 month, 4 weeks ago
On Thu, Aug 07, 2025 at 12:46:17PM +1000, Aleksa Sarai wrote:

> It felt odd to use "return ret;" at the start and switch to "return n;"
> at the end, but feel free to change it when applying.

s/ret/err/ would take care of that, as well as clarifying the intent -
not that "mutex_lock_interruptible() returns 0 or error" hadn't been
the basic common knowledge...

Anyway, that's really nitpicking at this point.