Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

lib/fonts: Manage font-data lifetime with font_data_get/_put()

Add font_data_get() and font_data_put(). Update consoles to use them
over REFCOUNT() and plain kfree().

Newly allocated font data starts with a reference count of 1. Loading
the font puts the previously loaded font. If the reference count reaches
zero, font_data_put() frees the font data.

The kernel stores a refcount of zero for internal font data. Invoking
font_data_get() and font_data_put() tests this internally and returns
success without further operation. From the caller's perspective,
getting and putting works the same for all font data.

Fbcon used the userfont flag distinguish between internal fonts and
fonts loaded by user space. Only the latter where refcounted. With the
new helper's automatic handling of internal font data, remove the
userfont flag from fbcon.

Newport_con uses a default font, FONT_DATA, until user space loads
custom font data. Remove all special cases for FONT_DATA, as the get
and put calls' read-only handling also covers this case.

v3:
- fix module linker error wrt font symbols (Nathan, Arnd)
- fix typos

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Helge Deller <deller@gmx.de>

authored by

Thomas Zimmermann and committed by
Helge Deller
1de371b1 e2e000a0

+115 -53
+8 -15
drivers/video/console/newport_con.c
··· 517 517 518 518 new_data += FONT_EXTRA_WORDS * sizeof(int); 519 519 FNTSIZE(new_data) = size; 520 - REFCOUNT(new_data) = 0; /* usage counter */ 520 + REFCOUNT(new_data) = 1; /* usage counter */ 521 521 FNTSUM(new_data) = 0; 522 522 523 523 p = (unsigned char *)font_data_buf(new_data); ··· 532 532 if (font_data[i] != FONT_DATA 533 533 && font_data_size(font_data[i]) == size 534 534 && !memcmp(font_data[i], new_data, size)) { 535 - kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); 535 + font_data_put(new_data); 536 536 /* current font is the same as the new one */ 537 537 if (i == unit) 538 538 return 0; 539 539 new_data = font_data[i]; 540 + font_data_get(new_data); 540 541 break; 541 542 } 542 543 } 543 - /* old font is user font */ 544 - if (font_data[unit] != FONT_DATA) { 545 - if (--REFCOUNT(font_data[unit]) == 0) 546 - kfree(font_data[unit] - 547 - FONT_EXTRA_WORDS * sizeof(int)); 548 - } 549 - REFCOUNT(new_data)++; 544 + 545 + font_data_put(font_data[unit]); 550 546 font_data[unit] = new_data; 551 547 552 548 return 0; ··· 550 554 551 555 static int newport_set_def_font(int unit, struct console_font *op) 552 556 { 553 - if (font_data[unit] != FONT_DATA) { 554 - if (--REFCOUNT(font_data[unit]) == 0) 555 - kfree(font_data[unit] - 556 - FONT_EXTRA_WORDS * sizeof(int)); 557 - font_data[unit] = FONT_DATA; 558 - } 557 + font_data_put(font_data[unit]); 558 + font_data[unit] = FONT_DATA; 559 + font_data_get(font_data[unit]); 559 560 560 561 return 0; 561 562 }
+30 -35
drivers/video/fbdev/core/fbcon.c
··· 1023 1023 vc->vc_font.charcount = font->charcount; 1024 1024 1025 1025 p->fontdata = font->data; 1026 + font_data_get(p->fontdata); 1026 1027 } 1027 1028 1028 1029 cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ··· 1087 1086 vc->vc_font.charcount = fvc->vc_font.charcount; 1088 1087 1089 1088 p->fontdata = t->fontdata; 1090 - p->userfont = t->userfont; 1091 - 1092 - if (p->userfont) 1093 - REFCOUNT(p->fontdata)++; 1089 + font_data_get(p->fontdata); 1094 1090 } else { 1095 1091 const struct font_desc *font = NULL; 1096 1092 ··· 1102 1104 vc->vc_font.charcount = font->charcount; 1103 1105 1104 1106 p->fontdata = font->data; 1107 + font_data_get(p->fontdata); 1105 1108 } 1106 1109 } 1107 1110 ··· 1193 1194 1194 1195 static void fbcon_free_font(struct fbcon_display *p) 1195 1196 { 1196 - if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) 1197 - kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); 1198 - p->fontdata = NULL; 1199 - p->userfont = 0; 1197 + if (p->fontdata) { 1198 + font_data_put(p->fontdata); 1199 + p->fontdata = NULL; 1200 + } 1200 1201 } 1201 1202 1202 1203 static void set_vc_hi_font(struct vc_data *vc, bool set); ··· 1419 1420 vc->vc_font.height = (*default_mode)->vc_font.height; 1420 1421 vc->vc_font.charcount = (*default_mode)->vc_font.charcount; 1421 1422 p->fontdata = t->fontdata; 1422 - p->userfont = t->userfont; 1423 - if (p->userfont) 1424 - REFCOUNT(p->fontdata)++; 1423 + font_data_get(p->fontdata); 1425 1424 } 1426 1425 1427 1426 var->activate = FB_ACTIVATE_NOW; ··· 2050 2053 struct fb_var_screeninfo var = info->var; 2051 2054 int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; 2052 2055 2053 - if (p->userfont && font_data_size(p->fontdata)) { 2056 + if (font_data_size(p->fontdata)) { 2054 2057 unsigned int size = vc_font_size(&vc->vc_font); 2055 2058 2056 2059 /* ··· 2410 2413 } 2411 2414 2412 2415 static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, 2413 - font_data_t *data, int userfont) 2416 + font_data_t *data) 2414 2417 { 2415 2418 struct fb_info *info = fbcon_info_from_console(vc->vc_num); 2416 2419 struct fbcon_par *par = info->fbcon_par; 2417 2420 struct fbcon_display *p = &fb_display[vc->vc_num]; 2418 - int resize, ret, old_userfont, old_width, old_height, old_charcount; 2421 + int resize, ret, old_width, old_height, old_charcount; 2419 2422 font_data_t *old_fontdata = p->fontdata; 2420 2423 const u8 *old_data = vc->vc_font.data; 2424 + 2425 + font_data_get(data); 2421 2426 2422 2427 resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); 2423 2428 p->fontdata = data; 2424 2429 vc->vc_font.data = font_data_buf(p->fontdata); 2425 - old_userfont = p->userfont; 2426 - if ((p->userfont = userfont)) 2427 - REFCOUNT(data)++; 2428 2430 2429 2431 old_width = vc->vc_font.width; 2430 2432 old_height = vc->vc_font.height; ··· 2453 2457 update_screen(vc); 2454 2458 } 2455 2459 2456 - if (old_userfont && (--REFCOUNT(old_fontdata) == 0)) 2457 - kfree(old_fontdata - FONT_EXTRA_WORDS * sizeof(int)); 2460 + if (old_fontdata) 2461 + font_data_put(old_fontdata); 2462 + 2458 2463 return 0; 2459 2464 2460 2465 err_out: 2461 2466 p->fontdata = old_fontdata; 2462 2467 vc->vc_font.data = old_data; 2463 - 2464 - if (userfont) { 2465 - p->userfont = old_userfont; 2466 - if (--REFCOUNT(data) == 0) 2467 - kfree(data - FONT_EXTRA_WORDS * sizeof(int)); 2468 - } 2469 - 2470 2468 vc->vc_font.width = old_width; 2471 2469 vc->vc_font.height = old_height; 2472 2470 vc->vc_font.charcount = old_charcount; 2471 + 2472 + font_data_put(data); 2473 2473 2474 2474 return ret; 2475 2475 } ··· 2483 2491 int w = font->width; 2484 2492 int h = font->height; 2485 2493 int size, alloc_size; 2486 - int i, csum; 2494 + int i, csum, ret; 2487 2495 font_data_t *new_data; 2488 - u8 *data = font->data; 2496 + const u8 *data = font->data; 2489 2497 int pitch = PITCH(font->width); 2490 2498 2491 2499 /* Is there a reason why fbconsole couldn't handle any charcount >256? ··· 2528 2536 2529 2537 new_data += FONT_EXTRA_WORDS * sizeof(int); 2530 2538 FNTSIZE(new_data) = size; 2531 - REFCOUNT(new_data) = 0; /* usage counter */ 2539 + REFCOUNT(new_data) = 1; /* usage counter */ 2532 2540 for (i=0; i< charcount; i++) { 2533 2541 memcpy((u8 *)new_data + i * h * pitch, data + i * vpitch * pitch, h * pitch); 2534 2542 } ··· 2542 2550 for (i = first_fb_vc; i <= last_fb_vc; i++) { 2543 2551 struct vc_data *tmp = vc_cons[i].d; 2544 2552 2545 - if (fb_display[i].userfont && 2546 - fb_display[i].fontdata && 2553 + if (fb_display[i].fontdata && 2547 2554 FNTSUM(fb_display[i].fontdata) == csum && 2548 2555 font_data_size(fb_display[i].fontdata) == size && 2549 2556 tmp->vc_font.width == w && 2550 2557 !memcmp(fb_display[i].fontdata, new_data, size)) { 2551 - kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); 2552 - new_data = (u8 *)fb_display[i].fontdata; 2558 + font_data_get(fb_display[i].fontdata); 2559 + font_data_put(new_data); 2560 + new_data = fb_display[i].fontdata; 2553 2561 break; 2554 2562 } 2555 2563 } 2556 - return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1); 2564 + ret = fbcon_do_set_font(vc, font->width, font->height, charcount, new_data); 2565 + font_data_put(new_data); 2566 + 2567 + return ret; 2557 2568 } 2558 2569 2559 2570 static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, ··· 2573 2578 2574 2579 font->width = f->width; 2575 2580 font->height = f->height; 2576 - return fbcon_do_set_font(vc, f->width, f->height, f->charcount, f->data, 0); 2581 + return fbcon_do_set_font(vc, f->width, f->height, f->charcount, f->data); 2577 2582 } 2578 2583 2579 2584 static u16 palette_red[16];
-1
drivers/video/fbdev/core/fbcon.h
··· 27 27 struct fbcon_display { 28 28 /* Filled in by the low-level console driver */ 29 29 font_data_t *fontdata; 30 - int userfont; /* != 0 if fontdata kmalloc()ed */ 31 30 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION 32 31 u_short scrollmode; /* Scroll Method, use fb_scrollmode() */ 33 32 #endif
+2
include/linux/font.h
··· 54 54 return (const unsigned char *)fd; 55 55 } 56 56 57 + void font_data_get(font_data_t *fd); 58 + bool font_data_put(font_data_t *fd); 57 59 unsigned int font_data_size(font_data_t *fd); 58 60 59 61 /*
+75 -2
lib/fonts/fonts.c
··· 12 12 * for more details. 13 13 */ 14 14 15 + #include <linux/container_of.h> 16 + #include <linux/font.h> 15 17 #include <linux/module.h> 16 - #include <linux/types.h> 18 + #include <linux/slab.h> 17 19 #include <linux/string.h> 20 + #include <linux/types.h> 21 + 18 22 #if defined(__mc68000__) 19 23 #include <asm/setup.h> 20 24 #endif 21 - #include <linux/font.h> 22 25 23 26 /* 24 27 * Helpers for font_data_t 25 28 */ 29 + 30 + static struct font_data *to_font_data_struct(font_data_t *fd) 31 + { 32 + return container_of(fd, struct font_data, data[0]); 33 + } 34 + 35 + static bool font_data_is_internal(font_data_t *fd) 36 + { 37 + return !REFCOUNT(fd); /* internal fonts have no reference counting */ 38 + } 39 + 40 + static void font_data_free(font_data_t *fd) 41 + { 42 + kfree(to_font_data_struct(fd)); 43 + } 44 + 45 + /** 46 + * font_data_get - Acquires a reference on font data 47 + * @fd: Font data 48 + * 49 + * Font data from user space is reference counted. The helper 50 + * font_data_get() increases the reference counter by one. Invoke 51 + * font_data_put() to release the reference. 52 + * 53 + * Internal font data is located in read-only memory. In this case 54 + * the helper returns success without modifying the counter field. 55 + * It is still required to call font_data_put() on internal font data. 56 + */ 57 + void font_data_get(font_data_t *fd) 58 + { 59 + if (font_data_is_internal(fd)) 60 + return; /* never ref static data */ 61 + 62 + if (WARN_ON(!REFCOUNT(fd))) 63 + return; /* should never be 0 */ 64 + ++REFCOUNT(fd); 65 + } 66 + EXPORT_SYMBOL_GPL(font_data_get); 67 + 68 + /** 69 + * font_data_put - Release a reference on font data 70 + * @fd: Font data 71 + * 72 + * Font data from user space is reference counted. The helper 73 + * font_data_put() decreases the reference counter by one. If this was 74 + * the final reference, it frees the allocated memory. 75 + * 76 + * Internal font data is located in read-only memory. In this case 77 + * the helper returns success without modifying the counter field. 78 + * 79 + * Returns: 80 + * True if the font data's memory buffer has been freed, false otherwise. 81 + */ 82 + bool font_data_put(font_data_t *fd) 83 + { 84 + unsigned int count; 85 + 86 + if (font_data_is_internal(fd)) 87 + return false; /* never unref static data */ 88 + 89 + if (WARN_ON(!REFCOUNT(fd))) 90 + return false; /* should never be 0 */ 91 + 92 + count = --REFCOUNT(fd); 93 + if (!count) 94 + font_data_free(fd); 95 + 96 + return !count; 97 + } 98 + EXPORT_SYMBOL_GPL(font_data_put); 26 99 27 100 /** 28 101 * font_data_size - Return size of the font data in bytes