On Fri, Jan 22 2021, Xin Long wrote: > In commit 1f4aace60b0e ("fs/seq_file.c: simplify seq_file iteration code > and interface"), it broke a behavior: op show() is always called when op > next() returns an available obj. Interesting. I was not aware that some callers assumed this guarantee. If we are going to support it (which seems reasonable) we should add a statement of this guarantee to the documentation - Documentation/filesystems/seq_file.rst. Maybe a new paragraph after "Finally, the show() function ..." Note that show() will *always* be called after a successful start() or next() call, so that it can release any resources (such as ref-counts) that was acquired by those calls. > > This caused a refcnt leak in net/sctp/proc.c, as of the seq_operations > sctp_assoc_ops, transport obj is held in op next() and released in op > show(). > > Here fix it by moving count check against iov_iter_count after calling > op show() so that op show() can still be called when op next() returns > an available obj. > > Note that m->index needs to increase so that op start() could go fetch > the next obj in the next round. This is certainly wrong. As the introduction in my patch said: A large part of achieving this is to *always* call ->next after ->show has successfully stored all of an entry in the buffer. Never just increment the index instead. Incrementing ->index in common seq_file code is wrong. As we are no longer calling ->next after a successful ->show, we need to make that ->show appear unsuccessful so that it will be retried. This is done be setting "m->count = offs". So the moved code below becomes if (m->count >= iov_iter_count(iter)) { /* That record is more than we want, so discard it */ m->count = offs; break; } Possibly that can be merged into the preceding 'if'. Also the traverse() function contains a call to ->next that is not reliably followed by a call to ->show, even when successful. That needs to be fixed too. Thanks, NeilBrown > > Fixes: 1f4aace60b0e ("fs/seq_file.c: simplify seq_file iteration code and interface") > Reported-by: Prijesh <prpatel@xxxxxxxxxx> > Signed-off-by: Xin Long <lucien.xin@xxxxxxxxx> > --- > fs/seq_file.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/fs/seq_file.c b/fs/seq_file.c > index 03a369c..da304f7 100644 > --- a/fs/seq_file.c > +++ b/fs/seq_file.c > @@ -264,8 +264,6 @@ ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter) > } > if (!p || IS_ERR(p)) // no next record for us > break; > - if (m->count >= iov_iter_count(iter)) > - break; > err = m->op->show(m, p); > if (err > 0) { // ->show() says "skip it" > m->count = offs; > @@ -273,6 +271,10 @@ ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter) > m->count = offs; > break; > } > + if (m->count >= iov_iter_count(iter)) { > + m->index++; > + break; > + } > } > m->op->stop(m, p); > n = copy_to_iter(m->buf, m->count, iter); > -- > 2.1.0
Attachment:
signature.asc
Description: PGP signature