Return rotated font data as font_data_t instead of unsigned char*.
Release the data with font_data_put() in fbcon.

It is still possible to use preallocated font buffers for the rotated
font data. The font data tracks the buffer size and reference count to
do so; font_data_rotate() invokes __font_data_alloc() to allocate a
new font-data buffer is necessary.

Returning rotated font data as font_data_t further allows for using
regular font-data helpers on it. Fbcon now manages buffer life time
with the font data's reference counting. Removes the plain kfree().

Signed-off-by: Thomas Zimmermann <[email protected]>
---
 drivers/video/fbdev/core/fbcon.c        |  3 ++-
 drivers/video/fbdev/core/fbcon.h        |  3 +--
 drivers/video/fbdev/core/fbcon_rotate.c | 19 ++++++++-------
 include/linux/font.h                    |  5 ++--
 lib/fonts/font_rotate.c                 | 32 ++++++++++---------------
 5 files changed, 28 insertions(+), 34 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index d97d94bb8e99..9a88a47fc84c 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -770,7 +770,8 @@ static void fbcon_release(struct fb_info *info)
                kfree(par->cursor_data);
                kfree(par->cursor_src);
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
-               kfree(par->rotated.buf);
+               if (par->rotated.buf)
+                       font_data_put(par->rotated.buf);
 #endif
                kfree(info->fbcon_par);
                info->fbcon_par = NULL;
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index ab78dad15925..8b662226004c 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -90,8 +90,7 @@ struct fbcon_par {
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
        struct {
                font_data_t *fontdata;  /* source font */
-               unsigned char *buf;     /* rotated glyphs */
-               size_t bufsize;
+               font_data_t *buf;       /* rotated font */
                int buf_rotate;         /* rotation of buf */
        } rotated;
 #endif
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c 
b/drivers/video/fbdev/core/fbcon_rotate.c
index 6cdbc96eeca6..b7c48e7c4a6e 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -18,7 +18,7 @@
 int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 {
        struct fbcon_par *par = info->fbcon_par;
-       unsigned char *buf;
+       font_data_t *buf;
        int ret;
 
        if (par->p->fontdata == par->rotated.fontdata && par->rotate == 
par->rotated.buf_rotate)
@@ -32,21 +32,22 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data 
*vc)
 
        buf = font_data_rotate(par->rotated.fontdata, vc->vc_font.width,
                               vc->vc_font.height, vc->vc_font.charcount,
-                              par->rotated.buf_rotate, par->rotated.buf,
-                              &par->rotated.bufsize);
+                              par->rotated.buf_rotate, par->rotated.buf);
        if (IS_ERR(buf)) {
                ret = PTR_ERR(buf);
-               goto err_kfree;
+               goto err_font_data_put;
        }
 
+       if (par->rotated.buf)
+               font_data_put(par->rotated.buf);
        par->rotated.buf = buf;
 
        return 0;
 
-err_kfree:
-       kfree(par->rotated.buf);
-       par->rotated.buf = NULL; /* clear here to avoid output */
-       par->rotated.bufsize = 0;
-
+err_font_data_put:
+       if (par->rotated.buf) {
+               font_data_put(par->rotated.buf);
+               par->rotated.buf = NULL; /* clear here to avoid output */
+       }
        return ret;
 }
diff --git a/include/linux/font.h b/include/linux/font.h
index be1a26ff8ae9..2d7e2ca3db0f 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -120,9 +120,8 @@ void font_glyph_rotate_180(const unsigned char *glyph, 
unsigned int width, unsig
                           unsigned char *out);
 void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, 
unsigned int height,
                           unsigned char *out);
-unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned 
int height,
-                               unsigned int charcount, unsigned int steps,
-                               unsigned char *buf, size_t *bufsize);
+font_data_t *font_data_rotate(font_data_t *fd, unsigned int width, unsigned 
int height,
+                             unsigned int charcount, unsigned int steps, 
font_data_t *buf);
 
 /*
  * Font description
diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c
index 275406008823..ea54bd618ffb 100644
--- a/lib/fonts/font_rotate.c
+++ b/lib/fonts/font_rotate.c
@@ -181,8 +181,7 @@ EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
  * @height: The number of scanlines in the glyph
  * @charcount: The number of glyphs in the font
  * @steps: Number of rotation steps of 90°
- * @buf: Preallocated output buffer; can be NULL
- * @bufsize: The size of @buf in bytes; can be NULL
+ * @buf: Preallocated font data; can be NULL
  *
  * The parameters @width and @height refer to the visible number of pixels
  * and scanlines in a single glyph. The number of glyphs is given in 
@charcount.
@@ -194,16 +193,14 @@ EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
  * as returned by font_data_buf(). Callers are responsible to free the returned
  * buffer with kfree(). Font rotation typically happens when displays get
  * re-oriented. To avoid unnecessary re-allocation of the memory buffer, the
- * caller can pass in an earlier result buffer in @buf for reuse. The old and
- * new buffer sizes are given and retrieved by the caller in @bufsize. The
- * allocation semantics are compatible with krealloc().
+ * caller can pass in an earlier result in @buf for reuse. The returned font
+ * data should be released with font_data_put().
  *
  * Returns:
- * A buffer with rotated glyphs on success, or an error pointer otherwise
+ * Font data with rotated glyphs on success, or an error pointer otherwise
  */
-unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned 
int height,
-                               unsigned int charcount, unsigned int steps,
-                               unsigned char *buf, size_t *bufsize)
+font_data_t *font_data_rotate(font_data_t *fd, unsigned int width, unsigned 
int height,
+                             unsigned int charcount, unsigned int steps, 
font_data_t *buf)
 {
        const unsigned char *src = font_data_buf(fd);
        unsigned int s_cellsize = font_glyph_size(width, height);
@@ -227,19 +224,16 @@ unsigned char *font_data_rotate(font_data_t *fd, unsigned 
int width, unsigned in
        if (check_mul_overflow(charcount, d_cellsize, &size))
                return ERR_PTR(-EINVAL);
 
-       if (!buf || !bufsize || size > *bufsize) {
-               dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL);
-               if (!dst)
-                       return ERR_PTR(-ENOMEM);
-
-               kfree(buf);
-               buf = dst;
-               if (bufsize)
-                       *bufsize = size;
+       if (!buf || size > font_data_size(buf)) {
+               buf = __font_data_alloc(size, GFP_KERNEL);
+               if (IS_ERR(buf))
+                       return buf;
        } else {
-               dst = buf;
+               font_data_get(buf);
        }
 
+       dst = __font_data_wrbuf(buf);
+
        switch (steps) {
        case 0:
                memcpy(dst, src, size);
-- 
2.56.0

Reply via email to