@@ -1421,6 +1421,50 @@ static size_t get_record_print_text_size(struct printk_info *info,
14211421 return ((prefix_len * line_count ) + info -> text_len + 1 );
14221422}
14231423
1424+ /*
1425+ * Beginning with @start_seq, find the first record where it and all following
1426+ * records up to (but not including) @max_seq fit into @size.
1427+ *
1428+ * @max_seq is simply an upper bound and does not need to exist. If the caller
1429+ * does not require an upper bound, -1 can be used for @max_seq.
1430+ */
1431+ static u64 find_first_fitting_seq (u64 start_seq , u64 max_seq , size_t size ,
1432+ bool syslog , bool time )
1433+ {
1434+ struct printk_info info ;
1435+ unsigned int line_count ;
1436+ size_t len = 0 ;
1437+ u64 seq ;
1438+
1439+ /* Determine the size of the records up to @max_seq. */
1440+ prb_for_each_info (start_seq , prb , seq , & info , & line_count ) {
1441+ if (info .seq >= max_seq )
1442+ break ;
1443+ len += get_record_print_text_size (& info , line_count , syslog , time );
1444+ }
1445+
1446+ /*
1447+ * Adjust the upper bound for the next loop to avoid subtracting
1448+ * lengths that were never added.
1449+ */
1450+ if (seq < max_seq )
1451+ max_seq = seq ;
1452+
1453+ /*
1454+ * Move first record forward until length fits into the buffer. Ignore
1455+ * newest messages that were not counted in the above cycle. Messages
1456+ * might appear and get lost in the meantime. This is a best effort
1457+ * that prevents an infinite loop that could occur with a retry.
1458+ */
1459+ prb_for_each_info (start_seq , prb , seq , & info , & line_count ) {
1460+ if (len <= size || info .seq >= max_seq )
1461+ break ;
1462+ len -= get_record_print_text_size (& info , line_count , syslog , time );
1463+ }
1464+
1465+ return seq ;
1466+ }
1467+
14241468static int syslog_print (char __user * buf , int size )
14251469{
14261470 struct printk_info info ;
@@ -1492,9 +1536,7 @@ static int syslog_print(char __user *buf, int size)
14921536static int syslog_print_all (char __user * buf , int size , bool clear )
14931537{
14941538 struct printk_info info ;
1495- unsigned int line_count ;
14961539 struct printk_record r ;
1497- u64 max_seq ;
14981540 char * text ;
14991541 int len = 0 ;
15001542 u64 seq ;
@@ -1510,21 +1552,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
15101552 * Find first record that fits, including all following records,
15111553 * into the user-provided buffer for this dump.
15121554 */
1513- prb_for_each_info (clear_seq , prb , seq , & info , & line_count )
1514- len += get_record_print_text_size (& info , line_count , true, time );
1515-
1516- /*
1517- * Set an upper bound for the next loop to avoid subtracting lengths
1518- * that were never added.
1519- */
1520- max_seq = seq ;
1521-
1522- /* move first record forward until length fits into the buffer */
1523- prb_for_each_info (clear_seq , prb , seq , & info , & line_count ) {
1524- if (len <= size || info .seq >= max_seq )
1525- break ;
1526- len -= get_record_print_text_size (& info , line_count , true, time );
1527- }
1555+ seq = find_first_fitting_seq (clear_seq , -1 , size , true, time );
15281556
15291557 prb_rec_init_rd (& r , & info , text , LOG_LINE_MAX + PREFIX_MAX );
15301558
@@ -3427,7 +3455,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
34273455 char * buf , size_t size , size_t * len_out )
34283456{
34293457 struct printk_info info ;
3430- unsigned int line_count ;
34313458 struct printk_record r ;
34323459 unsigned long flags ;
34333460 u64 seq ;
@@ -3455,26 +3482,12 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
34553482
34563483 /*
34573484 * Find first record that fits, including all following records,
3458- * into the user-provided buffer for this dump.
3485+ * into the user-provided buffer for this dump. Pass in size-1
3486+ * because this function (by way of record_print_text()) will
3487+ * not write more than size-1 bytes of text into @buf.
34593488 */
3460-
3461- prb_for_each_info (dumper -> cur_seq , prb , seq , & info , & line_count ) {
3462- if (info .seq >= dumper -> next_seq )
3463- break ;
3464- len += get_record_print_text_size (& info , line_count , syslog , time );
3465- }
3466-
3467- /*
3468- * Move first record forward until length fits into the buffer. Ignore
3469- * newest messages that were not counted in the above cycle. Messages
3470- * might appear and get lost in the meantime. This is the best effort
3471- * that prevents an infinite loop.
3472- */
3473- prb_for_each_info (dumper -> cur_seq , prb , seq , & info , & line_count ) {
3474- if (len < size || info .seq >= dumper -> next_seq )
3475- break ;
3476- len -= get_record_print_text_size (& info , line_count , syslog , time );
3477- }
3489+ seq = find_first_fitting_seq (dumper -> cur_seq , dumper -> next_seq ,
3490+ size - 1 , syslog , time );
34783491
34793492 /*
34803493 * Next kmsg_dump_get_buffer() invocation will dump block of
0 commit comments