when given a max_fds argument lower than that current size (that can happen when called from close_range(..., CLOSE_RANGE_UNSHARE)), we can ignore all descriptors >= max_fds. Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> --- fs/file.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/fs/file.c b/fs/file.c index fbcd3da46109..894bd18241b5 100644 --- a/fs/file.c +++ b/fs/file.c @@ -272,20 +272,6 @@ static inline bool fd_is_open(unsigned int fd, const struct fdtable *fdt) return test_bit(fd, fdt->open_fds); } -static unsigned int count_open_files(struct fdtable *fdt) -{ - unsigned int size = fdt->max_fds; - unsigned int i; - - /* Find the last open fd */ - for (i = size / BITS_PER_LONG; i > 0; ) { - if (fdt->open_fds[--i]) - break; - } - i = (i + 1) * BITS_PER_LONG; - return i; -} - /* * Note that a sane fdtable size always has to be a multiple of * BITS_PER_LONG, since we have bitmaps that are sized by this. @@ -297,16 +283,33 @@ static unsigned int count_open_files(struct fdtable *fdt) * * Rather than make close_range() have to worry about this, * just make that BITS_PER_LONG alignment be part of a sane - * fdtable size. Becuase that's really what it is. + * fdtable size. Because that's really what it is. */ static unsigned int sane_fdtable_size(struct fdtable *fdt, unsigned int max_fds) { - unsigned int count; + const unsigned int min_words = BITS_TO_LONGS(NR_OPEN_DEFAULT); // 1 + unsigned long mask; + unsigned int words; + + if (max_fds > fdt->max_fds) + max_fds = fdt->max_fds; + + if (max_fds == NR_OPEN_DEFAULT) + return NR_OPEN_DEFAULT; + + /* + * What follows is a simplified find_last_bit(). There's no point + * finding exact last bit, when we are going to round it up anyway. + */ + words = BITS_TO_LONGS(max_fds); + mask = BITMAP_LAST_WORD_MASK(max_fds); + + while (words > min_words && !(fdt->open_fds[words - 1] & mask)) { + mask = ~0UL; + words--; + } - count = count_open_files(fdt); - if (max_fds < NR_OPEN_DEFAULT) - max_fds = NR_OPEN_DEFAULT; - return ALIGN(min(count, max_fds), BITS_PER_LONG); + return words * BITS_PER_LONG; } /* -- 2.39.2