2525 */
2626#define BUFSIZE (PAGE_SIZE)
2727
28+ #define BFD_MAX_DYNAMIC_SIZE (2 * 1024 * 1024)
29+
2830struct bfd_buf {
2931 char * mem ;
32+ size_t size ;
3033 struct list_head l ;
3134};
3235
@@ -61,6 +64,7 @@ static int buf_get(struct xbuf *xb)
6164 }
6265
6366 b -> mem = mem + i * BUFSIZE ;
67+ b -> size = BUFSIZE ;
6468 list_add_tail (& b -> l , & bufs );
6569 }
6670 }
@@ -77,11 +81,20 @@ static int buf_get(struct xbuf *xb)
7781
7882static void buf_put (struct xbuf * xb )
7983{
80- /*
81- * Don't unmap buffer back, it will get reused
82- * by next bfdopen call
83- */
84- list_add (& xb -> buf -> l , & bufs );
84+ struct bfd_buf * b = xb -> buf ;
85+
86+ if (b -> size > BUFSIZE ) {
87+ /* This buffer was remapped to fit a long line, unmap it back */
88+ munmap (b -> mem , b -> size );
89+ xfree (b );
90+ } else {
91+ /*
92+ * Don't unmap standard buffer back, it will get reused
93+ * by next bfdopen call
94+ */
95+ list_add (& b -> l , & bufs );
96+ }
97+
8598 xb -> buf = NULL ;
8699 xb -> mem = NULL ;
87100 xb -> data = NULL ;
@@ -140,11 +153,13 @@ static int brefill(struct bfd *f)
140153{
141154 int ret ;
142155 struct xbuf * b = & f -> b ;
156+ struct bfd_buf * b_buf = b -> buf ;
157+ size_t cap = b_buf ? b_buf -> size : BUFSIZE ;
143158
144159 memmove (b -> mem , b -> data , b -> sz );
145160 b -> data = b -> mem ;
146161
147- ret = read_all (f -> fd , b -> mem + b -> sz , BUFSIZE - b -> sz );
162+ ret = read_all (f -> fd , b -> mem + b -> sz , cap - b -> sz );
148163 if (ret < 0 ) {
149164 pr_perror ("Error reading file" );
150165 return -1 ;
@@ -172,12 +187,70 @@ char *breadline(struct bfd *f)
172187 return breadchr (f , '\n' );
173188}
174189
190+ static int grow_bfd_buffer (struct xbuf * b , struct bfd_buf * * p_b_buf , size_t cap )
191+ {
192+ struct bfd_buf * b_buf = * p_b_buf ;
193+ struct bfd_buf * new_buf ;
194+ void * new_mem ;
195+ size_t new_cap = cap * 2 ;
196+
197+ if (new_cap > BFD_MAX_DYNAMIC_SIZE ) {
198+ pr_err ("Line too long to fit in BFD_MAX_DYNAMIC_SIZE\n" );
199+ return - EIO ;
200+ }
201+
202+ new_buf = xmalloc (sizeof (* new_buf ));
203+ if (!new_buf ) {
204+ pr_perror ("Unable to allocate buffer for bfd" );
205+ return - ENOMEM ;
206+ }
207+
208+ new_mem = mmap (NULL , new_cap , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS , 0 , 0 );
209+ if (new_mem == MAP_FAILED ) {
210+ pr_perror ("Unable to allocate memory for bfd buffer" );
211+ xfree (new_buf );
212+ return - ENOMEM ;
213+ }
214+
215+ memcpy (new_mem , b -> data , b -> sz );
216+
217+ if (b_buf ) {
218+ if (b_buf -> size > BUFSIZE ) {
219+ /* This buffer was remapped to fit a long line, unmap it back */
220+ munmap (b_buf -> mem , b_buf -> size );
221+ xfree (b_buf );
222+ } else {
223+ /*
224+ * Don't unmap standard buffer back, it will get reused
225+ * by next bfdopen call
226+ */
227+ list_add (& b_buf -> l , & bufs );
228+ }
229+ }
230+
231+ /* Update pointers with the newly allocated buffer */
232+ * p_b_buf = new_buf ;
233+ b -> buf = new_buf ;
234+
235+ new_buf -> mem = new_mem ;
236+ new_buf -> size = new_cap ;
237+
238+ b -> mem = new_mem ;
239+ b -> data = new_mem ;
240+
241+ return 0 ;
242+ }
243+
175244char * breadchr (struct bfd * f , char c )
176245{
177246 struct xbuf * b = & f -> b ;
247+ struct bfd_buf * b_buf = b -> buf ;
178248 bool refilled = false;
179249 char * n ;
250+ size_t cap ;
180251 unsigned int ss = 0 ;
252+ int fill_ret ;
253+ char * final_str ;
181254
182255again :
183256 n = strnchr (b -> data + ss , b -> sz - ss , c );
@@ -195,40 +268,41 @@ char *breadchr(struct bfd *f, char c)
195268 if (!b -> sz )
196269 return NULL ;
197270
198- if (b -> sz == BUFSIZE ) {
199- pr_err ("The bfd buffer is too small\n" );
200- return ERR_PTR (- EIO );
271+ cap = b_buf ? b_buf -> size : BUFSIZE ;
272+ if (b -> sz == cap ) {
273+ int err = grow_bfd_buffer (b , & b_buf , cap );
274+ if (err )
275+ return ERR_PTR (err );
201276 }
202- /*
203- * Last bytes may lack the \n at the
204- * end, need to report this as full
205- * line anyway
206- */
207- b -> data [b -> sz ] = '\0' ;
208-
209- /*
210- * The b->data still points to old data,
211- * but we say that no bytes left there
212- * so next call to breadline will not
213- * "find" these bytes again.
214- */
215- b -> sz = 0 ;
216- return b -> data ;
217277 }
218278
219- /*
220- * small optimization -- we've scanned b->sz
221- * symbols already, no need to re-scan them after
222- * the buffer refill.
223- */
224279 ss = b -> sz ;
225280
226- /* no full line in the buffer -- refill one */
227- if (brefill ( f ) < 0 )
281+ fill_ret = brefill ( f );
282+ if (fill_ret < 0 )
228283 return ERR_PTR (- EIO );
229284
230- refilled = true;
285+ if (fill_ret == 0 ) {
286+ if (!b -> sz )
287+ return NULL ;
288+
289+ cap = b_buf ? b_buf -> size : BUFSIZE ;
290+ if (b -> sz == cap ) {
291+ int err = grow_bfd_buffer (b , & b_buf , cap );
292+ if (err )
293+ return ERR_PTR (err );
294+ }
295+
296+ final_str = b -> data ;
297+ final_str [b -> sz ] = '\0' ;
231298
299+ b -> data += b -> sz ;
300+ b -> sz = 0 ;
301+
302+ return final_str ;
303+ }
304+
305+ refilled = true;
232306 goto again ;
233307}
234308
@@ -251,15 +325,17 @@ static int bflush(struct bfd *bfd)
251325static int __bwrite (struct bfd * bfd , const void * buf , int size )
252326{
253327 struct xbuf * b = & bfd -> b ;
328+ struct bfd_buf * b_buf = b -> buf ;
329+ size_t cap = b_buf ? b_buf -> size : BUFSIZE ;
254330
255- if (b -> sz + size > BUFSIZE ) {
331+ if (b -> sz + size > cap ) {
256332 int ret ;
257333 ret = bflush (bfd );
258334 if (ret < 0 )
259335 return ret ;
260336 }
261337
262- if (size > BUFSIZE )
338+ if (size > cap )
263339 return write_all (bfd -> fd , buf , size );
264340
265341 memcpy (b -> data + b -> sz , buf , size );
0 commit comments